Classification d'image à l'aide d'un modèle pré-formé

Dans cette leçon, vous apprendrez à utiliser un modèle pré-entraîné pour détecter des objets dans une image donnée. Vous utiliserezsqueezenet module pré-formé qui détecte et classe les objets dans une image donnée avec une grande précision.

Ouvrez un nouveau Juypter notebook et suivez les étapes pour développer cette application de classification d'images.

Importation de bibliothèques

Tout d'abord, nous importons les packages requis en utilisant le code ci-dessous -

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

Ensuite, nous avons mis en place quelques variables -

INPUT_IMAGE_SIZE = 227
mean = 128

Les images utilisées pour la formation seront évidemment de tailles variées. Toutes ces images doivent être converties en une taille fixe pour un entraînement précis. De même, les images de test et l'image que vous souhaitez prédire dans l'environnement de production doivent également être converties à la taille, identique à celle utilisée lors de la formation. Ainsi, nous créons une variable ci-dessus appeléeINPUT_IMAGE_SIZE ayant de la valeur 227. Par conséquent, nous convertirons toutes nos images à la taille227x227 avant de l'utiliser dans notre classificateur.

Nous déclarons également une variable appelée mean ayant de la valeur 128, qui est utilisé plus tard pour améliorer les résultats de classification.

Ensuite, nous développerons deux fonctions de traitement de l'image.

Traitement d'image

Le traitement de l'image se compose de deux étapes. Le premier consiste à redimensionner l'image et le second à recadrer l'image au centre. Pour ces deux étapes, nous écrirons deux fonctions de redimensionnement et de recadrage.

Redimensionnement d'image

Tout d'abord, nous allons écrire une fonction de redimensionnement de l'image. Comme dit précédemment, nous redimensionnerons l'image pour227x227. Alors définissons la fonctionresize comme suit -

def resize(img, input_height, input_width):

Nous obtenons le rapport hauteur / largeur de l'image en divisant la largeur par la hauteur.

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

Si le rapport hauteur / largeur est supérieur à 1, cela indique que l'image est large, c'est-à-dire qu'elle est en mode paysage. Nous ajustons maintenant la hauteur de l'image et renvoyons l'image redimensionnée en utilisant le code suivant -

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 le rapport hauteur / largeur est less than 1, il indique le portrait mode. Nous ajustons maintenant la largeur en utilisant le code suivant -

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 le rapport hauteur / largeur est égal à 1, nous n'effectuons aucun réglage de hauteur / largeur.

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

Le code de fonction complet est donné ci-dessous pour votre référence rapide -

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)

Nous allons maintenant écrire une fonction pour recadrer l'image autour de son centre.

Recadrage d'image

Nous déclarons le crop_image fonction comme suit -

def crop_image(img,cropx,cropy):

Nous extrayons les dimensions de l'image en utilisant la déclaration suivante -

y,x,c = img.shape

Nous créons un nouveau point de départ pour l'image en utilisant les deux lignes de code suivantes -

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

Enfin, nous retournons l'image recadrée en créant un objet image avec les nouvelles dimensions -

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

Le code de fonction complet est donné ci-dessous pour votre référence rapide -

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]

Maintenant, nous allons écrire du code pour tester ces fonctions.

Traitement de l'image

Tout d'abord, copiez un fichier image dans images sous-dossier dans le répertoire de votre projet. tree.jpgLe fichier est copié dans le projet. Le code Python suivant charge l'image et l'affiche sur la console -

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 sortie est la suivante -

Notez que la taille de l'image d'origine est 600 x 960. Nous devons redimensionner ceci à notre spécification de227 x 227. Appelant notre défini précédemmentresizefonction fait ce travail.

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 sortie est comme donnée ci-dessous -

Notez que maintenant la taille de l'image est 227 x 363. Nous devons recadrer ceci pour227 x 227pour le flux final de notre algorithme. Nous appelons la fonction de recadrage précédemment définie à cet effet.

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')

Ci-dessous mentionné est la sortie du code -

À ce stade, l'image est de taille 227 x 227et est prêt pour un traitement ultérieur. Nous échangeons maintenant les axes de l'image pour extraire les trois couleurs dans trois zones différentes.

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

Ci-dessous est la sortie -

CHW Image Shape: (3, 227, 227)

Notez que le dernier axe est maintenant devenu la première dimension du tableau. Nous allons maintenant tracer les trois canaux en utilisant le code suivant -

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 sortie est indiquée ci-dessous -

Enfin, nous effectuons des traitements supplémentaires sur l'image tels que la conversion Red Green Blue à Blue Green Red (RGB to BGR), en supprimant la moyenne pour de meilleurs résultats et en ajoutant un axe de taille de lot en utilisant les trois lignes de code suivantes -

# 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)

À ce stade, votre image est en NCHW formatet est prêt à alimenter notre réseau. Ensuite, nous allons charger nos fichiers de modèle pré-entraînés et y insérer l'image ci-dessus pour la prédiction.

Prédire les objets dans l'image traitée

Nous commençons par configurer les chemins pour le init et predict réseaux définis dans les modèles pré-entraînés de Caffe.

Définition des chemins de fichier du modèle

Rappelez-vous de notre discussion précédente, tous les modèles pré-entraînés sont installés dans le modelsdossier. Nous avons configuré le chemin d'accès à ce dossier comme suit -

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

Nous avons tracé le chemin vers le init_net fichier protobuf du squeezenet modèle comme suit -

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

De même, nous mettons en place le chemin vers le predict_net protobuf comme suit -

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

Nous imprimons les deux chemins à des fins de diagnostic -

print(INIT_NET)
print(PREDICT_NET)

Le code ci-dessus avec la sortie est donné ici pour votre référence rapide -

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 sortie est mentionnée ci-dessous -

/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

Ensuite, nous allons créer un prédicteur.

Créer un prédicteur

Nous lisons les fichiers de modèle en utilisant les deux instructions suivantes -

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

Le prédicteur est créé en passant des pointeurs vers les deux fichiers en tant que paramètres vers le Predictor fonction.

p = workspace.Predictor(init_net, predict_net)

le pobject est le prédicteur, qui est utilisé pour prédire les objets dans une image donnée. Notez que chaque image d'entrée doit être au format NCHW comme ce que nous avons fait précédemment à notretree.jpg fichier.

Prédire les objets

Prédire les objets dans une image donnée est trivial - il suffit d'exécuter une seule ligne de commande. Nous appelonsrun méthode sur le predictor objet pour une détection d'objet dans une image donnée.

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

Les résultats de la prédiction sont désormais disponibles dans le results objet, que nous convertissons en un tableau pour notre lisibilité.

results = np.asarray(results)

Imprimez les dimensions du tableau pour votre compréhension en utilisant la déclaration suivante -

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

La sortie est comme indiqué ci-dessous -

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

Nous allons maintenant supprimer l'axe inutile -

preds = np.squeeze(results)

La prédication la plus élevée peut maintenant être récupérée en prenant le max valeur dans le preds tableau.

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

La sortie est la suivante -

Prediction: 984
Confidence: 0.89235985

Comme vous le voyez, le modèle a prédit un objet avec une valeur d'index 984 avec 89%confiance. L'indice de 984 n'a pas beaucoup de sens pour nous pour comprendre quel type d'objet est détecté. Nous devons obtenir le nom stringifié de l'objet en utilisant sa valeur d'index. Le type d'objets que le modèle reconnaît ainsi que leurs valeurs d'index correspondantes sont disponibles sur un référentiel github.

Maintenant, nous allons voir comment récupérer le nom de notre objet ayant une valeur d'index de 984.

Résultat stringifiant

Nous créons un objet URL vers le référentiel github comme suit -

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

Nous lisons le contenu de l'URL -

response = urllib2.urlopen(codes)

La réponse contiendra une liste de tous les codes et leurs descriptions. Quelques lignes de la réponse sont affichées ci-dessous pour votre compréhension de ce qu'elle contient -

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

Nous parcourons maintenant l'ensemble du tableau pour localiser notre code souhaité de 984 à l'aide d'un for boucle comme suit -

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")

Lorsque vous exécutez le code, vous verrez la sortie suivante -

Model predicts rapeseed with 0.89235985 confidence

Vous pouvez maintenant essayer le modèle sur une autre image.

Prédire une image différente

Pour prédire une autre image, copiez simplement le fichier image dans le imagesdossier de votre répertoire de projet. C'est le répertoire dans lequel notre ancientree.jpgle fichier est stocké. Modifiez le nom du fichier image dans le code. Une seule modification est requise comme indiqué ci-dessous

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

L'image originale et le résultat de la prédiction sont affichés ci-dessous -

La sortie est mentionnée ci-dessous -

Model predicts pretzel with 0.99999976 confidence

Comme vous le voyez, le modèle pré-entraîné est capable de détecter des objets dans une image donnée avec une grande précision.

Source complète

La source complète du code ci-dessus qui utilise un modèle pré-entraîné pour la détection d'objet dans une image donnée est mentionnée ici pour votre référence rapide -

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")

À ce stade, vous savez comment utiliser un modèle pré-entraîné pour effectuer les prédictions sur votre ensemble de données.

La prochaine étape consiste à apprendre à définir votre neural network (NN) architectures dans Caffe2et formez-les sur votre ensemble de données. Nous allons maintenant apprendre à créer un NN simple couche simple.