Clasificación de imágenes mediante un modelo previamente entrenado

En esta lección, aprenderá a utilizar un modelo previamente entrenado para detectar objetos en una imagen determinada. Usarássqueezenet Módulo pre-entrenado que detecta y clasifica los objetos en una imagen dada con gran precisión.

Abra una nueva Juypter notebook y siga los pasos para desarrollar esta aplicación de clasificación de imágenes.

Importación de bibliotecas

Primero, importamos los paquetes requeridos usando el siguiente código:

from caffe2.proto import caffe2_pb2
from caffe2.python import core, workspace, models
import numpy as np
import skimage.io
import skimage.transform
from matplotlib import pyplot
import os
import urllib.request as urllib2
import operator

A continuación, configuramos algunos variables -

INPUT_IMAGE_SIZE = 227
mean = 128

Obviamente, las imágenes utilizadas para el entrenamiento serán de varios tamaños. Todas estas imágenes deben convertirse a un tamaño fijo para un entrenamiento preciso. Asimismo, las imágenes de prueba y la imagen que se quiere predecir en el entorno de producción también deben convertirse al tamaño, el mismo que se utilizó durante el entrenamiento. Por lo tanto, creamos una variable llamada arribaINPUT_IMAGE_SIZE tener valor 227. Por lo tanto, convertiremos todas nuestras imágenes al tamaño227x227 antes de usarlo en nuestro clasificador.

También declaramos una variable llamada mean tener valor 128, que se utiliza más adelante para mejorar los resultados de la clasificación.

A continuación, desarrollaremos dos funciones para procesar la imagen.

Procesamiento de imágenes

El procesamiento de imágenes consta de dos pasos. El primero es cambiar el tamaño de la imagen y el segundo es recortar la imagen de forma centralizada. Para estos dos pasos, escribiremos dos funciones para cambiar el tamaño y recortar.

Cambio de tamaño de imagen

Primero, escribiremos una función para cambiar el tamaño de la imagen. Como se dijo anteriormente, cambiaremos el tamaño de la imagen para227x227. Así que definamos la funciónresize como sigue -

def resize(img, input_height, input_width):

Obtenemos la relación de aspecto de la imagen dividiendo el ancho por el alto.

original_aspect = img.shape[1]/float(img.shape[0])

Si la relación de aspecto es superior a 1, indica que la imagen es amplia, es decir que está en modo paisaje. Ahora ajustamos la altura de la imagen y devolvemos la imagen redimensionada usando el siguiente código:

if(original_aspect>1):
   new_height = int(original_aspect * input_height)
   return skimage.transform.resize(img, (input_width,
   new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Si la relación de aspecto es less than 1, indica el portrait mode. Ahora ajustamos el ancho usando el siguiente código:

if(original_aspect<1):
   new_width = int(input_width/original_aspect)
   return skimage.transform.resize(img, (new_width,
   input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Si la relación de aspecto es igual a 1, no realizamos ningún ajuste de altura / ancho.

if(original_aspect == 1):
   return skimage.transform.resize(img, (input_width,
   input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

El código de función completo se proporciona a continuación para su referencia rápida:

def resize(img, input_height, input_width):
   original_aspect = img.shape[1]/float(img.shape[0])
   if(original_aspect>1):
      new_height = int(original_aspect * input_height)
      return skimage.transform.resize(img, (input_width,
	   new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
   if(original_aspect<1):
         new_width = int(input_width/original_aspect)
         return skimage.transform.resize(img, (new_width,
         input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
   if(original_aspect == 1):
         return skimage.transform.resize(img, (input_width,
         input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Ahora escribiremos una función para recortar la imagen alrededor de su centro.

Recorte de imágenes

Declaramos el crop_image funciona de la siguiente manera:

def crop_image(img,cropx,cropy):

Extraemos las dimensiones de la imagen usando la siguiente declaración:

y,x,c = img.shape

Creamos un nuevo punto de partida para la imagen usando las siguientes dos líneas de código:

startx = x//2-(cropx//2)
starty = y//2-(cropy//2)

Finalmente, devolvemos la imagen recortada creando un objeto de imagen con las nuevas dimensiones -

return img[starty:starty+cropy,startx:startx+cropx]

El código de función completo se proporciona a continuación para su referencia rápida:

def crop_image(img,cropx,cropy):
   y,x,c = img.shape
   startx = x//2-(cropx//2)
   starty = y//2-(cropy//2)
   return img[starty:starty+cropy,startx:startx+cropx]

Ahora, escribiremos código para probar estas funciones.

Procesando imagen

En primer lugar, copie un archivo de imagen en images subcarpeta dentro del directorio de su proyecto. tree.jpgEl archivo se copia en el proyecto. El siguiente código de Python carga la imagen y la muestra en la consola:

img = skimage.img_as_float(skimage.io.imread("images/tree.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')

La salida es la siguiente:

Tenga en cuenta que el tamaño de la imagen original es 600 x 960. Necesitamos cambiar el tamaño de esto a nuestra especificación de227 x 227. Llamando a nuestro definido anteriormenteresizela función hace este trabajo.

img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')

La salida es la que se muestra a continuación:

Tenga en cuenta que ahora el tamaño de la imagen es 227 x 363. Necesitamos recortar esto para227 x 227para la alimentación final de nuestro algoritmo. Llamamos a la función de cultivo previamente definida para este propósito.

img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')

A continuación se menciona la salida del código:

En este punto, la imagen es de tamaño 227 x 227y está listo para su posterior procesamiento. Ahora intercambiamos los ejes de la imagen para extraer los tres colores en tres zonas diferentes.

img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)

A continuación se muestra la salida:

CHW Image Shape: (3, 227, 227)

Tenga en cuenta que el último eje ahora se ha convertido en la primera dimensión de la matriz. Ahora trazaremos los tres canales usando el siguiente código:

pyplot.figure()
for i in range(3):
   pyplot.subplot(1, 3, i+1)
   pyplot.imshow(img[i])
   pyplot.axis('off')
   pyplot.title('RGB channel %d' % (i+1))

La salida se indica a continuación:

Finalmente, realizamos un procesamiento adicional en la imagen, como convertir Red Green Blue a Blue Green Red (RGB to BGR), eliminando la media para obtener mejores resultados y agregando el eje de tamaño de lote utilizando las siguientes tres líneas de código:

# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)

En este punto, su imagen está en NCHW formaty está listo para ingresar a nuestra red. A continuación, cargaremos nuestros archivos de modelo previamente entrenados y alimentaremos la imagen de arriba para la predicción.

Predicción de objetos en imagen procesada

Primero configuramos los caminos para el init y predict redes definidas en los modelos pre-entrenados de Caffe.

Establecer rutas de archivo de modelo

Recuerde de nuestra discusión anterior, todos los modelos entrenados previamente se instalan en el modelscarpeta. Configuramos la ruta a esta carpeta de la siguiente manera:

CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")

Preparamos el camino hacia el init_net archivo protobuf del squeezenet modelo de la siguiente manera -

INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')

Asimismo, configuramos el camino hacia el predict_net protobuf de la siguiente manera:

PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')

Imprimimos las dos rutas con fines de diagnóstico:

print(INIT_NET)
print(PREDICT_NET)

El código anterior junto con el resultado se proporciona aquí para su referencia rápida:

CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)

La salida se menciona a continuación:

/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/init_net.pb
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/predict_net.pb

A continuación, crearemos un predictor.

Creando Predictor

Leemos los archivos del modelo usando las siguientes dos declaraciones:

with open(INIT_NET, "rb") as f:
   init_net = f.read()
with open(PREDICT_NET, "rb") as f:
   predict_net = f.read()

El predictor se crea pasando punteros a los dos archivos como parámetros al Predictor función.

p = workspace.Predictor(init_net, predict_net)

los pobject es el predictor, que se utiliza para predecir los objetos en cualquier imagen dada. Tenga en cuenta que cada imagen de entrada debe estar en formato NCHW como lo hemos hecho anteriormente a nuestrotree.jpg archivo.

Predicción de objetos

Predecir los objetos en una imagen dada es trivial, simplemente ejecutando una sola línea de comando. Nosotros llamamosrun método en el predictor objeto para la detección de un objeto en una imagen determinada.

results = p.run({'data': img})

Los resultados de la predicción ahora están disponibles en el results objeto, que convertimos en una matriz para nuestra legibilidad.

results = np.asarray(results)

Imprima las dimensiones de la matriz para su comprensión utilizando la siguiente declaración:

print("results shape: ", results.shape)

La salida es la que se muestra a continuación:

results shape: (1, 1, 1000, 1, 1)

Ahora eliminaremos el eje innecesario:

preds = np.squeeze(results)

La predicación más alta ahora se puede recuperar tomando el max valor en el preds formación.

curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)

La salida es la siguiente:

Prediction: 984
Confidence: 0.89235985

Como ve, el modelo ha predicho un objeto con un valor de índice 984 con 89%confianza. El índice de 984 no tiene mucho sentido para nosotros para comprender qué tipo de objeto se detecta. Necesitamos obtener el nombre en cadena para el objeto usando su valor de índice. El tipo de objetos que reconoce el modelo junto con sus valores de índice correspondientes están disponibles en un repositorio de github.

Ahora, veremos cómo recuperar el nombre de nuestro objeto que tiene un valor de índice de 984.

Resultado de cadena de caracteres

Creamos un objeto URL en el repositorio de github de la siguiente manera:

codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac0
71eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"

Leemos el contenido de la URL -

response = urllib2.urlopen(codes)

La respuesta contendrá una lista de todos los códigos y sus descripciones. A continuación se muestran algunas líneas de la respuesta para que comprenda lo que contiene:

5: 'electric ray, crampfish, numbfish, torpedo',
6: 'stingray',
7: 'cock',
8: 'hen',
9: 'ostrich, Struthio camelus',
10: 'brambling, Fringilla montifringilla',

Ahora iteramos toda la matriz para localizar nuestro código deseado de 984 usando un for bucle de la siguiente manera:

for line in response:
   mystring = line.decode('ascii')
   code, result = mystring.partition(":")[::2]
   code = code.strip()
   result = result.replace("'", "")
   if (code == str(curr_pred)):
      name = result.split(",")[0][1:]
      print("Model predicts", name, "with", curr_conf, "confidence")

Cuando ejecute el código, verá el siguiente resultado:

Model predicts rapeseed with 0.89235985 confidence

Ahora puede probar el modelo en otra imagen.

Predecir una imagen diferente

Para predecir otra imagen, simplemente copie el archivo de imagen en el imagescarpeta del directorio de su proyecto. Este es el directorio en el que nuestro anteriortree.jpgel archivo está almacenado. Cambie el nombre del archivo de imagen en el código. Solo se requiere un cambio como se muestra a continuación

img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)

La imagen original y el resultado de la predicción se muestran a continuación:

La salida se menciona a continuación:

Model predicts pretzel with 0.99999976 confidence

Como puede ver, el modelo previamente entrenado es capaz de detectar objetos en una imagen dada con gran precisión.

Fuente completa

La fuente completa del código anterior que utiliza un modelo previamente entrenado para la detección de objetos en una imagen determinada se menciona aquí para su referencia rápida:

def crop_image(img,cropx,cropy):
   y,x,c = img.shape
   startx = x//2-(cropx//2)
   starty = y//2-(cropy//2)
   return img[starty:starty+cropy,startx:startx+cropx]
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
with open(INIT_NET, "rb") as f:
   init_net = f.read()
with open(PREDICT_NET, "rb") as f:
   predict_net = f.read()
p = workspace.Predictor(init_net, predict_net)
results = p.run({'data': img})
results = np.asarray(results)
print("results shape: ", results.shape)
preds = np.squeeze(results)
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac071eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
response = urllib2.urlopen(codes)
for line in response:
   mystring = line.decode('ascii')
   code, result = mystring.partition(":")[::2]
   code = code.strip()
   result = result.replace("'", "")
   if (code == str(curr_pred)):
      name = result.split(",")[0][1:]
      print("Model predicts", name, "with", curr_conf, "confidence")

En este momento, sabrá cómo utilizar un modelo previamente entrenado para realizar las predicciones en su conjunto de datos.

Lo que sigue es aprender a definir su neural network (NN) arquitecturas en Caffe2y capacítelos en su conjunto de datos. Ahora aprenderemos cómo crear un NN trivial de una sola capa.