En esta publicación, revisamos un ejemplo en pytorch que utiliza un modelo pre-entrenado para la clasificación de imágenes
reconocimiento de imagen con pytorch
idea
La idea es entrenar un modelo para reconocer a un perro en dos posiciones: sentado y parado; pero este mismo concepto puede escalarse a más categorías (más posiciones)
información para el entrenamiento
Para esto, he recabado algunas imágenes de mi perrita Renata <3, todas las imágenes cuentan con al misma resolución de 4032 x 3024 pixeles
La estructura que vamos a necesitar en nuestro directorio es:
images
test
dog_sitting
dog_standing
train
dog_sitting
dog_standing
Como puedes observar, dentro del directorio, tenemos dos categorías principales que corresponden a la información que vamos a utilizar para el entrenamiento (train) y validación (test) de nuestro modelo. Después, un nivel más adentro, contamos con carpetas que describen a la categoría a la cuál pertenecen las imágenes que contienen, esto es:
- dog_sitting - contiene imágenes de perros sentados
- dog_standing - contiene imágenes de perros parados
pytorch
Disclaimer: No soy un experto en pytorch, así que mucha información que veras en este post tendrán referencias externas a las publicaciones originales donde puedes seguir el pensamiento detrás de la selección de los componentes
modelo
Utilizaremos un modelo que se encuentra dentro de pytorch llamado resnet50, este modelo ya se encuentra pre-entrenado y será nuestra base para enseñarle a reconocer nuestras categorías (dog_sitting, dog_standing)
# si tienes un hardware con cuda cores,
# puedes cambiar este parametros por "cuda"
device = "cpu"
# cargar el modelo pre-entrenado
# y configurarlo para utilizar el hardware seleccionado previamente
model = models.resnet50(pretrained=True).to(device)
for param in model.parameters():
param.requires_grad = False
# capa personalizada para adaptarse a nuestro caso particular
model.fc = nn.Sequential(
nn.Linear(2048, 128),
nn.ReLU(inplace=True),
nn.Linear(128, 2)
).to(device)
carga de datos de entrenamiento
Para la carga de los datos de train y test, primero debemos definir un transformador, el cual nos ayudara a estandarizar el tamaño de las imágenes; y como paso adicional para el entrenamiento, las imágenes se giran de forma aleatoria para asegurarnos que el training no tenga un sesgo; por ejemplo, podríamos tener un sesgo por el ángulo de la cámara
normalizadores
normalizer = transforms.Normalize(
[0.5, 0.5, 0.5],
[0.5, 0.5, 0.5]
)
transformers = {
'train': transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalizer
]),
'test': transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
normalizer
])
}
Nota: los diccionarios que estaremos utilizando van a contar siempre con las fases train y test, ya que cada fase cuenta con un transformador distinto
data set
Ahora debemos indicar dónde se encuentran los directorios para cada fase y proveer el transformador que les corresponden
data_set = {
'train': datasets.ImageFolder('./images/train', transformers['train']),
'test': datasets.ImageFolder('./images/test', transformers['test'])
}
También, hay que configurar los componentes que realizarán la lectura de los datos
data_loaders = {
'train': torch.utils.data.DataLoader(
data_set['train'],
batch_size=32,
shuffle=True,
num_workers=2
),
'test': torch.utils.data.DataLoader(
data_set['test'],
batch_size=32,
shuffle=False,
num_workers=2
)
}
recapitulando
Hasta ahora hemos realizado lo siguiente:
- cargar y ajustar el modelo que vamos a utilizar para el entrenamiento
- configurar cómo se tratará a la información
- indicar donde se encuentran nuestros datos
- configurar los componentes de lectura
entrenamiento
El entrenamiento será definido de la siguiente manera:
- definir un criterio para el cálculo del error (loss) y optimización para el aprendizaje
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.fc.parameters())
- ejecutar las fases de train y test distintas veces
epochs = 10
for epoch in range(epochs):
for phase in ['train', 'test']:
model_train(phase)
- Tratar de reducir el error y aumentar el puntaje acertado de nuestro modelo
def model_train(phase):
running_loss = 0.0
running_corrects = 0.0
for x, y in data_loaders[phase]:
# ingresar X y Y en el hardware
inputs = x.to(device)
labels = y.to(device)
# realizar la prediccion
outputs = model(inputs)
# medir el error
loss = criterion(outputs, labels)
# para fase de train, es necesario
# efectuar la parte de aprendizaje
if phase == 'train':
optimizer.zero_grad()
loss.backward()
optimizer.step()
_, prediction = torch.max(outputs, 1)
# medir como va mejorando/empeorando el modelo en esta fase
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(prediction == labels.data)
# medir como va mejorando/empeorando el model en la iteracion (epoch)
epoch_loss = running_loss / len(data_set[phase])
eopch_corrects = running_corrects.double() / len(data_set[phase])
- guardar el modelo
torch.save(trained_model.state_dict(), './models/dog-trainer.h5')
probando el modelo
Ya que contamos con nuestro modelo entrenado, haremos una prueba con un par de fotos que no se encuentra en el conjunto de datos iniciales:


Resultado:

Definitivamente podemos mejorar las predicciones para el caso del perro parado (standing), pero es algo que podría arreglarse fácilmente agregando más datos de prueba. Por ahora, para este proyecto personal, es suficiente
conclusiones
Pytorch es una librería que nos ayuda a realizar un entrenamiento de modelos de manera simple y rápida; ésta también provee un catálogo de modelos pre-entrenados que pueden ser adaptados a nuevos casos de uso, quitando así, la necesidad de obtener una cantidad enorme de datos para tener una precisión adecuada, y por ende, se reduce el costo de cómputo necesario para el entrenamiento
Es agradable ver lo mucho que encapsulan este tipo de librerías, tanto así que no es necesario contar con un conocimiento profundo de los temas para realizar proyectos personales o comenzar a familiarizarnos con los conceptos y componentes que viven dentro del mundo de ML
referencias
Transfer learning with ResNet-50 in PyTorch | Kaggle
Repositorio: https://github.com/carlosJoseloMtz/pytorch-clasificador-de-imagenes