Datenanalyse

Neuronales Netz: Erkennung von handgeschriebenen Ziffern

 aufwärts

Als Anwendung eines neuronalen Netzes ist im Folgenden die Erkennung von handgeschriebenen Ziffern beschrieben. Das Programm ist in der Programmiersprache Python als jupyter-Notebook implementiert.

Handgeschriebene Ziffern

Eine Standardanwendung für ein neuronales Netz ist die Erkennung von handgeschriebenen Ziffern. Die Datei mnist_train.csv enthält die Daten von 60.000 gescannten handgeschriebenen Ziffern. Mit diesen Daten wird das neuronale Netz zunächst trainiert. Anschließend wird das neuronale Netz mit weiteren 10.000 handgeschriebenen Ziffern, die sich in der Datei mnist_test.csv befinden, getestet.

Jede der beiden CSV-Dateien enhält eine Tabelle. Jede Zeile der Tabelle besteht aus 785 Zahlenwerten, dabei gibt der erste Wert die Ziffer an, die dargestellt ist, und die restlichen 784 Zahlenwerte stellen Graustufen eines 28×28-Pixel-Bildes dar, das die handgeschriebene Ziffer zeigt. Als Beispiel ist in Bild 1 eine handgeschriebene Ziffer 6 zu sehen.

Bild 1: Handgeschriebene Ziffer 6 als 28×28-Pixel-Bild
Bild 1: Handgeschriebene Ziffer 6 als 28×28-Pixel-Bild

Die Daten entstammen der öffentlich zugänglichen MNIST-Datensammlung (http://yann.lecun.com/exdb/mnist/).

Eingabedaten aufbereiten

Die Trainingsdaten, die sich in der CSV-Datei mnist_train.csv befinden, werden zunächst mit folgender Funktion eingelesen.

def readInput(filename):
    datafile=open(filename, 'r')
    datalist=datafile.readlines()
    datafile.close()
    return datalist

Das Array datalist besteht aus 60.000 Strings, die jeweils Zeilen von durch Kommas getrennten Werten darstellen. Mit einer Funktion prepareInput werden die Daten für die weitere Verwendung aufbereitet.

Jede der durch Kommas unterteilten Zeilen wird im ersten Schritt in ein Array umgewandelt. Die Array-Einträge sind aber noch Strings, daher werden diese als nächstes in Zahlen umgewandelt. Dann wird die erste Zahl abgetrennt, diese entspricht dem Wert der dargestellten Ziffer, und in der Variablen d gespeichert. Die restlichen Zahlen werden um 128 vermindert, sodass sie in den Bereich {-128., ..., +127} fallen. Das Ergebnis ist der spätere Eingabevektor x, auf den in der Eingabeschicht ja die Funktion σ angewandt wird. So wird erreicht, dass der Wertebereich von σ ausgeschöpft wird.

Der Zielvektor y wird folgendermaßen gebildet. Zunächst wird Vektor mit zehn gleichen Werten von 0.1 erzeugt. In diesem Vektor wird an Indexposition d der Wert in 0.9 geändert. Das neuronale Netz soll später so trainiert werden, dass bei Eingabe einer handgeschriebenen Ziffer d das Neuron an Indexposition d der Ausgabeschicht einen hohen Wert liefert und alle anderen Neuronen der Ausgabeschicht einen niedrigen Wert. Die Ausgabewerte des neuronalen Netzes liegen stets zwischen 0 und 1, da sie als Fiúnktionswerte der Funktion σ zustande kommen.

Eingabevektor und zugehöriger Zielvektor werden miteinander verkettet, und alle so aufbereiteten Zeilen werden zum Schluss zu einer zweidimensionalen Liste r zusammengefügt.

 

def prepareInput(datalist):
    r=[]
    for z in datalist:
        v=z.split(',')
        x=[int(s) for s in v]
        d=x[0]
        x=[t-128 for t in x[1:]]
        y=[0.1]*10
        y[d]=0.9
        r+=[y+x]
    return r

In entsprechender Weise werden auch die Testdaten aus der Datei mnist_test.csv eingelesen und aufbereitet.

Programm

Es folgt das fertige Programm. Es beginnt mit den Definitionen der Funktionen readInput und prepareInput. Dann kommt die Definition der Funktion sigma. Die Definitionen der eigentlichen Funktionen des neuronalen Netzes, nämlich propagate, backpropagate, train und test schließen sich an.

Im Hauptprogramm wird zunächst das neuronale Netz definiert, indem pro Schicht die Anzahl der Neuronen angegeben wird. Hier etwa wird ein neuronales Netz mit drei Schichten definiert, wobei die Eingabeschicht 28 · 28 = 784 Neuronen umfasst, die innere Schicht 100 Neuronen und die Ausgabeschicht 10 Neuronen. Alternativ, hier im Programmtext auskommentiert, wird ein neuronales Netz mit vier Schichten definiert.

Überraschenderweise hat die Initialisierung der Gewichtungsmatrizen erheblichen Einfluss auf die Erkennungsrate des neuronalen Netzes. Hier ist eine Initialisierung gewählt, die normalverteilte Zufallswerte enthält.

Für die im Verlauf der Berechnung erforderlichen Vektoren werden zunächst Platzhalter erzeugt, sodass später per Indizierung darauf zugegriffen werden kann (zum Beispiel muss e[0] vorhanden sein, wenn ihm ein Wert zugewiesen wird).

Es folgt dann das Programmstück zum Trainieren und Testen des neuronalen Netzes. Die 60.000 Trainingsdatensätze werden mehrfach in sogenannten Epochen in das Netz eingegeben, um es zu trainieren. Im Anschluss daran wird mit den 10.000 Testdatensätzen jeweils die erzielte Erkennungsrate bestimmt.

 

import numpy as np

# Daten aus Datei einlesen
def readInput(filename):
    datafile=open(filename, 'r')
    datalist=datafile.readlines()
    datafile.close()
    return datalist

# Daten für die weitere Verwendung aufbereiten
def prepareInput(datalist):
    r=[]
    for z in datalist:
        v=z.split(',')
        x=[int(s) for s in v]
        d=x[0]
        x=[t-128 for t in x[1:]]
        y=[0.1]*10
        y[d]=0.9
        r+=[y+x]
    return r

# Aktivierungsfunktion
def sigma(x):
    return 1.0/(1+np.exp(-x))

# Eingabevektor x durch das neuronale Netz schicken
def propagate(x):
    e[0]=np.array(x).reshape(1,m[0])  # 1 x m[0]-Matrix
    s[0]=sigma(e[0])
    for r in range(1, n):
        e[r]=np.matmul(s[r-1], w[r-1])
        s[r]=sigma(e[r])

# Zielvektor y durch das neuronale Netz zurückverbreiten
# und dabei die Gewichtungen anpassen
def backpropagate(y):
    y=np.array(y).reshape(1, m[n-1])  # 1 x m[n-1]-Matrix
    r=n-1
    f[r]=s[r] - y
    h[r]=f[r]*s[r]*(1-s[r])
    # Fehler zurückpropagieren
    for r in range(n-2, 0, -1):
        f[r]=np.matmul(h[r+1], w[r].T)
        h[r]=f[r]*s[r]*(1-s[r])
    # Gewichte anpassen
    for r in range(n-1, 0, -1):
        w[r-1] -= np.matmul(s[r-1].T, alpha*h[r])

# das neuronale Netz mit den Trainingsdaten trainieren
def train():
    for z in traindata:
        x=z[10:]
        propagate(x)
        y=z[:10]
        backpropagate(y)

# das neuronale Netz mit den Testdaten testen
# und die Erkennungsrate bestimmen
def test():
    cnt=0
    for z in testdata:
        x=z[10:]
        propagate(x)
        y=z[:10]
        p=np.argmax(y)
        q=np.argmax(s[n-1][0])  # [0] weil 1 x m_n-1-Matrix
        if p==q:
            cnt+=1
    return 100.0*cnt/len(testdata)  # Prozent richtig erkannt
       
# Neuronales Netz definieren
# Anzahl der Neuronen pro Schicht
m=[28*28,200,10]
#m=[28*28,300,80,10]
n=len(m)    # Anzahl der Schichten
# Liste mit Gewichtungsmatrizen:
w=[np.random.normal(0.0, pow(m[r-1], -0.5), (m[r-1], m[r])) for r in range(1,n)]
e=[0]*n  # Platzhalter für Eingabevektoren
s=[0]*n  # Platzhalter für Ausgabevektoren
f=[0]*n  # Platzhalter für Fehlervektoren
h=[0]*n  # Platzhalter für Fehlervektoren

# Trainingsdaten einlesen
traindata=prepareInput(readInput("mnist_train.csv"))
# Testdaten einlesen
testdata=prepareInput(readInput("mnist_test.csv"))

# Mehrere Epochen mit jeweils 60.000 Trainingsdatensätzen und
# anschließendem Test mit 10.000 Testdatensätzen durchlaufen,
# nach und nach die Lernrate verringern
epochs=6
for i in range(epochs):
    alpha=0.1*(epochs-i)  # Lernrate nach und nach verringern
    train()
    print("Training zu Ende")
    p=test()
    print('Erkennung: '+str(p)+ " %")

Der Programmtext steht in Form eines jupyter-Notebooks unter MultilayerNeuralNetwork-HandwrittenNumbers.ipynb zum Herunterladen zur Verfügung. Zusätzlich erforderlich sind die Dateien mnist_train.csv und mnist_test.csv.

Probieren Sie das Programm mit unterschiedlichen neuronalen Netzen mit unterschiedlicher Anzahl von Schichten und Anzahl von Neuronen in den inneren Schichten aus. Die Anzahl der Neuronen in der Eingabeschicht liegt fest, sie beträgt 28 · 28 = 784 entsprechend der Anzahl der Pixel der Eingabebilder. Die Anzahl der Neuronen der Ausgabeschicht liegt ebenfalls fest, sie beträgt 10 entsprechend der Anzahl der zu erkennenden unterschiedlichen Ziffern 0, ..., 9.

Leistungsfähigkeit

Das hier angegebene neuronale Netz erzielt nach der sechsten Trainingsepoche eine Erkennungsrate von über 97 %. Tatsächlich wäre eine Erkennungsrate von 100 % auch gar nicht unbedingt sinnvoll, da manche Ziffer so unsauber geschrieben ist, dass eine Zuordnung zu einem "richtigen" Wert rein willkürlich wäre.

 

Weiter mit:   up

 

homeH.W. Lang   Hochschule Flensburg   lang@hs-flensburg.de   Impressum   Datenschutz   ©   Created: 04.01.2021   Updated: 29.01.2021
Valid HTML 4.01 Transitional

Hochschule Flensburg
Campus Flensburg

Informatik in Flensburg studieren...

 

Neu gestaltetes Studienangebot:

Bachelor-Studiengang
Angewandte Informatik

mit Schwerpunkten auf den Themen Software, Web, Mobile, Security und Usability.

Ihr Abschluss
nach 7 Semestern:
Bachelor of Science

 

 

 

Master-Studiengang
Angewandte Informatik

Ein projektorientiertes Studium auf höchstem Niveau mit den Schwerpunkten Internet-Sicherheit, Mobile Computing und Human-Computer Interaction.

Ihr Abschluss
nach 3 Semestern:
Master of Science

 

Weitere Informatik-Studienangebote an der Hochschule Flensburg:

Medieninformatik

Wirtschaftsinformatik