[PYTHON] Erkennung handgeschriebener Zahlen durch ein mehrschichtiges neuronales Netzwerk

1. 1. Was ist Erkennung durch künstliche Intelligenz?

In den letzten Jahren hat das Gebiet der künstlichen Intelligenz bemerkenswerte Fortschritte gemacht. Ein Algorithmus, der als neuronales Netzwerk bezeichnet wird, wird im Allgemeinen verwendet, um Dinge durch künstliche Intelligenz zu erkennen und zu beurteilen. Dies ist ein Versuch, die Funktionsweise des menschlichen Gehirns nachzuahmen, da es automatisch aus einem technischen Ansatz lernt. Lassen Sie diesmal den Computer die handgeschriebenen Zahlen erkennen, damit der Mensch sie auf natürliche Weise erkennen kann.

2. Bilderkennung durch neuronales Netzwerk

Ein neuronales Netzwerk ist ein Lernmodell, das den Nerv des menschlichen Gehirns nachahmt. Durch die Durchführung einer großen Anzahl nichtlinearer Transformationen ist dies ein Ersatz, der aus gegebenen Daten sehr komplexe Ergebnisse liefern kann. Auf dem Gebiet der Bilderkennung kann gesagt werden, dass die Bilderkennung durch Anwenden eines Korrelationsprozesses, der als Schablonenanpassung bezeichnet wird, auf das neuronale Netz realisiert wird. (Obwohl es einige Missverständnisse geben kann, handelt es sich nur um einen Korrelationsprozess in Bezug auf die Faltung von Pixeln und die Helligkeit.)

Das diesmal zu erkennende Bild ist eine handschriftliche Nummer von MNIST.

Lassen Sie uns herunterladen. Da es sich nicht um Bilddaten handelt, können diese nach dem Herunterladen so verwendet werden, wie sie sind Konvertieren wir es in Bilddaten, indem wir auf die folgenden Dokumente auf der offiziellen Website verweisen.


TRAINING SET LABEL FILE (train-labels-idx1-ubyte):

[offset] [type] [value] [description] 0000 32 bit integer 0x00000801(2049) magic number (MSB first) 0004 32 bit integer 60000 number of items 0008 unsigned byte ?? label 0009 unsigned byte ?? label ........ xxxx unsigned byte ?? label The labels values are 0 to 9.

TRAINING SET IMAGE FILE (train-images-idx3-ubyte):

[offset] [type] [value] [description] 0000 32 bit integer 0x00000803(2051) magic number 0004 32 bit integer 60000 number of images 0008 32 bit integer 28 number of rows 0012 32 bit integer 28 number of columns 0016 unsigned byte ?? pixel 0017 unsigned byte ?? pixel ........ xxxx unsigned byte ?? pixel Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).


Sie können sehen, dass das Lehrersignal nach dem Versatz 8 und die Trainingsdaten nach dem Versatz 16 gespeichert werden. Wenn Sie es daher als Binärdatei öffnen und die Byte-Zeichenfolge für jeden Pixelwert (28 * 28) extrahieren, können Sie die Bilddatei abrufen. Durch ordnungsgemäße Binärisierung können Sie die folgenden Bilddaten handgeschriebener Zahlen für 60000-Daten erhalten. image_0_1.png image_1_3.png image_2_5.png Wir werden diese Plus-Testdaten beim Training des neuronalen Netzes verwenden.

3. 3. Mehrschichtiges neuronales Netzwerkmodell

Das Modell des diesmal verwendeten neuronalen Netzes wird durch die folgenden Anforderungen definiert.

Es ist ein einfaches und extrem neuronales Netzwerk, aber ist es der Punkt, dass es zwei versteckte Schichten verwendet? Es gibt viele Dinge, die verbessert werden müssen, aber lassen Sie uns dies zunächst in die Praxis umsetzen.

Die Code-Implementierung ist unten dargestellt.

MultiLayerPerceptron_MNIST.py


# 1. Preprocess
import random
# 1.1. Make NeuralLetwork
# 1.1.1. Define Layers
n_hidden = 2
n_layer = n_hidden + 2

# 1.1.2. Define Units
n_unit_i = 7 * 7 + 1
n_unit_h = 20 # all 
n_unit_o = 10

unit_i = [0 for u in range(n_unit_i)]
unit_h1 = [0 for u in range(n_unit_h)]
unit_h2 = [0 for u in range(n_unit_h)]
unit_o = [0 for u in range(n_unit_o)]

# 1.1.3. Initialize weight
w1 = [[random.uniform(-1, 1) for u_before in range(n_unit_i)] for u_after in range(n_unit_h)]
w2 = [[random.uniform(-1, 1) for u_before in range(n_unit_h)] for u_after in range(n_unit_h)]
w3 = [[random.uniform(-1, 1) for u_before in range(n_unit_h)] for u_after in range(n_unit_o)]

# 1.2. Define dataset

import mydatasets

n_data = 100
ipt = mydatasets.inputdata("digit")
res = ipt.load_data2(size=(7, 7), num=n_data)

train = res[0][0]
for k in train:
    for n in k:
        n.insert(0, 1)

def maketeach(kind):
    buf = []
    for o in range(n_unit_o):
        if o == kind:
            buf.append(1) 
        else:
            buf.append(0)
    return buf
    
# 1.3 Implement forward propagation
import math

# 1.3.1 Define activation fucntion
def sigmoid(z):
    if z > 10: return 0.99999
    elif z < -10: return 0.00001
    else: return 1 / (1 + math.exp(-1 * z))
    
# 1.3.2 forward propagation

def forward(train_vec):
    
    for i in range(n_unit_i):
        unit_i[i] = train_vec[i]
    unit_i[0] = 1
        
    # 1.3.2.1 forward between input-hidden1
    for h1 in range(n_unit_h):
        buf = 0
        for i in range(n_unit_i):
            buf += unit_i[i] * w1[h1][i]
        unit_h1[h1] = sigmoid(buf)
    unit_h1[0] = 1
        
    # 1.3.2.2 forward between hidden1-hidden2
    for h2 in range(n_unit_h):
        buf = 0
        for h1 in range(n_unit_h):
            buf += unit_h1[h1] * w2[h2][h1]
        unit_h2[h2] = sigmoid(buf)
    unit_h2[0] = 1

    # 1.3.2.3 forward between hidden2-output
    for o in range(n_unit_o):
        buf = 0
        for h2 in range(n_unit_h):
            buf += unit_h2[h2] * w3[o][h2]
        unit_o[o] = sigmoid(buf)

# 1.3.3 back propagation

alpha = 0.1
def backpropagation(teach_vec):
    
    # 1.3.3.1 get cost
    buf = 0
    for o in range(n_unit_o):
        buf += (teach_vec[o] - unit_o[o]) ** 2
    cost = buf / 2
    
    # 1.3.3.2 get grad between hidden2-output
    for o in range(n_unit_o):
        for h2 in range(n_unit_h):
            delta = (unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o]) * unit_h2[h2]
            w3[o][h2] -= alpha * delta
            
    # 1.3.3.3 get grad
    for o in range(n_unit_o):
        for h2 in range(n_unit_h):
            for h1 in range(n_unit_h):
                delta = ((unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o])
                         * w3[o][h2] * unit_h2[h2] * (1 - unit_h2[h2]) * unit_h1[h1])
                w2[h2][h1] -= alpha * delta
                
    # 1.3.3.4 get grad
    for o in range(n_unit_o):
        for h2 in range(n_unit_h):
            for h1 in range(n_unit_h):
                for i in range(n_unit_i):
                    delta = ((unit_o[o] - teach_vec[o]) * unit_o[o] * (1 - unit_o[o])
                             * w3[o][h2] * unit_h2[h2] * (1 - unit_h2[h2])
                             * w2[h2][h1] * unit_h1[h1] * (1 -unit_h1[h1]) * unit_i[i])
                    w1[h1][i] -= alpha *delta
                    
    return cost
    
import matplotlib.pyplot as plt
plt_x = []
plt_y = []

n_epoch = 30
n_train = len(train)
n_kind = 10
n = 0
error_threshold = 0.001

print("Backpropagation training is started now.")

def training(n):
    for e in range(n_epoch):
        for d in range(n_data):
            for k in range(n_kind):
                try:
                    n += 1
                    forward(train[k][d])
                    c = backpropagation(maketeach(k))
                    plt_x.append(n)
                    plt_y.append(c)
                    if n % 100 == 0:
                        print("learn num: {0}".format(n))
                    if c < error_threshold and e > n_epoch // 2:
                        print("cost is least than error threshold. (n: {})".format(n))
                        return 1
                except Exception as e:
                    print("n:{}, d:{}, k{}, Error:{}".format(n, d, k, e.args))
                    pass
    return 0

def forecast(train_data, dim):
    forward(train_data)
    res = unit_o
    n = 0
    for r in res:
        if r == max(res):
            max_score = n
        n += 1
    print("max score : {}".format(max_score))
    print("scores is below : ")
    print(res)
    
    import numpy as np
    import cv2
    mat = []
    row = []
    cnt = 0
    n = 0
    for t in range(1, len(train_data)):
        row.append(train_data[t])
        cnt += 1
        n += 1
        if cnt == 7:
            #print("if statement is called at n:{}".format(n))
            mat.append(row)
            row = []
            cnt = 0
    cv2.imwrite('forecast_input.png', np.array(mat)*255)
    
    return max_score
    
def validation(vaild_sets):
    n_dim = 7
    correct = 0
    incorrect = 0
    n_kind = 10
    for d in range(n_data):
        for k in range(n_kind):
            if forecast(train[k][d], n_dim) == k:
                correct += 1
            else:
                incorrect += 1
    total = correct + incorrect
    print("validation result:: correct answer is {} / {}".format(correct, total))

training(n)
plt.plot(plt_x, plt_y)
plt.xlim(0, 30000)
plt.ylim(0.0, 1.51)
plt.show()

valid = res[1][0]
for k in valid:
    for n in k:
        n.insert(0, 1)
        
validation(valid)

4. Ausführungsergebnis

Unter Verwendung der Anzahl der Lernfehlergraphen wurden die folgenden Ergebnisse erhalten.

result_MLP_MNIST.png

Zu Beginn kann das neuronale Netz nicht zwischen 0 (richtige Antwort) und 1 (falsche Antwort) unterscheiden und trifft eine halbfertige Beurteilung von 0,5. Wenn Sie lernen, können Sie immer mehr unterscheiden. Wenn das Ergebnis korrekt ist, können Sie ein Urteil nahe 0 fällen. Wenn das Ergebnis falsch ist, können Sie ein Urteil nahe 1 fällen.

Dies ist das Ergebnis der Verwendung von Sigmoid für die Ausgabeaktivierungsfunktion. Sigmoid bewirkt eine Normalisierung des Wertes im Bereich von 0 bis 1, was den Erfolg oder Misserfolg der Erkennung in Form einer Wahrscheinlichkeit anzeigt.

Als Ergebnis der Validierung betrug die Erkennungsrate handgeschriebener Zahlen 84,7%. Wenn Sie mit dem oben genannten primitiven Algorithmus ein solches Ergebnis erzielen können, können Sie sagen, dass es Ihnen vorerst gelungen ist, handgeschriebene Zahlen zu erkennen.

4.5. Nachtrag zum Ausführungsergebnis (16/06/06)

Ich wurde darauf hingewiesen, dass die Bedeutung des Ausführungsergebnisses schwer zu lesen ist, daher werde ich eine Erklärung hinzufügen.

Lassen Sie uns zunächst den Bereich der Ausführungsergebnisse verfeinern.

ダウンロード (2).png

Die obige Abbildung zeigt die Fehlerrate bis zum Versuch 29970 ... 30000. Sie können die Periodizität in diesem Diagramm sehen. Die Periodizität für jeden Zifferntyp (0 ... 9), z. B. niedriger Fehler, wenn die Einerstelle 0 oder 1 ist, und hoher Fehler, wenn die Einerstelle 9 ist.

Diese Vibration ist auf den Lernalgorithmus zurückzuführen. In dem diesmal verwendeten Algorithmus wird Shioume, wie das Lernen von 1 nach dem Lernen von 0, dazu gebracht, jedes Mal die folgenden Arten von Zahlen zu lernen. Daher schwankt die Fehlerrate in Abhängigkeit von der Anzahl der Versuche stark. Es gibt keine direkte Verbindung zu aufeinanderfolgenden Versuchen, sondern zu Versuchen, die auf 10 basieren. Sie lernen die Erkennung von 0, indem Sie 0 → 10 → 20 → 30 versuchen, und lernen die Erkennung von 1, indem Sie 1 → 11 → 21 versuchen.

Die durchschnittliche Erkennungsrate ist je nach Anzahl unterschiedlich. Irgendwann erkennen einige Modelle 0 möglicherweise gut und 9 möglicherweise nicht. Deshalb variieren die Wahrnehmungen und scheinen zu vibrieren.

Und während das Lernen fortschreitet, lernt das Modell einen sogenannten "idealen Wert". Die Fehlerrate erhöht sich ebenfalls. Dies liegt daran, dass beim Festigen des Idealwerts der Grad der Abweichung des Eingabewerts deutlicher wird als im neutralen Zustand. Schauen wir uns ein Beispiel für den Idealwert und den Grad der Abweichung an.

output_and_error.jpg

Die obige Abbildung zeigt das Ergebnis der Eingabe eines Teils des 0-Validierungssatzes und dessen Fehlerrate. Die Fehlerrate ist der letzte Teil des Unterstrichs im Dateinamen vor der Erweiterung. Die Indexnummer des Bildes liegt vor der Fehlerrate. In diesem Bild zeigt das 93. Eingabebild die höchste Fehlerrate (0,4708). Das Modell erfuhr, dass es schwer zu erkennen war, dass es 0 war, als ich diese stumpfe Form sah. Im obigen Bild hat Nr. 98 auch die niedrigste Fehlerrate, so dass auch gelernt wird, dass 0 nach rechts geneigt der idealen Form von 0 am nächsten kommt.

5. Fazit

Diesmal habe ich eine einfache Implementierung eines neuronalen Netzes gezeigt. Mit dem aktuellen Algorithmus gibt es jedoch immer noch Unzufriedenheiten hinsichtlich der Anzahl der Schulungen und Fehler. Nächstes Mal werde ich diese Unzufriedenheit mit mehreren Ansätzen lösen.

Recommended Posts

Erkennung handgeschriebener Zahlen durch ein mehrschichtiges neuronales Netzwerk
Überprüfung der Chargennormalisierung mit einem mehrschichtigen neuronalen Netz
Aufbau eines neuronalen Netzwerks, das XOR durch Z3 reproduziert
Implementierung eines zweischichtigen neuronalen Netzwerks 2
Untersuchung des wiederkehrenden neuronalen Netzes (RNN) durch Chainer ~ Überprüfung der Genauigkeit von Zufallszahlen in Excel und R ~
Erstellen Sie mithilfe des TensorFlow-Faltungsnetzwerks einen Klassifikator mit einer Handschrifterkennungsrate von 99,2%
Implementierung eines 3-Schicht-Neuronalen Netzwerks (kein Lernen)
Implementierung von "verschwommenen" neuronalen Netzen mit Chainer
[Chainer] Dokumentklassifizierung nach Faltungsnetzwerk
Visualisieren Sie die innere Schicht des neuronalen Netzwerks
Parametrisches neuronales Netzwerk
Übersicht über DNC (Differentiable Neural Computers) + Implementierung durch Chainer
Bayesianische Optimierungsimplementierung von Hyperparametern des neuronalen Netzwerks (Chainer + GPyOpt)
Grundlagen von PyTorch (2) - Wie erstelle ich ein neuronales Netzwerk?
Implementierung eines Faltungs-Neuronalen Netzwerks mit nur Numpy
Ich habe ein Convolutional Neural Network (CNN) mit einem TensorFlow-Tutorial zur Cloud9-Klassifizierung handgeschriebener Bilder ausprobiert.