Il s'agit d'un mémo d'étude (6ème) sur la classification d'images (environnement Google Colaboratory) utilisant TensorFlow2 + Keras. Le sujet est la classification des images numériques manuscrites (MNIST), qui est un élément standard.
Dernière fois a fait une prédiction (classification) en utilisant l'image numérique manuscrite préparée à l'avance par le MNIST. Cette fois, j'aimerais utiliser ** une image que je me suis préparée ** pour classer les modèles comme entraînés. En outre, je voudrais expliquer le programme Python (en utilisant la bibliothèque Pillow) lié au ** prétraitement tel que le redimensionnement et le rognage ** requis à ce moment-là.
J'ai créé un caractère manuscrit de "** 8 **" avec une taille de ** 100 ** $ \ fois $ ** 100 ** pixel en peignant et l'ai enregistré en tant que fichier PNG de couleur (RVB). Je l'ai nommé test-8.png
.
Vous pouvez importer en activant l'onglet Fichier dans Google Colab. Menu latéral et glisser-déposer depuis votre bureau comme suit: Le fichier téléchargé sera supprimé ** après une certaine période de temps **.
Vous pouvez également télécharger à l'aide de la boîte de dialogue de sélection de fichier en écrivant une cellule de code et en l'exécutant comme suit.
Le chemin absolu du fichier téléchargé (test-8.png
) sera / content / test-8.png
. De plus, puisque le répertoire courant est / content
, vous pouvez y accéder avec juste test-8.png
.
Vous pouvez également monter Google Drive et le rechercher. Pour plus d'informations, consultez Google Colaboratory (de la première utilisation au chargement des fichiers) @ Qiita.
Chargez le fichier image téléchargé et affichez-le pour en vérifier le contenu. Les images sont gérées à l'aide de Pillow (PIL Fork). Seulement 3 lignes.
python
import PIL.Image as Image
img = Image.open('test-8.png')
display(img)
Le ** prétraitement ** suivant est requis pour remplir le modèle formé.
Vous pouvez effectuer le prétraitement ci-dessus avec le code suivant. Il convient de noter qu'une image normale à 256 niveaux de gris ** blanc est "255" et le noir est "0" **, il doit donc être inversé.
python
import numpy as np
import PIL.Image as Image
import matplotlib.pyplot as plt
img = Image.open('test-8.png')
img = img.convert('L') # 1.Convertir en échelle de gris
img = img.resize((28,28)) # 2.Redimensionné à 28x28
x_sample = np.array(img) # 3. numpy.Convertir en type ndarray
x_sample = 1.0 - x_sample / 255.0 # 4.Inversion / normalisation
y_sample = 8 #Corriger les données de réponse
#Sortie de confirmation
print(f'x_sample.type = {type(x_sample)}')
print(f'x_sample.shape = {x_sample.shape}')
plt.figure()
plt.imshow(x_sample,vmin=0.,vmax=1.,cmap='Greys')
plt.show()
Le résultat de l'exécution est le suivant.
Pour cet x_sample
, faites une prédiction avec un modèle entraîné et créez un rapport de résultat de prédiction avec le programme montré dans 4th. Ce sera comme suit.
J'ai pu faire un bon pronostic (classement).
Fondamentalement, c'est le même que le programme montré dans 4th, mais x_sample
est la seule donnée d'entrée, y_sample
est la bonne réponse, Je réécris l'hypothèse que le modèle entraîné est stocké dans model
.
matplotlib_Processus de préparation de la sortie japonaise
!pip install japanize-matplotlib
import japanize_matplotlib
python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as pe
import matplotlib.transforms as ts
s_sample = model.predict(np.array([x_sample]))[0] #Prédiction (classification)
fig, ax = plt.subplots(nrows=2,figsize=(3,4.2), dpi=120,
gridspec_kw={'height_ratios': [3, 1]})
plt.subplots_adjust(hspace=0.05)
#Afficher l'image des nombres manuscrits sur la face supérieure
ax[0].imshow(x_sample,interpolation='nearest',vmin=0.,vmax=1.,cmap='Greys')
ax[0].tick_params(axis='both', which='both', left=False,
labelleft=False, bottom=False, labelbottom=False)
#La valeur de réponse correcte et la valeur prédite sont affichées en haut à gauche
t = ax[0].text(0.5, 0.5, f'Bonne réponse:{y_sample}',
verticalalignment='top', fontsize=9, color='tab:red')
t.set_path_effects([pe.Stroke(linewidth=2, foreground='white'), pe.Normal()])
t = ax[0].text(0.5, 2.5, f'Prédiction:{s_sample.argmax()}',
verticalalignment='top', fontsize=9, color='tab:red')
t.set_path_effects([pe.Stroke(linewidth=2, foreground='white'), pe.Normal()])
#Afficher la sortie de prédiction NN en bas
b = ax[1].bar(np.arange(0,10),s_sample,width=0.95)
b[s_sample.argmax()].set_facecolor('tab:red') #Rendre l'élément maximum rouge
#Réglage de l'axe X
ax[1].tick_params(axis='x',bottom=False)
ax[1].set_xticks(np.arange(0,10))
t = ax[1].set_xticklabels(np.arange(0,10),fontsize=11)
t[s_sample.argmax()].set_color('tab:red') #Rendre l'élément maximum rouge
offset = ts.ScaledTranslation(0, 0.03, plt.gcf().dpi_scale_trans)
for label in ax[1].xaxis.get_majorticklabels() :
label.set_transform(label.get_transform() + offset)
#Réglage de l'axe Y
ax[1].tick_params(axis='y',direction='in')
ax[1].set_ylim(0,1)
ax[1].set_yticks(np.linspace(0,1,5))
ax[1].set_axisbelow(True)
ax[1].grid(axis='y')
Si vous préparez vous-même une image de nombres manuscrits, il y a des cas où ** le numéro ne se trouve pas au centre de l'image ** comme indiqué ci-dessous.
Si vous appliquez la prédiction (classification) à une image telle qu'elle est, vous obtiendrez ** des résultats terribles ** comme suit.
Pour cette raison, avant de faire une prédiction, il est nécessaire de déplacer la partie caractère vers le centre et d'effectuer un prétraitement de telle sorte que la partie caractère net représente environ 90% de la taille de la figure. il y a. De plus, il est nécessaire d'éliminer les ** saletés ** et ** poussières ** autres que les caractères.
Ici, je voudrais faire le prétraitement (automatisé) suivant.
Prétraitement
import numpy as np
from PIL import Image, ImageChops,ImageFilter, ImageOps, ImageDraw
import matplotlib.pyplot as plt
#Ajouter des marges (blanches) de la largeur spécifiée en haut, en bas, à gauche et à droite de la figure
def add_margin(img, margin):
w, h = img.size
w2 = w + 2 * margin
h2 = h + 2 * margin
result = Image.new('L', (w2, h2), 255)
result.paste(img, (margin, margin))
return result
#La taille qui correspond au côté long du rectangle donné par l'argument
#Calculer un carré (mais un peu plus grand) carré
def to_square( rect ):
x1, y1, x2, y2 = rect # (x1,y1)Est le coin supérieur gauche, (x2,y2)Est la coordonnée inférieure droite
s = max( x2-x1, y2-y1 ) #Obtenez la longueur du côté long
s = int(s*1.3) #Un peu plus grand
nx1 = (x1+x2)/2 - s/2
nx2 = (x1+x2)/2 + s/2
ny1 = (y1+y2)/2 - s/2
ny2 = (y1+y2)/2 + s/2
return (nx1,ny1,nx2,ny2)
img = Image.open('test-2x.png')
img = img.convert('L')
#display(img)
#Ajoutez des marges blanches en haut, en bas, à gauche et à droite de l'image
img = add_margin(img,int(max(img.size)*0.2))
#display(img)
#Créer une image inversée
img2 = ImageOps.invert(img)
#Brouiller
img2 = img2.filter(ImageFilter.GaussianBlur(1.5))
#display(img2)
#Binarisation
img2 = img2.point(lambda p: p > 150 and 255)
#display(img2)
#Obtenez la plus petite zone (rectangulaire) autre que le noir
rect = img2.getbbox()
# tmp = img2.convert('RGB')
# ImageDraw.Draw(tmp).rectangle(rect, fill=None, outline='red')
# display(tmp)
#Convertir un rectangle en carré qui s'adapte au côté long
sqr = to_square(rect)
# tmp = img2.convert('RGB')
# ImageDraw.Draw(tmp).rectangle(sqr, fill=None, outline='red')
# display(tmp)
#Paré d'un carré
img = img.crop(sqr)
#display(img)
#Après ça, comme avant
img = img.convert('L') # 1.Convertir en échelle de gris
img = img.resize((28,28)) # 2.Redimensionné à 28x28
x_sample = np.array(img) # 3. numpy.Convertir en type ndarray
x_sample = 1.0 - x_sample / 255.0 # 4.Inversion / normalisation
y_sample = 2 #Corriger les données de réponse
#Sortie de confirmation
print(f'x_sample.type = {type(x_sample)}')
print(f'x_sample.shape = {x_sample.shape}')
plt.figure()
plt.imshow(x_sample,vmin=0.,vmax=1.,cmap='Greys')
plt.show()
Il s'agit d'une comparaison des résultats de la ** classification prédictive sans prétraitement et de la ** classification prédictive après prétraitement. Je me rends compte une fois de plus que le prétraitement est important avant d'essayer et de se tromper sur le modèle de prédiction.
――Depuis que le fossé extérieur est comblé, je voudrais enfin étudier la ** construction du modèle ** du réseau neuronal.
Recommended Posts