Plötzlich begann ich in Kapitel 3 von "Deep Learning von Grund auf - Theorie und Implementierung von Deep Learning, das mit Python gelernt wurde" zu studieren. Es ist ein Memo der Reise.
Die Ausführungsumgebung ist macOS Mojave + Anaconda 2019.10. Weitere Informationen finden Sie in Kapitel 1 dieses Memos.
(Zu anderen Kapiteln dieses Memos: Kapitel 1 / Kapitel 2 / 3 Kapitel / Kapitel 4 / Kapitel 5 / [Kapitel 6](https: / /qiita.com/segavvy/items/ca4ac4c9ee1a126bff41) / Kapitel 7 / Kapitel 8 / Zusammenfassung)
In diesem Kapitel wird beschrieben, wie das neuronale Netzwerk funktioniert.
Es erklärt den Unterschied beim Zählen von Schichten und den Unterschied zwischen Perceptron und dem neuronalen Netzwerk. Es ist etwas unpraktisch, dass verschiedene Personen unterschiedliche Schichten zählen.
Dies ist eine Einführung in die Arten von Aktivierungsfunktionen. Ich habe versucht, die drei Arten von Funktionen grafisch darzustellen, die angezeigt werden.
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
"""Schrittfunktion, die 1 zurückgibt, wenn die Eingabe 0 überschreitet
Args:
x (numpy.ndarray):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
return np.array(x > 0, dtype=np.int)
def sigmoid(x):
"""Sigmaid-Funktion
Args:
x (numpy.ndarray):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
return 1 / (1 + np.exp(-x))
def relu(x):
"""ReLU-Funktion
Args:
x (numpy.ndarray)):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
return np.maximum(0, x)
#Berechnung
x = np.arange(-5.0, 5.0, 0.01) #Schritt ist klein, damit die Schrittfunktion nicht diagonal aussieht
y_step = step_function(x)
y_sigmoid = sigmoid(x)
y_relu = relu(x)
#Diagrammzeichnung
plt.plot(x, y_step, label="step")
plt.plot(x, y_sigmoid, linestyle="--", label="sigmoid")
plt.plot(x, y_relu, linestyle=":", label="ReLU")
plt.ylim(-0.1, 5.1)
plt.legend()
plt.show()
Das einzige, was ich nicht verstanden habe, war, dass die Aktivierungsfunktion keine lineare Funktion sein sollte. Ich habe aus der Erklärung des Buches verstanden, dass wenn es nur ein Neuron in jeder Schicht gibt, es in einer Schicht ausgedrückt werden kann, selbst wenn es mehrschichtig ist. Aber selbst wenn es in jeder Schicht mehrere Neuronen gibt, kann es in einer Schicht ausgedrückt werden? Ich konnte es hier nicht gut verstehen.
Die Erklärung besteht darin, die Berechnung mehrdimensionaler Arrays durch die Berechnung von Matrizen zu ersetzen, um die Effizienz zu verbessern. Ich habe den Ersatz durch Matrixberechnung studiert, als ich vor ungefähr 3 Jahren den Online-Kurs für maschinelles Lernen [^ 1] belegte und ihn in den folgenden 100 Klopfen der Sprachverarbeitung [^ 2] verwendete, also werde ich ihn überprüfen. Ich tat.
Implementieren Sie ein dreischichtiges neuronales Netzwerk mithilfe der Matrixberechnung im vorherigen Abschnitt. Es gab keine Funktion zum Lernen, also gab es nichts, worüber man stolpern konnte.
Erläuterung der Softmax-Funktion. ~~ Auch hier gab es keinen besonderen Stolperstein. ~~ Ich wollte nicht stolpern, aber ich habe einen Fehler bemerkt. Wenn Sie keine Stapelverarbeitung durchführen, gibt es kein Problem, wie im Buch implementiert, aber Sie müssen es ändern, wenn Sie "3.6.3 Stapelverarbeitung" implementieren.
Unten finden Sie den Softmax-Code, der die Stapelverarbeitung unterstützt.
python
def softmax(x):
"""Softmax-Funktion
Args:
x (numpy.ndarray):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
#Für die Stapelverarbeitung ist x(Anzahl der Chargen, 10)Es wird eine zweidimensionale Anordnung von.
#In diesem Fall ist es erforderlich, für jedes Bild, das gesendet wird, eine gute Berechnung durchzuführen.
if x.ndim == 2:
#Für jedes Bild (Achse=1) Berechnen Sie den Maximalwert und formen Sie ihn neu, damit er gesendet werden kann
c = np.max(x, axis=1).reshape(x.shape[0], 1)
#Berechnen Sie das Molekül, während Sie den Maximalwert als Überlauf-Gegenmaßnahme abziehen
exp_a = np.exp(x - c)
#Der Nenner gilt auch für jedes Bild (Achse)=Umformen, so dass es zu 1) summiert und gesendet werden kann
sum_exp_a = np.sum(exp_a, axis=1).reshape(x.shape[0], 1)
#Berechnet für jedes Bild
y = exp_a / sum_exp_a
else:
#Wenn es sich nicht um eine Stapelverarbeitung handelt, implementieren Sie sie gemäß dem Buch
c = np.max(x)
exp_a = np.exp(x - c) #Überlaufmaßnahmen
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
Darüber hinaus im GitHub-Repository https://github.com/oreilly-japan/deep-learning-from-scratch dieses Buches An einer Quelle wurde es für den Rundfunk transponiert. Vielleicht ist es ein Geschwindigkeitsvorteil, aber auf den ersten Blick wusste ich nicht, was ich tat, also habe ich Code ausprobiert, der "Umformung" verwendet.
Es implementiert tatsächlich den Inferenzprozess des neuronalen Netzwerks unter Verwendung der trainierten Parameter. Ich benötige ein "sample_weight.pkl", in dem die gelernten Parameter gespeichert sind, daher das GitHub-Repository dieses Buches [https://github.com/oreilly-japan/deep-learning-from-scratch](https: // github). Lassen Sie uns die Dateien im Ordner ch3
von com / oreilly-japan / deep-learning-from-Grund) in das aktuelle Verzeichnis bringen.
Als ich mit der Implementierung gemäß dem Buch fortfuhr, stieß ich auf eine Überlaufwarnung.
/Users/segavvy/Documents/deep-learning-from-scratch/ch03/3.6_mnist.py:19: RuntimeWarning: overflow encountered in exp
return 1 / (1 + np.exp(-x))
Lesen Sie hierzu die Erläuterung zu Maschinelles Lernen mit Python treffen >> Logistische Regression >> Sigmoid-Funktion und legen Sie den Wert von x fest. Ich habe versucht, das Problem zu beheben, damit es nicht überläuft.
Bei der Berechnung der endgültigen Erkennungsgenauigkeit wird im Buch "Genauigkeit_cnt" in "Float" typkonvertiert. In Python3 gibt die Division zwischen Ganzzahlen jedoch einen Gleitkomma zurück, sodass diese Konvertierung unnötig erscheint.
Während ich es implementierte, fragte ich mich, welche Art von Bild ich nicht gut ableiten konnte, also versuchte ich es anzuzeigen.
Unten ist der Code, den ich geschrieben habe.
# coding: utf-8
import numpy as np
import os
import pickle
import sys
sys.path.append(os.pardir) #Fügen Sie dem Pfad das übergeordnete Verzeichnis hinzu
from dataset.mnist import load_mnist
from PIL import Image
def sigmoid(x):
"""Sigmaid-Funktion
Da es bei der Implementierung des Buches überläuft, wird es unter Bezugnahme auf die folgende Site korrigiert.
http://www.kamishima.net/mlmpyja/lr/sigmoid.html
Args:
x (numpy.ndarray):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
#Korrigieren Sie x in einem Bereich, der nicht überläuft
sigmoid_range = 34.538776394910684
x2 = np.maximum(np.minimum(x, sigmoid_range), -sigmoid_range)
#Sigmaid-Funktion
return 1 / (1 + np.exp(-x2))
def softmax(x):
"""Softmax-Funktion
Args:
x (numpy.ndarray):Eingang
Returns:
numpy.ndarray:Ausgabe
"""
#Für die Stapelverarbeitung ist x(Anzahl der Chargen, 10)Es wird eine zweidimensionale Anordnung von.
#In diesem Fall ist es erforderlich, für jedes Bild, das gesendet wird, eine gute Berechnung durchzuführen.
if x.ndim == 2:
#Für jedes Bild (Achse=1) Berechnen Sie den Maximalwert und formen Sie ihn neu, damit er gesendet werden kann
c = np.max(x, axis=1).reshape(x.shape[0], 1)
#Berechnen Sie das Molekül, während Sie den Maximalwert als Überlauf-Gegenmaßnahme abziehen
exp_a = np.exp(x - c)
#Der Nenner gilt auch für jedes Bild (Achse)=Umformen, so dass es zu 1) summiert und gesendet werden kann
sum_exp_a = np.sum(exp_a, axis=1).reshape(x.shape[0], 1)
#Berechnet für jedes Bild
y = exp_a / sum_exp_a
else:
#Wenn es sich nicht um eine Stapelverarbeitung handelt, implementieren Sie sie gemäß dem Buch
c = np.max(x)
exp_a = np.exp(x - c) #Überlaufmaßnahmen
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
def load_test_data():
"""MNIST-Testbild- und Testetikettenerfassung
Der Bildwert ist 0.0〜1.Normalisiert auf 0.
Returns:
numpy.ndarray, numpy.ndarray:Testbild,Testetikett
"""
(x_train, t_train), (x_test, t_test) \
= load_mnist(flatten=True, normalize=True)
return x_test, t_test
def load_sapmle_network():
"""Holen Sie sich Probe trainierte Gewichtsparameter
Returns:
dict:Gewichts- und Bias-Parameter
"""
with open("sample_weight.pkl", "rb") as f:
network = pickle.load(f)
return network
def predict(network, x):
"""Inferenz durch neuronales Netzwerk
Args:
network (dict):Gewichts- und Bias-Parameter
x (numpy.ndarray):Eingabe in das neuronale Netzwerk
Returns:
numpy.ndarray:Neuronale Netzwerkausgabe
"""
#Parameterabruf
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
#Berechnung des neuronalen Netzes (vorwärts)
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, W3) + b3
y = softmax(a3)
return y
def show_image(img):
"""Bildschirm
Args:
image (numpy.ndarray):Bild-Bitmap
"""
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
#MNIST-Testdaten lesen
x, t = load_test_data()
#Laden Sie die Parameter für das Probengewicht
network = load_sapmle_network()
#Inferenz, Berechnung der Erkennungsgenauigkeit
batch_size = 100 #Stapelverarbeitungseinheit
accuracy_cnt = 0 #Die Anzahl der richtigen Antworten
error_image = None #Nicht erkanntes Bild
for i in range(0, len(x), batch_size):
#Chargendatenaufbereitung
x_batch = x[i:i + batch_size]
#Inferenz
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
#Richtige Antwortanzahl
accuracy_cnt += np.sum(p == t[i:i + batch_size])
#Fehler beim nicht erkannten Bild_Mit Bild verbinden
for j in range(0, batch_size):
if p[j] != t[i + j]:
if error_image is None:
error_image = x_batch[j]
else:
error_image = np.concatenate((error_image, x_batch[j]), axis=0)
print("Erkennungsgenauigkeit:" + str(accuracy_cnt / len(x)))
#Nicht erkannte Bilder anzeigen
error_image *= 255 #Der Bildwert ist 0.0〜1.Da es auf 0 normalisiert ist, setzen Sie es auf 0 bis 255 zurück, damit es angezeigt werden kann.
show_image(error_image.reshape(28 * (len(x) - accuracy_cnt), 28))
Und das Ausführungsergebnis.
Erkennungsgenauigkeit:0.9352
Da die fehlgeschlagenen ~~ 793 ~~ 648 Bilder einfach vertikal verbunden sind, wird ein lächerlich langes Bild angezeigt, aber es gibt sicherlich viele Zeichen, die schwer zu verstehen sind. Es gibt jedoch einige Zeichen, die erkannt werden können.
~~ Das Buch sagt auch, dass die Erkennungsgenauigkeit "0,9352" sein wird, aber aus irgendeinem Grund ist sie "0,9207" geworden. Selbst wenn ich die Sigmoid-Funktion in den Zustand zurückversetzt habe, in dem die Warnung ausgegeben wurde, hat sie sich nicht geändert, sodass möglicherweise ein anderer Fehler vorliegt ... ~~
~~ Kapitel 3 hatte auch viel Kritik für mich, so dass ich keinen großen Stolperstein gemacht habe, aber ich mache mir Sorgen über den Unterschied in der Erkennungsgenauigkeit am Ende. ~~ Ich hatte nicht vor, über Kapitel 3 zu stolpern, aber ich bemerkte die folgenden zwei Punkte später.
Wie @tunnel betonte, fand ich heraus, warum sich die Erkennungsgenauigkeit vom Buch unterschied! Ursprünglich war es notwendig, die auf 0,0 bis 1,0 normierten Bilddatenwerte zu verwenden, aber diejenigen, die 0 bis 255 blieben, wurden verwendet. Danke @tunnel! Auch wenn die Werte bisher unterschiedlich sind, ist die Erkennungsgenauigkeit wahrscheinlich beeinträchtigt, aber es ist interessant, dass sie nicht so schlecht geworden ist.
Selbst wenn ich aus irgendeinem Grund in Kapitel 4 erfahren habe, wurde die Verlustfunktion nicht klein, und als ich die Ursache untersuchte, bemerkte ich, dass die Softmax-Funktion die Stapelverarbeitung nicht unterstützen konnte. Der obige Code wurde behoben. (Ich war froh, wenn dies in Kapitel 3 etwas näher erläutert wurde ...)
(Zu anderen Kapiteln dieses Memos: Kapitel 1 / Kapitel 2 / 3 Kapitel / Kapitel 4 / Kapitel 5 / [Kapitel 6](https: / /qiita.com/segavvy/items/ca4ac4c9ee1a126bff41) / Kapitel 7 / Kapitel 8 / Zusammenfassung)
[^ 1]: Dies ist eine Vorlesung Maschinelles Lernen, die von der Stanford University im Online-Kursdienst Coursera angeboten wird. Freiwillige fügten japanische Untertitel hinzu, und selbst wenn ich nicht gut Englisch konnte, war es ziemlich gut. Die Technik, Array-Berechnungen durch Matrixberechnungen zu ersetzen, wird unter dem Namen Vectorization beschrieben. [^ 2]: Ich habe es verwendet, als ich Problem 73 von Kapitel 8 von 100 Language Processing Knock 2015 gelöst habe. Lernen Sie zu diesem Zeitpunkt Notizen [100 Amateur-Sprachverarbeitungsklopfen: 73](https://qiita.com/segavvy/items/5ad0d5742a674bdf56cc#%E3%83%99%E3%82%AF%E3%83%88% Gepostet als E3% 83% AB% E5% 8C% 96).
Recommended Posts