[PYTHON] Deep Learning / Deep Learning von Null 2 Kapitel 6 Memo

1. Zuallererst

Ich lese ein Meisterwerk, ** "Deep Learning from Zero 2" **. Diesmal ist ein Memo von Kapitel 6. Um den Code auszuführen, laden Sie den gesamten Code von Github herunter und verwenden Sie das Jupiter-Notizbuch in Kapitel 06.

2. LSTM-Modell

Der Code für ch06 / train_rnnlm.py, der die Wortreihenfolge des PTB-Datensatzes lernt. Im einfachen RNN-Modell in Kapitel 5 haben wir nur die ersten 1000 Wörter des Trainingsdatensatzes gelernt, aber diesmal lernen wir ungefähr 900.000 Wörter für den gesamten Trainingsdatensatz.

Führen Sie mit time_size = 35, batch_size = 20, word_size = hidden_size = 100, max_eopch = 4 aus.

import sys
sys.path.append('..')
from common.optimizer import SGD
from common.trainer import RnnlmTrainer
from common.util import eval_perplexity
from dataset import ptb
from rnnlm import Rnnlm

#Hyper-Parametereinstellungen
batch_size = 20
wordvec_size = 100
hidden_size = 100  #Anzahl der Elemente im verborgenen Zustandsvektor von RNN
time_size = 35  #Die Größe für die Bereitstellung von RNN
lr = 20.0
max_epoch = 4
max_grad = 0.25

#Trainingsdaten lesen
corpus, word_to_id, id_to_word = ptb.load_data('train')
corpus_test, _, _ = ptb.load_data('test')
vocab_size = len(word_to_id)
xs = corpus[:-1]
ts = corpus[1:]

#Modellgenerierung
model = Rnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
trainer = RnnlmTrainer(model, optimizer)

#Lernen Sie, indem Sie Gradientenausschnitte anwenden
trainer.fit(xs, ts, max_epoch, batch_size, time_size, max_grad,
            eval_interval=20)
trainer.plot(ylim=(0, 500))

#Mit Testdaten auswerten
model.reset_state()
ppl_test = eval_perplexity(model, corpus_test)
print('test perplexity: ', ppl_test)

#Parameter speichern
model.save_params()

スクリーンショット 2020-05-22 19.20.28.png

Es dauerte 33 Minuten, bis mein Macbook Air fertig war. Die Ratlosigkeit nach 4 Epochen betrug 111,47 und die Ratlosigkeit gemäß den Testdaten betrug 136,3. Wenn Sie das nächste Wort vorhersagen, haben Sie 136 Möglichkeiten. Die Bedingungen sind völlig anders als in Kapitel 5, daher kann ich sie nicht vergleichen, aber sie sind größer als erwartet.

Im einfachen RNN-Modell von Kapitel 5 tritt wahrscheinlich eine Gradientenexplosion auf. Im LSTM-Modell wird daher die Trainerklasse verwendet, um dies zu unterdrücken.Gradientenausschnitt( -threshold < ||\hat{g}|| <Schwelle)Funktionen sind enthalten.   3.Rnnlm

import sys
sys.path.append('..')
from common.time_layers import *
from common.base_model import BaseModel


class Rnnlm(BaseModel):
    def __init__(self, vocab_size=10000, wordvec_size=100, hidden_size=100):
        V, D, H = vocab_size, wordvec_size, hidden_size
        rn = np.random.randn

        #Gewichtsinitialisierung
        embed_W = (rn(V, D) / 100).astype('f')
        lstm_Wx = (rn(D, 4 * H) / np.sqrt(D)).astype('f')
        lstm_Wh = (rn(H, 4 * H) / np.sqrt(H)).astype('f')
        lstm_b = np.zeros(4 * H).astype('f')
        affine_W = (rn(H, V) / np.sqrt(H)).astype('f')
        affine_b = np.zeros(V).astype('f')

        #Schichterzeugung
        self.layers = [
            TimeEmbedding(embed_W),
            TimeLSTM(lstm_Wx, lstm_Wh, lstm_b, stateful=True),
            TimeAffine(affine_W, affine_b)
        ]
        self.loss_layer = TimeSoftmaxWithLoss()
        self.lstm_layer = self.layers[1]

        #Listen Sie alle Gewichte und Verläufe auf
        self.params, self.grads = [], []
        for layer in self.layers:
            self.params += layer.params
            self.grads += layer.grads

    def predict(self, xs):
        for layer in self.layers:
            xs = layer.forward(xs)
        return xs

    def forward(self, xs, ts):
        score = self.predict(xs)
        loss = self.loss_layer.forward(score, ts)
        return loss

    def backward(self, dout=1):
        dout = self.loss_layer.backward(dout)
        for layer in reversed(self.layers):
            dout = layer.backward(dout)
        return dout

    def reset_state(self):
        self.lstm_layer.reset_state()

スクリーンショット 2020-05-22 13.31.47.png Die Schichtstruktur von ** Rnnlm ** ersetzt einfach die Zeit-RNN-Schicht des Modells in Kapitel 5 durch die Zeit-LSTM-Schicht. Bevor wir uns Time LSTM ansehen, schauen wir uns zunächst die dort verwendete LSTM-Ebene an.

4. LSTM-Schicht

class LSTM:
    def __init__(self, Wx, Wh, b):

        self.params = [Wx, Wh, b]
        self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
        self.cache = None

    def forward(self, x, h_prev, c_prev):
        Wx, Wh, b = self.params
        N, H = h_prev.shape

        A = np.dot(x, Wx) + np.dot(h_prev, Wh) + b

        f = A[:, :H]
        g = A[:, H:2*H]
        i = A[:, 2*H:3*H]
        o = A[:, 3*H:]

        f = sigmoid(f)
        g = np.tanh(g)
        i = sigmoid(i)
        o = sigmoid(o)

        c_next = f * c_prev + g * i
        h_next = o * np.tanh(c_next)

        self.cache = (x, h_prev, c_prev, i, f, g, o, c_next)
        return h_next, c_next

スクリーンショット 2020-05-22 16.33.56.png

Dies ist der Vorwärtsausbreitungsteil der ** LSTM-Schicht **. Da die Formeln für die Zellspeicherung und die Vorwärtsausbreitung der drei Gates alle dieselbe Form haben, berechnen die Gewichte $ W_x, W_h und b $ A zusammen und schneiden dann A, um es zu aktivieren. Es ist effizient, die Funktion zu übergeben.

    def backward(self, dh_next, dc_next):
        Wx, Wh, b = self.params
        x, h_prev, c_prev, i, f, g, o, c_next = self.cache

        tanh_c_next = np.tanh(c_next)

        ds = dc_next + (dh_next * o) * (1 - tanh_c_next ** 2)

        dc_prev = ds * f

        di = ds * g
        df = ds * c_prev
        do = dh_next * tanh_c_next
        dg = ds * i

        di *= i * (1 - i)
        df *= f * (1 - f)
        do *= o * (1 - o)
        dg *= (1 - g ** 2)

        dA = np.hstack((df, dg, di, do))

        dWh = np.dot(h_prev.T, dA)
        dWx = np.dot(x.T, dA)
        db = dA.sum(axis=0)

        self.grads[0][...] = dWx
        self.grads[1][...] = dWh
        self.grads[2][...] = db

        dx = np.dot(dA, Wx.T)
        dh_prev = np.dot(dA, Wh.T)

        return dx, dh_prev, dc_prev

スクリーンショット 2020-05-22 13.16.09.png Für die Rückausbreitung kann dA erhalten werden, indem df, dg, di und do gefunden und mit hstach verbunden werden. Danach kann, da es sich um die Rückausbreitung von MatMul handelt, dWx, dWh, db, dx, dh_prev erhalten werden.

5.TimeLSTM

class TimeLSTM:
    def __init__(self, Wx, Wh, b, stateful=False):
        self.params = [Wx, Wh, b]
        self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
        self.layers = None

        self.h, self.c = None, None
        self.dh = None
        self.stateful = stateful

    def forward(self, xs):
        Wx, Wh, b = self.params
        N, T, D = xs.shape
        H = Wh.shape[0]

        self.layers = []
        hs = np.empty((N, T, H), dtype='f')

        if not self.stateful or self.h is None:
            self.h = np.zeros((N, H), dtype='f')
        if not self.stateful or self.c is None:
            self.c = np.zeros((N, H), dtype='f')

        for t in range(T):
            layer = LSTM(*self.params)
            self.h, self.c = layer.forward(xs[:, t, :], self.h, self.c)
            hs[:, t, :] = self.h

            self.layers.append(layer)

        return hs

スクリーンショット 2020-05-22 18.06.23.png

Es ist im Grunde das gleiche wie für TimeRNN. ** Time LSTM Layer ** ist ein Netzwerk, das T LSTM Layer verbindet. Hier können Sie anpassen, ob der Status h zwischen Blöcken mit dem Argument stateful geerbt werden soll. Es gibt auch Zelle C zum Speichern des Speichers.

Bereiten Sie für die Vorwärtsausbreitung zunächst einen Container hs (N, T, H) für die Ausgabe vor. Während die for-Schleife gedreht wird, werden die t-ten Daten durch xs [:, t,:] ausgeschnitten und in das normale LSTM eingegeben, und die Ausgabe befindet sich an der angegebenen Position des von hs [:, t,:] vorbereiteten Containers. Während wir es speichern, registrieren wir Ebenen in Ebenen.

    def backward(self, dhs):
        Wx, Wh, b = self.params
        N, T, H = dhs.shape
        D = Wx.shape[0]

        dxs = np.empty((N, T, D), dtype='f')
        dh, dc = 0, 0

        grads = [0, 0, 0]
        for t in reversed(range(T)):
            layer = self.layers[t]
            dx, dh, dc = layer.backward(dhs[:, t, :] + dh, dc)
            dxs[:, t, :] = dx
            for i, grad in enumerate(layer.grads):
                grads[i] += grad

        for i, grad in enumerate(grads):
            self.grads[i][...] = grad
        self.dh = dh
        return dxs

    def set_state(self, h, c=None):
        self.h, self.c = h, c

    def reset_state(self):
        self.h, self.c = None, None

Die TimeLSTM-Vorwärtsausbreitung hat drei Ausgänge. Bei der Rückwärtsausbreitung wird also $ dh_t + dh_ {next} + dc_ {next} $, die Summe dieser drei, eingegeben.

Erstellen Sie zunächst einen Container dxs, der stromabwärts fließt, ermitteln Sie den Gradienten dx jedes Mal mit backward () der LSTM-Schicht in umgekehrter Reihenfolge der Vorwärtsausbreitung und ersetzen Sie ihn durch den entsprechenden Index von dxs. Der Parameter weight fügt die Gewichtsverläufe für jede Ebene hinzu und überschreibt das Endergebnis in self.grads.

6. Verbessertes LSTM-Modell

Lassen Sie uns nun das verbesserte Modell train_better_rnnlm.py ausführen. Wie erwartet ist dies mit der CPU allein schwierig, daher habe ich cupy auf meinem Windows-Computer installiert.

Führen Sie mit time_size = 35, batch_size = 20, ** word_size = hidden_size = 650, max_epoch = 40 ** aus.

import sys
sys.path.append('..')
from common import config
#Löschen Sie bei der Ausführung auf einer GPU den folgenden Kommentar (Cupy erforderlich).
# ==============================================
config.GPU = True
# ==============================================
from common.optimizer import SGD
from common.trainer import RnnlmTrainer
from common.util import eval_perplexity, to_gpu
from dataset import ptb
from better_rnnlm import BetterRnnlm

#Hyper-Parametereinstellungen
batch_size = 20
wordvec_size = 650
hidden_size = 650
time_size = 35
lr = 20.0
max_epoch = 40
max_grad = 0.25
dropout = 0.5

#Trainingsdaten lesen
corpus, word_to_id, id_to_word = ptb.load_data('train')
corpus_val, _, _ = ptb.load_data('val')
corpus_test, _, _ = ptb.load_data('test')

if config.GPU:
    corpus = to_gpu(corpus)
    corpus_val = to_gpu(corpus_val)
    corpus_test = to_gpu(corpus_test)

vocab_size = len(word_to_id)
xs = corpus[:-1]
ts = corpus[1:]

model = BetterRnnlm(vocab_size, wordvec_size, hidden_size, dropout)
optimizer = SGD(lr)
trainer = RnnlmTrainer(model, optimizer)

best_ppl = float('inf')
for epoch in range(max_epoch):
    trainer.fit(xs, ts, max_epoch=1, batch_size=batch_size,
                time_size=time_size, max_grad=max_grad)

    model.reset_state()
    ppl = eval_perplexity(model, corpus_val)
    print('valid perplexity: ', ppl)

    if best_ppl > ppl:
        best_ppl = ppl
        model.save_params()
    else:
        lr /= 4.0
        optimizer.lr = lr

    model.reset_state()
    print('-' * 50)

#Auswertung mit Testdaten
model.reset_state()
ppl_test = eval_perplexity(model, corpus_test)
print('test perplexity: ', ppl_test)

キャプチャ2.PNG Es wurde in weniger als 3 Stunden auf der Windows-Maschine (GTX1060) abgeschlossen. Die Auswertung durch Testdaten nach 40 Personen hat sich auf Ratlosigkeit = 76-79 verbessert.

In diesem Code wird die Ratlosigkeit der Testdaten für jede Epch berechnet und der Lernkoeffizient lr wird nur verringert, wenn sich der Wert verschlechtert. Werfen wir einen Blick auf Better Rnnlm.

7.BetterRnnlm

import sys
sys.path.append('..')
from common.time_layers import *
from common.np import *  # import numpy as np
from common.base_model import BaseModel

class BetterRnnlm(BaseModel):
    def __init__(self, vocab_size=10000, wordvec_size=650,
                 hidden_size=650, dropout_ratio=0.5):
        V, D, H = vocab_size, wordvec_size, hidden_size
        rn = np.random.randn

        embed_W = (rn(V, D) / 100).astype('f')
        lstm_Wx1 = (rn(D, 4 * H) / np.sqrt(D)).astype('f')
        lstm_Wh1 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')
        lstm_b1 = np.zeros(4 * H).astype('f')
        lstm_Wx2 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')
        lstm_Wh2 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')
        lstm_b2 = np.zeros(4 * H).astype('f')
        affine_b = np.zeros(V).astype('f')

        self.layers = [
            TimeEmbedding(embed_W),
            TimeDropout(dropout_ratio),
            TimeLSTM(lstm_Wx1, lstm_Wh1, lstm_b1, stateful=True),
            TimeDropout(dropout_ratio),
            TimeLSTM(lstm_Wx2, lstm_Wh2, lstm_b2, stateful=True),
            TimeDropout(dropout_ratio),
            TimeAffine(embed_W.T, affine_b)  # weight tying!!
        ]
        self.loss_layer = TimeSoftmaxWithLoss()
        self.lstm_layers = [self.layers[2], self.layers[4]]
        self.drop_layers = [self.layers[1], self.layers[3], self.layers[5]]

        self.params, self.grads = [], []
        for layer in self.layers:
            self.params += layer.params
            self.grads += layer.grads

    def predict(self, xs, train_flg=False):
        for layer in self.drop_layers:
            layer.train_flg = train_flg

        for layer in self.layers:
            xs = layer.forward(xs)
        return xs

    def forward(self, xs, ts, train_flg=True):
        score = self.predict(xs, train_flg)
        loss = self.loss_layer.forward(score, ts)
        return loss

    def backward(self, dout=1):
        dout = self.loss_layer.backward(dout)
        for layer in reversed(self.layers):
            dout = layer.backward(dout)
        return dout

    def reset_state(self):
        for layer in self.lstm_layers:
            layer.reset_state()

スクリーンショット 2020-05-23 16.17.02.png BetterRnnlm Schichtstruktur. Es gibt drei Funktionen: mehrschichtige LSTM-Schicht (2), Verwendung von Dropout (2) und Gewichtsverteilung von Time Embedding und Time Affine.

Während die Ausdruckskraft durch Überlagerung von LSTM erhöht wird, ist Time Dropout (der Inhalt entspricht im Wesentlichen dem von Dropout) enthalten, um das Überlernen zu unterdrücken. Für die Gewichtsverteilung sind die Gewichte der Time Embeddinh-Schicht (V, H) und die Gewichte der Affine-Schicht (H, v), sodass die Trainingsparameter reduziert werden, indem die Gewichte der Time Embedding-Schicht als Gewichte der Affine-Schicht verwendet werden. Unterdrückt Überlernen und erleichtert das Lernen.

Recommended Posts

Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 4 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 3 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 5 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 7 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 8 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 4 Memo
Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 3 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 6 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 7]
Deep Learning / Deep Learning von Grund auf neu Kapitel 6 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 5]
Deep Learning / Deep Learning von Grund auf neu Kapitel 7 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [~ Kapitel 4]
Deep Learning von Grund auf neu Kapitel 2 Perceptron (Memo lesen)
Verbessertes Lernen, um von null bis tief zu lernen
"Deep Learning from Grund" Memo zum Selbststudium (Teil 12) Deep Learning
Deep Learning von Grund auf neu
Selbststudien-Memo "Deep Learning from Grund" (unlesbares Glossar)
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 9) MultiLayerNet-Klasse
[Lernnotiz] Deep Learning von Grund auf ~ Implementierung von Dropout ~
"Deep Learning from Grund" Memo zum Selbststudium (10) MultiLayerNet-Klasse
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 11) CNN
Deep Learning von Grund auf 1-3 Kapitel
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 19) Datenerweiterung
Python-Lernnotiz für maschinelles Lernen von Chainer aus Kapitel 2
Deep Learning 2 von Grund auf 1.3 Verarbeitung natürlicher Sprache 1.3 Zusammenfassung
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 1
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 5
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 2
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 3
Ein Amateur stolperte in Deep Learning von Grund auf neu. Hinweis: Kapitel 7
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 5
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 1
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 4
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 4
Deep Learning Memo von Grund auf neu gemacht
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 2
Selbststudien-Memo "Deep Learning from Grund" (Nr. 15) TensorFlow-Anfänger-Tutorial
Deep Learning Tutorial aus dem Umgebungsbau
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 14) Führen Sie das Programm in Kapitel 4 in Google Colaboratory aus
"Deep Learning from Grund" Memo zum Selbststudium (Teil 8) Ich habe die Grafik in Kapitel 6 mit matplotlib gezeichnet
Selbststudien-Memo "Deep Learning from Grund" (Nr. 13) Verwenden Sie Google Colaboratory
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 10-2) Anfangswert des Gewichts
Tiefes Lernen von Grund auf neu (Vorwärtsausbreitung)
Tiefes Lernen / Tiefes Lernen von Grund auf 2-Versuchen Sie, GRU zu bewegen
Bildausrichtung: von SIFT bis Deep Learning
[Windows 10] Aufbau einer "Deep Learning from Scratch" -Umgebung
Lernbericht über das Lesen von "Deep Learning von Grund auf neu"
[Deep Learning von Grund auf neu] Über die Optimierung von Hyperparametern
Deep Learning aus den mathematischen Grundlagen (während der Teilnahme)
LPIC201 Studiennotiz
Django Lernnotiz
Deep Learning Memorandum
Starten Sie Deep Learning
Python vs Ruby "Deep Learning von Grund auf neu" Kapitel 2 Logikschaltung von Perceptron
Python Deep Learning
Deep Learning × Python