Dies ist ein Studienmemo (6. Ausgabe) zur Bildklassifizierung (Google Colaboratory-Umgebung) mit TensorFlow2 + Keras. Das Thema ist die Klassifizierung von handgeschriebenen numerischen Bildern (MNIST), die ein Standardelement ist.
Letztes Mal machte eine Vorhersage (Klassifizierung) unter Verwendung des handgeschriebenen numerischen Bildes, das zuvor von MNIST erstellt wurde. Dieses Mal möchte ich ein Bild verwenden, das ich selbst erstellt habe, um die Modelle als trainiert zu klassifizieren. Darüber hinaus möchte ich das Python-Programm (unter Verwendung der Pillow-Bibliothek) erläutern, das sich auf die ** Vorverarbeitung bezieht, z. B. das Ändern der Größe und das Trimmen **, die zu diesem Zeitpunkt erforderlich waren.
Ich habe durch Malen ein handgeschriebenes Zeichen von "** 8 **" mit einer Größe von ** 100 ** $ \ mal $ ** 100 ** Pixel erstellt und es als Farb-PNG-Datei (RGB) gespeichert. Ich habe es "test-8.png " genannt.
Sie können hochladen, indem Sie die Registerkarte Datei im Seitenmenü von Google Colab aktivieren und wie folgt per Drag & Drop von Ihrem Desktop ziehen: Die hochgeladene Datei wird ** nach einer bestimmten Zeit ** gelöscht **.
Sie können auch über den Dateiauswahldialog hochladen, indem Sie eine Codezelle schreiben und wie folgt ausführen.
Der absolute Pfad der hochgeladenen Datei (test-8.png
) lautet / content / test-8.png
. Da das aktuelle Verzeichnis "/ content" ist, können Sie auch mit "test-8.png " darauf zugreifen.
Sie können auch Google Drive bereitstellen und danach suchen. Weitere Informationen finden Sie unter Google Colaboratory (von der ersten Verwendung bis zum Laden von Dateien) @ Qiita.
Laden Sie die hochgeladene Bilddatei und zeigen Sie sie zur Überprüfung des Inhalts an. Bilder werden mit Pillow (PIL Fork) behandelt. Nur 3 Zeilen.
python
import PIL.Image as Image
img = Image.open('test-8.png')
display(img)
Die folgende ** Vorverarbeitung ** ist erforderlich, um das trainierte Modell auszufüllen.
Sie können die obige Vorverarbeitung mit dem folgenden Code durchführen. Es ist zu beachten, dass ein normales Graustufenbild mit 256 Schritten ** Weiß "255" und Schwarz "0" ** ist, daher muss es invertiert werden.
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.In Graustufen konvertieren
img = img.resize((28,28)) # 2.Größe geändert auf 28x28
x_sample = np.array(img) # 3. numpy.In ndarray-Typ konvertieren
x_sample = 1.0 - x_sample / 255.0 # 4.Inversion / Normalisierung
y_sample = 8 #Richtige Antwortdaten
#Bestätigungsausgabe
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()
Das Ausführungsergebnis ist wie folgt.
Erstellen Sie für dieses x_sample
eine Vorhersage mit einem trainierten Modell und erstellen Sie einen Vorhersageergebnisbericht mit dem in [4.] gezeigten Programm (https://qiita.com/code0327/items/1047adc050ab6d75ad5c). Es wird wie folgt sein.
Ich konnte eine gute Vorhersage treffen (Klassifizierung).
Grundsätzlich ist es dasselbe wie das in [4.] gezeigte Programm (https://qiita.com/code0327/items/1047adc050ab6d75ad5c), aber "x_sample" sind die einzelnen Eingabedaten, "y_sample" sind die richtigen Antwortdaten. Ich schreibe die Annahme um, dass das trainierte Modell in "Modell" gespeichert ist.
matplotlib_Japanischer Prozess zur Vorbereitung der Ausgabe
!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] #Vorhersage (Klassifizierung)
fig, ax = plt.subplots(nrows=2,figsize=(3,4.2), dpi=120,
gridspec_kw={'height_ratios': [3, 1]})
plt.subplots_adjust(hspace=0.05)
#Zeigen Sie das Bild der handgeschriebenen Zahlen auf der Oberseite an
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)
#Der richtige Antwortwert und der vorhergesagte Wert werden oben links angezeigt
t = ax[0].text(0.5, 0.5, f'Richtige Antwort:{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'Prognose:{s_sample.argmax()}',
verticalalignment='top', fontsize=9, color='tab:red')
t.set_path_effects([pe.Stroke(linewidth=2, foreground='white'), pe.Normal()])
#Zeigen Sie die NN-Vorhersageausgabe unten an
b = ax[1].bar(np.arange(0,10),s_sample,width=0.95)
b[s_sample.argmax()].set_facecolor('tab:red') #Machen Sie den maximalen Gegenstand rot
#X-Achseneinstellung
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') #Machen Sie den maximalen Gegenstand rot
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)
#Einstellung der Y-Achse
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')
Wenn Sie selbst ein Bild mit handgeschriebenen Zahlen erstellen, gibt es Fälle, in denen sich ** die Zahlen nicht in der Bildmitte befinden **, wie unten gezeigt.
Wenn Sie ein solches Bild so vorhersagen (klassifizieren), wie es ist, erhalten Sie ** schreckliche Ergebnisse ** wie folgt.
Aus diesem Grund ist es vor einer Vorhersage erforderlich, den Zeichenteil in die Mitte zu verschieben und eine Vorverarbeitung durchzuführen, so dass der Nettozeichenteil etwa 90% der Größe der Figur beträgt. es gibt. Außerdem müssen ** Schmutz ** und ** Staub ** außer Zeichen entfernt werden.
Hier möchte ich die folgende (automatisierte) Vorverarbeitung durchführen.
Vorverarbeitung
import numpy as np
from PIL import Image, ImageChops,ImageFilter, ImageOps, ImageDraw
import matplotlib.pyplot as plt
#Fügen Sie oben, unten, links und rechts in der Abbildung Ränder (weiß) mit der angegebenen Breite hinzu
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
#Die Größe, die zur langen Seite des durch das Argument angegebenen Rechtecks passt
#Berechnen Sie ein Quadrat (aber etwas größer)
def to_square( rect ):
x1, y1, x2, y2 = rect # (x1,y1)Ist die obere linke, (x2,y2)Ist die untere rechte Koordinate
s = max( x2-x1, y2-y1 ) #Holen Sie sich die Länge der langen Seite
s = int(s*1.3) #Ein bisschen größer
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)
#Fügen Sie oben, unten, links und rechts im Bild weiße Ränder hinzu
img = add_margin(img,int(max(img.size)*0.2))
#display(img)
#Erstellen Sie ein invertiertes Bild
img2 = ImageOps.invert(img)
#Verwischen
img2 = img2.filter(ImageFilter.GaussianBlur(1.5))
#display(img2)
#Binarisierung
img2 = img2.point(lambda p: p > 150 and 255)
#display(img2)
#Holen Sie sich den kleinsten Bereich (rechteckig) außer schwarz
rect = img2.getbbox()
# tmp = img2.convert('RGB')
# ImageDraw.Draw(tmp).rectangle(rect, fill=None, outline='red')
# display(tmp)
#Konvertieren Sie ein Rechteck in ein Quadrat, das zur langen Seite passt
sqr = to_square(rect)
# tmp = img2.convert('RGB')
# ImageDraw.Draw(tmp).rectangle(sqr, fill=None, outline='red')
# display(tmp)
#Mit einem Quadrat getrimmt
img = img.crop(sqr)
#display(img)
#Danach das gleiche wie zuvor
img = img.convert('L') # 1.In Graustufen konvertieren
img = img.resize((28,28)) # 2.Größe geändert auf 28x28
x_sample = np.array(img) # 3. numpy.In ndarray-Typ konvertieren
x_sample = 1.0 - x_sample / 255.0 # 4.Inversion / Normalisierung
y_sample = 2 #Richtige Antwortdaten
#Bestätigungsausgabe
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()
Dies ist ein Vergleich der Ergebnisse der ** prädiktiven Klassifizierung ohne Vorverarbeitung und der ** prädiktiven Klassifizierung nach der Vorverarbeitung. Ich erkenne noch einmal, dass die Vorverarbeitung wichtig ist, bevor ich das Vorhersagemodell versuche und Fehler mache.
――Da der äußere Wassergraben aufgefüllt ist, möchte ich endlich den ** Modellbau ** des neuronalen Netzes untersuchen.
Recommended Posts