[PYTHON] Lerne Zundokokiyoshi mit einem einfachen RNN

Es gibt bereits eine Person, die Zundokokiyoshi mithilfe von LSTM implementiert, aber ich denke, dass Sie auf dieser Ebene nur mit einem einfachen RNN lernen können sollten. Ich habe versucht, es mit Chainer zu implementieren, um RNN zu verstehen.

Gemäß 7.5 des Buches "Deep Learning (Machine Learning Professional Series)" (ISBN-13: 978-4061529021) erinnert sich RNN Sie können es für die letzten 10 Stunden tun. Sie müssen sich nur an das Muster erinnern, in dem "Zun" viermal und "Doko" einmal vorkommt, daher sollte es innerhalb dieses Bereichs liegen.

Denkweise

Ich dachte an eine möglichst einfache Struktur. Geben Sie zwei ein ($ x_1, x_2 ). Es hat eine Zwischenschicht und die Anzahl der Einheiten beträgt 10. Es gibt auch zwei Ausgänge ( y_1, y_2 $). Die Eingabe ist wie folgt definiert.

Mist → x_0 = 0, x_1 = 1 \\
Doco → x_0 = 1, x_1 = 0

Die Ausgabe ist wie folgt definiert: Angenommen, es ist ein einfaches Klassifizierungsproblem.

Kiyoshi ist fehlgeschlagen → y_0 = 1, y_1 = 0 \\
Kiyoshi gründete → y_0 = 0, y_1 = 1

Modelldefinition

Die Code-Definition lautet wie folgt.

import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, Variable, optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L

class RNN(chainer.Chain):
    def __init__(self):
        super(RNN, self).__init__(
            w1 = L.Linear(2, 10),
            h1 = L.Linear(10, 10),
            o = L.Linear(10, 2)
            )
    def reset_state(self):
        self.last_z = chainer.Variable(np.zeros((1,10), dtype=np.float32))
    def __call__(self, x):
        z = F.relu(self.w1(x) + self.h1(self.last_z))
        self.last_z = z
        y = F.relu(self.o(z))
        return y

rnn = RNN()
rnn.reset_state()
model = L.Classifier(rnn)
optimizer = optimizers.Adam() #Benutze Adam
optimizer.setup(model)
optimizer.add_hook(chainer.optimizer.GradientClipping(10.0)) #Stellen Sie die Obergrenze des Verlaufs ein

Unter der Annahme einer Mini-Charge mit einer festen Größe von 1 ist der Anfangswert (last_z) Null. Während der in self.last_z berechnete Wert der verborgenen Ebene beibehalten wird, wird das Ergebnis an die Ausgabeebene übergeben.

Lernen

Generieren Sie mäßig zufällige Seriendaten und trainieren Sie diese.

ans_zundoko = [0, 0, 0, 0, 1] #Richtige Antwortreihenfolge
src_x_ary = [0, 0, 0, 1] #Stellen Sie die Erscheinungsrate des Zufallszahlengenerierungsarrays 0 höher als 1 ein

def zd_gen(): #Generator
    x_ary = [0, 0, 0, 0, 1]
    y_ary = [0, 0, 0, 0, 1]
    while True:
        x = x_ary.pop(0)
        y = y_ary.pop(0)
        x = [0, 1] if x == 0 else [1, 0]
        yield x, y
        new_x = src_x_ary[np.random.randint(0, 4)] #0 wenn 0 bis 2,Wenn es 3 ist, ist es 1.
        x_ary.append(new_x)
        y_ary.append(1 if x_ary == ans_zundoko else 0) # x_ary ist[0, 0, 0, 0, 1]Nur wenn

bprop_len = 40 #BPPT-Abschaltzeit
iter = 300 * 100 * 2 #Anzahl des Lernens
loss = 0
i = 0
for xx, yy in zd_gen():
    x = chainer.Variable(np.asarray([xx], dtype=np.float32))
    t = chainer.Variable(np.asarray([yy], dtype=np.int32))
    loss += model(x, t)
    i += 1
    if i % bprop_len == 0:
        model.zerograds()
        loss.backward()
        loss.unchain_backward()
        optimizer.update()
        print("iter %d, loss %f, x %d, y %d" % (i, loss.data, xx[0], yy))
        loss = 0
    if i > iter:
        break

Das Lernen ist zeitaufwändig und kann abhängig von den Anfangswerten funktionieren oder auch nicht. Es wird nicht richtig funktionieren, es sei denn, der Verlust fällt schließlich unter 0,1.

Versuchen Sie, den Optimierer in SGD oder bprop_len zu ändern, und die Ergebnisse ändern sich. Der hier eingestellte Wert verwendet den Fall, der irgendwie gut zur Hand ging.

Auswertung

Bewerten Sie das trainierte Modell. Sie können die Eingabespalten zufällig generieren, aber der Einfachheit halber habe ich statische Auswertungsdaten vorbereitet.

#Mist Mist Mist Mist Mist Doko Doko Mist
x_data = [[0,1], [0,1], [0,1], [0,1], [1,0], [1,0], [1,0], [0,1]]

rnn.reset_state()
for xx in x_data:
    print('Dung' if xx[1] == 1 else 'Doco')
    x = chainer.Variable(np.asarray([xx], dtype=np.float32))
    y = model.predictor(x)
    z = F.softmax(y, use_cudnn=False)
    if z.data[0].argmax() == 1: #Kiyoshi wird eingerichtet, wenn der Array-Index mit dem größeren Wert 1 ist.
        print('Kiyoshi')

Referenzausgabe

Die Ausgabe, wenn sie gut läuft, wird als Referenz angezeigt.

iter 59520, loss 0.037670, x 1, y 0
iter 59560, loss 0.051628, x 0, y 0
iter 59600, loss 0.037519, x 0, y 0
iter 59640, loss 0.041894, x 0, y 0
iter 59680, loss 0.059143, x 0, y 0
iter 59720, loss 0.062305, x 0, y 0
iter 59760, loss 0.055293, x 0, y 0
iter 59800, loss 0.060964, x 1, y 1
iter 59840, loss 0.057446, x 1, y 0
iter 59880, loss 0.034730, x 1, y 0
iter 59920, loss 0.054435, x 0, y 0
iter 59960, loss 0.039648, x 0, y 0
iter 60000, loss 0.036578, x 0, y 0
Dung
Dung
Dung
Dung
Doco
Kiyoshi
Doco
Doco
Dung

Impressionen

Ich habe das Gefühl, dass ich endlich RNN verstehen kann, das ich nicht vollständig verdaut hatte. Anfangs war die Anzahl der Einheiten in der mittleren Schicht gering und die BPTT-Grenzzeit war zu kurz eingestellt, sodass sie überhaupt nicht funktionierte, aber nach verschiedenen Anpassungen begann sie schließlich zu funktionieren. Es gibt viele Beispiele für die Verwendung von LSTM- und Worteinbettungsausdrücken in der Welt, aber ich habe beschlossen, es mit einem minimierten Problem zu versuchen, und ich bin froh, dass ich es endlich erkannt habe.

Es ist jedoch ein Problem, dass es immer noch einen Teil gibt, der vom Glück abhängt.

Recommended Posts

Lerne Zundokokiyoshi mit einem einfachen RNN
Erstellen einer einfachen Tabelle mit Stettytable
Eine Geschichte über einfaches maschinelles Lernen mit TensorFlow
Beispiel zum Zeichnen einer einfachen Uhr mit ebiten
Lerne Zundokokiyoshi mit LSTM
Erstellen Sie eine einfache CRUD-App mit der generischen Klassenansicht von Django
Ich habe mit PyQt einen einfachen Texteditor erstellt
Lernen Sie Librosa mit einem Tutorial 1
Ein einfaches Beispiel für pivot_table.
Zeitmessung mit einer Uhr
Erstellen Sie einen (einfachen) REST-Server
# 1 [python3] Einfache Berechnung mit Variablen
Pfeffer-Tutorial (5): Verwenden eines Tablets
Verwenden eines Druckers mit Debian 10
Erstellen Sie einen einfachen Textlint-Server
Ein Memorandum zur Verwendung von eigen3
Machen Sie einen einfachen CO2-Inkubator mit Raspberry PI und CO2-Sensor (MH-Z14A)
Erstellen Sie einen einfachen geplanten Stapel mit Dockers Python Image und parse-crontab
Ich ließ RNN Sin Wave lernen und sagte es voraus: Hyper-Parameter-Anpassung
Bewerten Sie die Leistung eines einfachen Regressionsmodells mithilfe der LeaveOneOut-Schnittstellenvalidierung