Escrito por Christian Tutivén Gálvez en Planeta Chatbot.

El pasado mes de octubre recibí un correo electrónico de Udacity indicándome que estaba aprobado como uno de los concursantes para el “Desafio de Becas de PyTorch de Facebook”. Feliz de saber que algunos amigos de nuestra comunidad AI Saturdays (una organización sin fines de lucro con el objetivo de capacitar a diversos individuos para que aprendan Inteligencia Artificial de forma colaborativa y basada en proyectos, más allá del camino de la educación convencional) también estaban concursando, nos pusimos manos a la obra con el proyecto final!!

[cta]

Desafio de Becas de PyTorch de Facebbok

Tabla de contenidos

Objetivos del proyecto final

En este proyecto, entrenaremos un clasificador de imágenes para identificar 102 tipos distintos de flores. Puedes imaginarte usar algo como esto en una aplicación de teléfono que te diga el nombre de la flor que está mirando tu cámara. En la práctica, entrenaría a este clasificador y luego lo exportaría para usarlo en su aplicación. En este artículo les mostraré como utilicé PyTorch para completar el proyecto. A continuación puedes ver algunos ejemplos de las imágenes a clasificar.

Espero que este articulo pueda ayudarte a introducirte en el mundo de la Inteligencia Artificial usando PyTorch.

Qué es PyTorch?

Es un paquete basado en Python que sirve como reemplazo de Numpy para usar el poder de las GPUs y proporciona flexibilidad y velocidad como plataforma de desarrollo de aprendizaje profundo. Si estas interesado en aprender más de PyTorch, visita el siguiente link.

Qué es Google Colab?

Esta herramienta de Google ofrece el uso de un portátil tipo jupyter. El portátil tiene la misma extensión (.ipynb) y funciona de la misma manera que en Jupyter. Se puede usar como un cuaderno de jupyter un entorno local instalado en la máquina personal de uno (esto no se tratará en este artículo), no obstante, para poder aprovechar toda su potencia, se podría utilizar mejor una GPU disponible (en Google Colab) e instalar los paquetes necesarios (es muy fácil, no te asustes).

Para los que se mueren de hambre por más detalles, Google tiene un cuaderno “Te damos la bienvenida a Colaboratory” que tiene como objetivo dar una introducción detallada a la herramienta.

https://colab.research.google.com/notebooks/welcome.ipynb

Google Colaboratory

Desarrollando una aplicación de Inteligencia Artificial (IA)

En el futuro, los algoritmos de IA se incorporarán a las aplicaciones más y más cotidianas. Por ejemplo, es posible que desees incluir un clasificador de imágenes en una aplicación de teléfono inteligente. Para hacer esto, usaría un modelo de aprendizaje profundo entrenado en cientos de miles de imágenes como parte de la arquitectura general de la aplicación. Una gran parte del desarrollo de software en el futuro será usar este tipo de modelos como partes comunes de las aplicaciones.

El Proyecto

El proyecto se divide en varios pasos:

* Cargar y preprocesar el conjunto de datos de la imagen.
* Entrena el clasificador de imágenes en tu conjunto de datos.
* Usa el clasificador entrenado para predecir el contenido de la imagen.

Esta guía te ayudara a desarrollar cada paso y como implementarlo en Python usando el entorno de Google Colab.

Empezando con Google Colab

Google Colab ofrece una GPU Tesla K80. Se puede seguir trabajando con la instancia de GPU continuamente hasta 12 horas! Una vez que hayan consumido las 12 horas, simplemente cierre el cuaderno y vuelva a abrirlo. Ahora, ¡A trabajar!

Para configurar Google Colab con PyTorch puedes leer mi articulo en este link.

Data set

Como estamos usando Google Colab debes descargarte el data set de las imágenes de las flores que entrega Udacity (estas imagenes estarán instaladas por 12 horas).

Para esto debes ingresar el siguiente código.

!wget https://s3.amazonaws.com/content.udacity-data.com/courses/nd188/flower_data.zip

Si no han pasado las 12 horas y en caso de que deseas reiniciar el cuaderno de Colab, ya no debes volver a ejecutar el código anterior.

El archivo descargado esta en formato zip, por lo que, para descomprimirlo debes hacerlo con el siguiente código, donde indicas cual es el archivo que deseas descomprimir y donde lo deseas descomprimir.

from zipfile import ZipFile  with ZipFile('flower_data.zip', 'r') as zf:   zf.extractall('flower_data/')

Al revisar el dataset, encontré que solo tiene una capeta de entrenamiento y otra de validación pero buscando y buscando encontré un enlace donde puedes descargarte el set de testeo. Para descargarte este set ingresa

!wget -O flower_data_orginal_test.zip "https://www.dropbox.com/s/da6ye9genbsdzbq/flower_data_original_test.zip?dl=1"

Igual que antes, viene comprimido así que debes descomprimirlo.

from zipfile import ZipFile  with ZipFile('flower_data_orginal_test.zip', 'r') as zf:   zf.extractall('flower_data/flower_data/test')

Udacity te entrega un enlace al repositorio donde están los archivos del challenge. Para clonarlos, ingresa el siguiente código.

!git clone https://github.com/udacity/pytorch_challenge.git

Importar librerías

Lo primero es importar los paquetes que necesitarás. Es una buena práctica mantener todas las importaciones al principio de su código. Cuando trabajes en este cuaderno y descubras que necesitas importar un paquete, asegúrate de agregar la importación al principio de tu cuaderno.

# Imports here  import torch  import torch.nn as nn  import torch.optim as optim  from torch.optim import lr_scheduler  import numpy as np  import time  import os  import argparse  from torchvision import datasets, models, transforms, utils  from torch.autograd import Variable  import torch.nn.functional as F  import copy  from PIL import Image  import matplotlib.pyplot as plt  import json  from collections import OrderedDict

Cargar los datos

Aquí usarás torchvision para cargar los datos (documentación). Para la capacitación, querrás aplicar transformaciones, como la escala aleatoria, el recorte y el volteado. Esto ayudará a que la red se generalice conduciendo a un mejor rendimiento. Si utilizas una red pre-entrenada, también deberás asegurarte de que los datos de entrada se redimensionen a 224×224 píxeles como lo requieren las redes.

El conjunto de validación se utiliza para medir el rendimiento del modelo en datos que aún no se han visto. Para esto, no se desea ninguna transformación de escala o rotación, pero deberás cambiar el tamaño y luego recortar las imágenes al tamaño adecuado.

Las redes pre-entrenadas disponibles de torchvision fueron entrenadas en el conjunto de datos de ImageNet donde cada canal de color se normalizó por separado. Para ambos conjuntos, deberás normalizar los medios y las desviaciones estándar de las imágenes a lo que la red espera. Para las medias, es [0.485, 0.456, 0.406] y para las desviaciones estándar [0.229, 0.224, 0.225], calculadas a partir de las imágenes de ImageNet. Estos valores cambiarán cada canal de color para que se centre en 0 y oscile entre -1 y 1.

A continuación, es útil configurar las transformaciones de datos. Esencialmente, las transformaciones de datos en PyTorch nos permiten entrenar en muchas variaciones de las imágenes originales que se recortan de diferentes maneras o se rotan de diferentes maneras.

# TODO: Define your transforms for the training and validation sets  data_transforms = {   'train': transforms.Compose([   transforms.RandomRotation(45),   transforms.RandomResizedCrop(224),   transforms.RandomHorizontalFlip(),   transforms.ToTensor(),   transforms.Normalize([0.485, 0.456, 0.406],    [0.229, 0.224, 0.225])   ]),   'valid': transforms.Compose([   transforms.Resize(256),   transforms.CenterCrop(224),   transforms.ToTensor(),   transforms.Normalize([0.485, 0.456, 0.406],    [0.229, 0.224, 0.225])   ]),   'test': transforms.Compose([   transforms.Resize(256),   transforms.CenterCrop(224),   transforms.ToTensor(),   transforms.Normalize([0.485, 0.456, 0.406],    [0.229, 0.224, 0.225])   ]),  }# TODO: Load the datasets with ImageFolder  # TODO: Using the image datasets and the trainforms, define the dataloaders  train_dir = 'flower_data/flower_data/train'  valid_dir = 'flower_data/flower_data/valid'  test_dir = 'flower_data/flower_data/test'  dirs = {'train': train_dir,    'valid': valid_dir,    'test' : test_dir}  image_datasets = {x: datasets.ImageFolder(dirs[x], transform=data_transforms[x]) for x in ['train', 'valid', 'test']}  dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=32, shuffle=True) for x in ['train', 'valid', 'test']}  dataset_sizes = {x: len(image_datasets[x])    for x in ['train', 'valid', 'test']}  class_names = image_datasets['train'].classes  class_to_idx = image_datasets['train'].class_to_idx

Ahora podemos mostrar el tamaño de cada uno de los data sets, el número de clases , las clases que tenemos y cuantos data sets existen.

print ("Dasaset Size: "+ str(dataset_sizes) + "\n")  n_class = len(class_names)  print ("Number of classes: "+ str(n_class) + "\n")  print ("Classes: "+ str(class_names) + "\n")print (len(dataloaders))

La salida será así:

Dasaset Size: {‘train’: 6552, ‘valid’: 818, ‘test’: 819}

Number of classes: 102

Classes: [‘1’, ‘10’, ‘100’, ‘101’, ‘102’, ‘11’, ‘12’, ‘13’, ‘14’, ‘15’, ‘16’, ‘17’, ‘18’, ‘19’, ‘2’, ‘20’, ‘21’, ‘22’, ‘23’, ‘24’, ‘25’, ‘26’, ‘27’, ‘28’, ‘29’, ‘3’, ‘30’, ‘31’, ‘32’, ‘33’, ‘34’, ‘35’, ‘36’, ‘37’, ‘38’, ‘39’, ‘4’, ‘40’, ‘41’, ‘42’, ‘43’, ‘44’, ‘45’, ‘46’, ‘47’, ‘48’, ‘49’, ‘5’, ‘50’, ‘51’, ‘52’, ‘53’, ‘54’, ‘55’, ‘56’, ‘57’, ‘58’, ‘59’, ‘6’, ‘60’, ‘61’, ‘62’, ‘63’, ‘64’, ‘65’, ‘66’, ‘67’, ‘68’, ‘69’, ‘7’, ‘70’, ‘71’, ‘72’, ‘73’, ‘74’, ‘75’, ‘76’, ‘77’, ‘78’, ‘79’, ‘8’, ‘80’, ‘81’, ‘82’, ‘83’, ‘84’, ‘85’, ‘86’, ‘87’, ‘88’, ‘89’, ‘9’, ‘90’, ‘91’, ‘92’, ‘93’, ‘94’, ‘95’, ‘96’, ‘97’, ‘98’, ‘99’]

3

Además podemos mostrar un ejemplo de una de las imágenes

images, labels = next(iter(dataloaders["train"]))  print(len(images[0,2]))  plt.imshow(images[0,0])

Mapeo de etiquetas

También deberás cargar una asignación de etiqueta de categoría a nombre de categoría. Puedes encontrar esto en el archivo cat_to_name.json dentro de la carpeta pytorch_challenge. Es un objeto JSON que se puede leer con el módulo json. Esto te dará un diccionario que asigna las categorías codificadas con enteros a los nombres reales de las flores.

with open('pytorch_challenge/cat_to_name.json', 'r') as f:   cat_to_name = json.load(f)

Construyendo y entrenando el clasificador

Ahora que los datos están listos, es hora de construir y entrenar al clasificador. Como de costumbre, se debe usar uno de los modelos pre-entrenados de torchvision.models para obtener las características de la imagen.

En los últimos años, se han creado varios modelos para reutilizarlos en problemas de visión de computadora. El uso de estos modelos pre-entrenados se conoce como aprendizaje por transferencia. PyTorch hace que sea fácil cargar modelos pre-entrenados y construir sobre ellos, que es lo que haremos en este proyecto.

Algunos de los modelos pre-entrenados más populares incluyen VGGNet, DenseNet, ResNet y AlexNet, todos los cuales son modelos pre-entrenados del Challenge de ImageNet. Estos modelos pre-entrenados permiten que otros obtengan rápidamente resultados de vanguardia en visión por computadora sin necesidad de grandes cantidades de poder de cómputo, tiempo y paciencia para encontrar la técnica de entrenamiento adecuada para optimizar los pesos.

Decidí usar la arquitectura DenseNet121, que podemos obtener de la biblioteca torchvision. Sin embargo, otros modelos podrían haberse utilizado fácilmente con una configuración muy similar.

model = models.densenet121(pretrained=True)

Puedes ver la arquitectura del modelo ejecutano la siguiente celda:

print(model)

Si te desplazas por la arquitectura del modelo, notará que tiene varias capas convolucionales. A continuación puedes ver la capa fina de la red.

(classifier): Linear(in_features=1024, out_features=1000) )

Hay dos partes del clasificador que deben ser consistentes

  1. El número de entidades de entrada con un valor de 1024 también debe ser el mismo que nuestro primer nivel de entrada.
  2. El número de características de salida, que actualmente es de 1000 características, debe ser igual al número de clases que tenemos en nuestro conjunto de datos. En nuestro caso, vamos a querer predecir las 102 clases de flores.

Luego, para garantizar que no actualizaremos los pesos del modelo pre-entrenado se define “param.requires_grad= False”. Además se define una nueva estructura de las capas finales del modelo re-definiendo el “classifier” previamente mostrado y para esto se usa un diccionario ordenado.

# TODO: Build and train your network  def build_model(hidden_layers, class_to_idx):   model = models.densenet121(pretrained=True)   for param in model.parameters():   param.requires_grad = False

classifier_input_size = model.classifier.in_features
print(«Input size: «, classifier_input_size)
output_size = 102 from collections import OrderedDict
classifier = nn.Sequential(OrderedDict([
(‘fc1’, nn.Linear(classifier_input_size, hidden_layers)),
(‘relu’, nn.ReLU()),
(‘drpot’, nn.Dropout(p=0.2)),
(‘fc2’, nn.Linear(hidden_layers, output_size)),
(‘output’, nn.LogSoftmax(dim=1))
]))

model.classifier = classifier
model.class_to_idx = class_to_idx
return model# TODO: Build and train your network

Se puede observar que esta función define nuestro nuevo classifier con dos fully connected layers, una función ReLu luego de la primera fully connected layer, un Dropout (0.20) y una salida de 102 características.

Se crea el nuevo modelo de la red donde se define que el hidden_layers tendrá 512 neuronas

hidden_layers = 512  model = build_model(hidden_layers, class_to_idx)

Y para ver la nueva arquitectura del modelo

print(model)

Se puede observar que el classifier cambio a:

(classifier): Sequential(

(fc1): Linear(in_features=1024, out_features=512)

(relu): ReLU()

(drpot): Dropout(p=0.2)

(fc2): Linear(in_features=512, out_features=102)

(output): LogSoftmax() ) )

Se definen las funciones de entrenamiento

def train(model, epochs, learning_rate, criterion, optimizer, training_loader, validation_loader):

model.train()
print_every = 40
steps = 0
use_gpu = False

if torch.cuda.is_available():
use_gpu = True
model.cuda()
else:
model.cpu() for epoch in range(epochs):
running_loss = 0
for inputs, labels in iter(training_loader):
steps += 1 if use_gpu:
inputs = Variable(inputs.float().cuda())
labels = Variable(labels.long().cuda())
else:
inputs = Variable(inputs)
labels = Variable(labels) optimizer.zero_grad()
output = model.forward(inputs)
loss = criterion(output, labels)
loss.backward()
optimizer.step()
running_loss += loss.data[0] if steps % print_every == 0:
validation_loss, accuracy = validate(model,
criterion, validation_loader) print(«Epoch: {}/{} «.format(epoch+1, epochs),
«Training Loss: {:.3f}
«.format(running_loss/print_every),
«Validation Loss: {:.3f}
«.format(validation_loss),
«Validation Accuracy:
{:.3f}».format(accuracy))def validate(model, criterion, data_loader):
model.eval()
accuracy = 0
test_loss = 0

for inputs, labels in iter(data_loader):
if torch.cuda.is_available():
inputs = Variable(inputs.float().cuda(), volatile=True)
labels = Variable(labels.long().cuda(), volatile=True)
else:
inputs = Variable(inputs, volatile=True)
labels = Variable(labels, volatile=True) output = model.forward(inputs)
test_loss += criterion(output, labels).data[0]
ps = torch.exp(output).data
equality = (labels.data == ps.max(1)[1])
accuracy += equality.type_as(torch.FloatTensor()).mean() return test_loss/len(data_loader), accuracy/len(data_loader)

Vamos a configurar las entradas necesarias para esta función. Hay seis entradas al modelo:

  1. El argumento “model” es el modelo, que es solo el modelo que creamos en la parte anterior.
  2. El argumento “criterion” es el método utilizado para evaluar el ajuste del modelo.
  3. El optimizador “optimizer” es la técnica de optimización utilizada para actualizar los pesos.
  4. Las épocas “epoch”, es una ejecución completa de feedforward y backpropagation a través de la red. Si deseas reducir el tiempo de entrenamiento puedes reducir los epoch.
  5. El learning_rate o tasa de aprendizaje, es un hiper-parámetro que controla cuánto estamos ajustando los pesos de nuestra red con respecto al gradiente de pérdida. Si la tasa de aprendizaje es baja, entonces la capacitación es más confiable (para no perder ningún mínimo local), pero la optimización tomará mucho tiempo porque los pasos hacia el mínimo de la función de pérdida son muy pequeños. Si la tasa de aprendizaje es alta, entonces el entrenamiento puede no converger o incluso divergir. Los cambios de peso pueden ser tan grandes que el optimizador sobrepasa el mínimo y empeora la pérdida.
Gradient descent with small (top) and large (bottom) learning rates. Source: Andrew Ng’s Machine Learning course on Coursera

Para entrenar mi modelo, establezco lo anterior a los siguientes valores:

epochs = 20  learning_rate = 0.001  criterion = nn.NLLLoss()  optimizer = optim.Adam(model.classifier.parameters(), lr=learning_rate)

Se entrena el modelo ejecutando la siguiente celda

train(model, epochs, learning_rate, criterion, optimizer, dataloaders['train'], dataloaders['valid'])

Si todo está configurado correctamente, debería ver algo como lo siguiente:

http://www.aprendemachinelearning.com/que-es-overfitting-y-underfitting-y-como-solucionarlo/

En la imagen puedes ver que tenemos un “training loss” y un “validation loss”, que nos permitirán ver si nuestro modelo esta “overfitting” es decir sobre-entrenado o tiene sobreajuste (el modelo no es esta generalizando porque el modelo tiene exactamente los mismos valores de las muestras de entrenamiento), si esta “underfitting” es decir tiene subajuste (tiene falta de entrenamiento) o nos dirá si esta correctamente entrenado.

Test de tu modelo

Es una buena práctica probar tu modelo capacitado en datos de prueba, imágenes que la red nunca ha visto, ya sea en entrenamiento o validación. Esto le dará una buena estimación del rendimiento del modelo en imágenes completamente nuevas. Debería poder alcanzar aproximadamente el 70% de precisión en el conjunto de pruebas si el modelo ha sido bien entrenado.

# TODO: Do validation on the test set  test_loss, accuracy = validate(model, criterion, dataloaders['testing'])  print("Val. Accuracy: {:.3f}".format(accuracy))  print("Val. Loss: {:.3f}".format(test_loss))

Guardar el punto de control

Ahora que tu modelo está entrenado, es hora de guardarlo para poder cargarlo más tarde y hacer predicciones. Probablemente desees guardar otras cosas, como la asignación de clases a los índices que obtiene de uno de los conjuntos de datos de imagen: image_datasets [‘train’]. class_to_idx. Puede adjuntar esto al modelo como un atributo que facilita la inferencia más adelante.

model.class_to_idx = image_datasets [‘train’]. class_to_idx

Recuerde que querrá reconstruir completamente el modelo más adelante para poder usarlo como inferencia. Asegúrese de incluir cualquier información que necesite en el punto de control. Si desea cargar el modelo y seguir entrenando, querrá guardar el número de épocas y el estado del optimizador, optimizer.state_dict. Es probable que desee utilizar este modelo capacitado en la siguiente parte del proyecto, por lo que es mejor guardarlo ahora.

# TODO: Save the checkpoint   model.class_to_idx = image_datasets['train'].class_to_idx  model.cpu()  torch.save({'arch': 'densenet121',   'state_dict': model.state_dict(),    'class_to_idx': model.class_to_idx},    'densenet121.pth')

Cargando el modelo

En este punto, es bueno escribir una función que pueda cargar un punto de control y reconstruir el modelo. De esa manera, puedes volver a este proyecto y seguir trabajando en él sin tener que volver a entrenar la red.

# TODO: Write a function that loads a checkpoint and rebuilds the model  def load_checkpoint(filepath):   checkpoint = torch.load(filepath)   model = models.densenet121()

classifier = nn.Sequential(OrderedDict([
(‘fc1’, nn.Linear(1024, hidden_layers)),
(‘relu’, nn.ReLU()),
(‘drpot’, nn.Dropout(p=0.2)),
(‘fc2’, nn.Linear(hidden_layers, 102)),
(‘output’, nn.LogSoftmax(dim=1))
]))

model.classifier = classifier
model.load_state_dict(checkpoint[‘state_dict’])

return model, checkpoint[‘class_to_idx’]# get index to class mapping
loaded_model, class_to_idx = load_checkpoint(‘densenet121.pth’)
idx_to_class = { v : k for k,v in class_to_idx.items()}

Inferencia para clasificación

Ahora hay que escribir una función para usar un modelo entrenado para la inferencia. Es decir, pasar una imagen al modelo y predecir la clase de la flor en la imagen.

Preprocesamiento de imágenes

Hay que escribir una función que preprocese la imagen para que pueda usarse como entrada para el modelo. Esta función debe procesar las imágenes de la misma manera utilizada para el entrenamiento. Primero, se cambia el tamaño de las imágenes donde el lado más corto es de 256 píxeles, manteniendo la relación de aspecto. Esto se puede hacer con los métodos de miniatura o cambio de tamaño. Luego deberá recortar la parte central de 224×224 de la imagen.

def process_image(image):   ''' Scales, crops, and normalizes a PIL image for a PyTorch    model, returns an Numpy array '''

# TODO: Process a PIL image for use in a PyTorch model size = 256, 256
image.thumbnail(size, Image.ANTIALIAS)
image = image.crop((128 – 112, 128 – 112, 128 + 112, 128 + 112))
npImage = np.array(image)
npImage = npImage/255.

imgA = npImage[:,:,0]
imgB = npImage[:,:,1]
imgC = npImage[:,:,2]

imgA = (imgA – 0.485)/(0.229)
imgB = (imgB – 0.456)/(0.224)
imgC = (imgC – 0.406)/(0.225)

npImage[:,:,0] = imgA
npImage[:,:,1] = imgB
npImage[:,:,2] = imgC

npImage = np.transpose(npImage, (2,0,1))

return npImag

Para verificar el trabajo, la siguiente función convierte un tensor de PyTorch y lo muestra en el cuaderno. Si tu función process_image funciona, al ejecutar la salida a través de esta función debería devolver la imagen original (excepto las partes recortadas).

def imshow(image, ax=None, title=None):   """Imshow for Tensor."""   if ax is None:   fig, ax = plt.subplots()

# PyTorch tensors assume the color channel is the first
dimension
# but matplotlib assumes is the third dimension
image = image.numpy().transpose((1, 2, 0))

# Undo preprocessing
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean

# Image needs to be clipped between 0 and 1 or it looks like
noise when displayed
image = np.clip(image, 0, 1)

ax.imshow(image)

return ax

Predicción de clase

Una vez que puede obtener imágenes en el formato correcto, es el momento de escribir una función para hacer predicciones con el modelo. Una práctica común es predecir la mayoría de las 5 clases más probables (generalmente llamadas top-K ).

Nuevamente, este método debe tomar una ruta hacia una imagen y un punto de control del modelo, luego devolver las probabilidades y las clases.

def predict(image_path, model, topk=5):   ''' Predict the class (or classes) of an image using a trained    deep learning model.'''

# TODO: Implement the code to predict the class from an image
file

image =
torch.FloatTensor([process_image(Image.open(image_path))])
model.eval()
output = model.forward(Variable(image))
pobabilities = torch.exp(output).data.numpy()[0] top_idx = np.argsort(pobabilities)[-topk:][::-1]
top_class = [idx_to_class[x] for x in top_idx]
top_probability = pobabilities[top_idx] return top_probability, top_classprint (predict(‘flower_data/flower_data/test/1/image_06743.jpg’, loaded_model))

Comprobación

Ahora que se puede usar el modelo entrenado para las predicciones, hay que verificar que tenga sentido. Incluso si la precisión de las pruebas es alta, siempre es bueno verificar que no haya errores obvios.

# TODO: Display an image along with the top 5 classes  def view_classify(img, probabilities, classes, mapper):   ''' Function for viewing an image and it's predicted classes.   '''   img_filename = img.split('/')[-2]   img = Image.open(img) fig, (ax1, ax2) = plt.subplots(figsize=(6,10), ncols=1, nrows=2)   flower_name = mapper[img_filename]

ax1.set_title(flower_name)
ax1.imshow(img)
ax1.axis(‘off’)

y_pos = np.arange(len(probabilities))
ax2.barh(y_pos, probabilities)
ax2.set_yticks(y_pos)
ax2.set_yticklabels([mapper[x] for x in classes])
ax2.invert_yaxis()img = ‘flower_data/flower_data/test/24/image_06815.jpg’
p, c = predict(img, loaded_model)
view_classify(img, p, c, cat_to_name)

Obteniendo como salida la siguiente comprobación:

Conclusiones

Como podemos ver, las redes pre-entrenadas son increíblemente beneficiosas, ya que nos permiten enfocarnos en los aspectos específicos de nuestro caso de uso, mientras reutilizamos genéricos conocidos para el preprocesamiento de imágenes en el ejemplo.

También hemos aprendido que el tamaño de la salida de nuestro clasificador debe ser el mismo que el número de tipos diferentes que queremos poder identificar.

Finalmente, hemos visto que la salida de las capas de entidades y la entrada de nuestro clasificador personalizado también deben coincidir en tamaño.

Espero que este artículo te ayude a entender de una manera fácil como usar PyTorch y Google Colab para mediante redes neuronales pre-entrenadas clasificar imágenes.

2 comentarios en «Deep Learning: cómo clasificar imágenes usando PyTorch y Google Colab»
  1. hola buenos dias muy interesante tu artículo yo estuve realizando algunas pruebas pero usando mobilenet con diversas opciones tensorflow y ml5 , recien estoy empezando con este tema estoy viendo como aumentar la cantidad de clasificación o modelos que me da mobilenet ya que quiero que me clasifique bacterias voy a ver si en Udacity existe alguna base de de ese tipo de datos vere tambien de usar tus ejemplos y ver que resultado me da desde ya gracias por compartir tu informacion

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *