Warum LSTM beim Informations-Latching schlechter abschneidet als das Vanilla-Netzwerk für wiederkehrende Neuronen

8

Ich möchte besser verstehen, warum sich LSTM über einen längeren Zeitraum an Informationen erinnern kann als Vanille / einfaches wiederkehrendes neuronales Netzwerk (SRNN), indem ich ein Experiment aus dem Artikel Lernen von Langzeitabhängigkeiten mit Gradientenabstieg von Bengio et al. 1994 .

Siehe Abb. 1. und 2 auf diesem Papier. Die Aufgabe ist in einer bestimmten Reihenfolge einfach. Wenn sie mit einem hohen Wert (z. B. 1) beginnt, lautet die Ausgabebezeichnung 1; Wenn es mit einem niedrigen Wert beginnt (z. B. -1), ist das Ausgabeetikett 0. Die Mitte ist Rauschen. Diese Aufgabe wird als Informations-Latching bezeichnet, da sich das Modell beim Durchlaufen des mittleren Rauschens den Startwert merken muss, um ein korrektes Etikett auszugeben. Es wurde ein einzelnes Neuron-RNN verwendet, um ein Modell zu erstellen, das ein solches Verhalten aufweist. Die Abbildung 2 (b) zeigt die Ergebnisse, und die Erfolgshäufigkeit des Trainings eines solchen Modells nimmt mit zunehmender Sequenzlänge dramatisch ab. Es gab kein Ergebnis für LSTM, da es 1994 noch nicht erfunden wurde.

Ich werde also neugierig und würde gerne sehen, ob LSTM für eine solche Aufgabe tatsächlich eine bessere Leistung erbringt. In ähnlicher Weise konstruierte ich ein einzelnes Neuron-RNN sowohl für Vanille- als auch für LSTM-Zellen, um das Informations-Latching zu modellieren. Überraschenderweise stellte ich fest, dass LSTM schlechter abschneidet, und ich weiß nicht warum. Könnte mir jemand helfen zu erklären oder wenn etwas mit meinem Code nicht stimmt, bitte?

Hier ist mein Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Hier ist mein Code:

import matplotlib.pyplot as plt
import numpy as np    
from keras.models import Model
from keras.layers import Input, LSTM, Dense, SimpleRNN


N = 10000
num_repeats = 30
num_epochs = 5
# sequence length options
lens = [2, 5, 8, 10, 15, 20, 25, 30] + np.arange(30, 210, 10).tolist()

res = {}
for (RNN_CELL, key) in zip([SimpleRNN, LSTM], ['srnn', 'lstm']):
    res[key] = {}
    print(key, end=': ')
    for seq_len in lens:
        print(seq_len, end=',')
        xs = np.zeros((N, seq_len))
        ys = np.zeros(N)

        # construct input data
        positive_indexes = np.arange(N // 2)
        negative_indexes = np.arange(N // 2, N)

        xs[positive_indexes, 0] = 1
        ys[positive_indexes] = 1

        xs[negative_indexes, 0] = -1
        ys[negative_indexes] = 0

        noise = np.random.normal(loc=0, scale=0.1, size=(N, seq_len))

        train_xs = (xs + noise).reshape(N, seq_len, 1)
        train_ys = ys

        # repeat each experiments multiple times
        hists = []
        for i in range(num_repeats):
            inputs = Input(shape=(None, 1), name='input')

            rnn = RNN_CELL(1, input_shape=(None, 1), name='rnn')(inputs)
            out = Dense(2, activation='softmax', name='output')(rnn)
            model = Model(inputs, out)
            model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
            hist = model.fit(train_xs, train_ys, epochs=num_epochs, shuffle=True, validation_split=0.2, batch_size=16, verbose=0)
            hists.append(hist.history['val_acc'][-1])
        res[key][seq_len] = hists
    print()


fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(pd.DataFrame.from_dict(res['lstm']).mean(), label='lstm')
ax.plot(pd.DataFrame.from_dict(res['srnn']).mean(), label='srnn')
ax.legend()

Ich habe auch das Ergebnis im Notizbuch angezeigt , was praktisch wäre, wenn Sie die Ergebnisse replizieren möchten. Es dauerte über einen Tag, bis das Experiment auf meinem Computer nur mit CPU ausgeführt wurde. Auf einem GPU-fähigen Computer könnte es schneller sein.

Update 2018-04-18 :

Ich habe versucht, eine Figur in der Landschaft von RNN zu reproduzieren, die von Abbildung 6 in Über die Schwierigkeit des Trainings wiederkehrender neuronaler Netze inspiriert ist . Ich finde es interessant, die Bildung von Klippen in der Verlustlandschaft zu sehen, wenn die Anzahl der Wiederholungen / Zeitschritte / Sequenzlängen zunimmt, was mit der Erklärung der hier beobachteten Schwierigkeit des Trainings langer Sequenzen zusammenhängen könnte. Weitere Details finden Sie hier .

Geben Sie hier die Bildbeschreibung ein

Update 2018-04-19

@ Shimaos Experiment erweitern. Es scheint, dass LSTM und GRU einfach nicht so gut darin sind, Informationen zu erfassen. Wenn Sie jedoch zu einer anderen Aufgabe wechseln, die ich als Bit-Relay bezeichne (@ shimaos Aufgabe 2), ist die GRU besser, während SRNN und LSTM gleich schlecht sind.

Jetzt neige ich dazu zu glauben, dass die Leistung eines Zelltyps aufgabenspezifisch sein könnte.

Aufgabe 1: Informationsspeicherung (1 Einheit; 10 Wiederholungen; 10 Epochen)

Geben Sie hier die Bildbeschreibung ein

Aufgabe 2: Bitrelais (8 Einheiten; 10 Wiederholungen; 10 Epochen)

Geben Sie hier die Bildbeschreibung ein

Fehlerbalken sind Standardabweichungen.

Eine interessante Frage ist dann, warum LSTM beim Latching von Informationen nicht funktioniert. Angesichts der Einfachheit der Aufgabe sollte sie funktionieren können, nicht wahr? Könnte in Bezug auf die Steigungen mit der Landschaft (z. B. Klippen) zusammenhängen.

Zyxue
quelle
Es sieht so aus, als würden Sie in beiden Fällen eine RNN mit einer Einheit verwenden. Haben Sie versucht, es größer zu machen, sagen wir 10 oder 100?
Alex R.
1
Nein, die Idee des Originalpapiers ist es, das einfachste System zu entwerfen, damit wir effektiv argumentieren können. Was ist die Motivation, mehrere Zellen zu verwenden? Die Aufgabe ist so einfach, und Sie können sehen, dass sowohl LSTM als auch SRNN gut funktionieren, wenn die Sequenz kurz ist.
Zyxue
Ich habe dieses Papier nicht genau (oder vor kurzem) gelesen, aber sind Sie sicher, dass Sie die experimentellen Bedingungen genau reproduzieren? Es erscheint plausibel, dass es eine Reihe kleiner, aber wichtiger Unterschiede zwischen Ihrem Setup und dem Papier gibt, die den Fehler erklären könnten. Oder anders ausgedrückt, dies ist im Grunde ein Debugging-Problem, bei dem es nur einen relativ uninformativen Komponententest gibt.
Sycorax sagt Reinstate Monica
@Sycorax, in dem Artikel geht es nur um Vanille-RNN, da LSTM 1994 noch nicht erfunden wurde. Meine Ergebnisse zu Vanille-RNN stimmen mit denen überein. Deshalb ist LSTM schlechter, was mich verwirrt.
Zyxue
Dieses Papier paper.nips.cc/paper/… könnte von Interesse sein - es befasst sich mit den langfristigen Abhängigkeitsproblemen, die Bengio in dem von Ihnen zitierten Papier angesprochen hat. Daher könnte die Replikation des von Schmidhuber verwendeten Experiments ein produktiverer Weg sein
sagt Sycorax Stellen Sie Monica am

Antworten:

3

Es gibt einen Fehler in Ihrem Code, da die erste Hälfte Ihrer konstruierten Beispiele positiv und der Rest negativ ist, aber Keras nicht mischen, bevor die Daten in Zug und Wert aufgeteilt werden, was bedeutet, dass der gesamte Wertesatz negativ ist und der Das Zugset ist auf positiv ausgerichtet, weshalb Sie seltsame Ergebnisse wie die Genauigkeit 0 (schlechter als der Zufall) erhalten haben.

Außerdem habe ich einige Parameter (wie Lernrate, Anzahl der Epochen und Stapelgröße) angepasst, um sicherzustellen, dass das Training immer konvergiert.

Schließlich habe ich nur 5 und 100 Zeitschritte ausgeführt, um Rechenaufwand zu sparen.

Geben Sie hier die Bildbeschreibung ein

Seltsamerweise trainiert das LSTM nicht richtig, obwohl das GRU fast so gut funktioniert wie das RNN.

Ich habe eine etwas schwierigere Aufgabe ausprobiert: In positiven Sequenzen ist das Vorzeichen des ersten Elements und eines Elements in der Mitte der Sequenz das gleiche (beide +1 oder beide -1), in negativen Sequenzen sind die Vorzeichen unterschiedlich. Ich hatte gehofft, dass die zusätzliche Speicherzelle im LSTM hier davon profitieren würde

Geben Sie hier die Bildbeschreibung ein

Es hat besser funktioniert als RNN, aber nur am Rande, und die GRU gewinnt aus irgendeinem Grund.

Ich habe keine vollständige Antwort darauf, warum das RNN bei der einfachen Aufgabe besser abschneidet als das LSTM. Ich denke, es muss sein, dass wir nicht die richtigen Hyperparameter gefunden haben, um das LSTM richtig zu trainieren, zusätzlich zu der Tatsache, dass das Problem für ein einfaches RNN einfach ist. Möglicherweise neigt ein Modell mit so wenigen Parametern auch eher dazu, im lokalen Minimum hängen zu bleiben.

Der geänderte Code

Shimao
quelle
Ich habe Ihr Experiment erweitert und konsistente Ergebnisse erzielt. Ich denke, die Leistung ist wahrscheinlich aufgabenspezifisch.
Zyxue
0

Ich weiß nicht, ob es einen Unterschied machen wird, aber ich würde verwenden:

out = Dense (1, activation='sigmoid', ...

und

model.compile(loss='binary_crossentropy', ...

für ein binäres Klassifizierungsproblem.

Wayne
quelle
1
Ich glaube mathematisch sind die beiden gleich. Insbesondere entspricht Sigmoid Softmax, wo es nur zwei Klassen gibt. binary_crossentropy ist immerhin crossentropy für zwei Klassen. Dieses Problem verwirrt mich wirklich und ich bin offen dafür, das Kopfgeld zu erhöhen, wenn jemand eine nette Erklärung liefern könnte.
Zyxue
Verwenden Sie für jede Version dieselben Parameter? LSTM ist komplexer und erfordert möglicherweise mehr Daten, mehr Epochen, eine andere Lernrate usw. @ zyxue
Wayne