Wiederkehrende neuronale Netze (RNN) mit Keras

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Einführung

Wiederkehrende neuronale Netze (RNN) sind eine Klasse von neuronalen Netzen, die für die Modellierung von Sequenzdaten wie Zeitreihen oder natürlicher Sprache geeignet sind.

Schematisch verwendet eine RNN-Schicht eine for Schleife, um die Zeitschritte einer Sequenz zu durchlaufen, während ein interner Zustand beibehalten wird, der Informationen über die Zeitschritte codiert, die sie bisher gesehen hat.

Die Keras RNN-API wurde mit folgenden Schwerpunkten entwickelt:

  • Einfachheit: die eingebauten in keras.layers.RNN , keras.layers.LSTM , keras.layers.GRU Schichten Sie ermöglichen, schnell wiederkehrende Modelle zu bauen , ohne schwierige Konfiguration Entscheidungen zu treffen zu haben.

  • Einfache Anpassung : Sie können auch Ihre eigene RNN-Zellenebene (den inneren Teil der for Schleife) mit benutzerdefiniertem Verhalten definieren und mit der generischen keras.layers.RNN (der for Schleife selbst) verwenden. Auf diese Weise können Sie schnell und flexibel verschiedene Forschungsideen mit minimalem Code prototypisieren.

Einrichten

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

Eingebaute RNN-Schichten: ein einfaches Beispiel

In Keras gibt es drei integrierte RNN-Schichten:

  1. keras.layers.SimpleRNN , ein vollständig verbundenes RNN, bei dem die Ausgabe des vorherigen Zeitschritts dem nächsten Zeitschritt zugeführt werden soll.

  2. keras.layers.GRU , erstmals vorgeschlagen in Cho et al., 2014 .

  3. keras.layers.LSTM , erstmals vorgeschlagen in Hochreiter & Schmidhuber, 1997 .

Anfang 2015 hatte Keras die ersten wiederverwendbaren Open-Source-Python-Implementierungen von LSTM und GRU.

Hier ist ein einfaches Beispiel eines Sequential Modells, das Folgen von ganzen Zahlen verarbeitet, jede ganze Zahl in einen 64-dimensionalen Vektor einbettet und dann die Folge von Vektoren unter Verwendung einer LSTM Schicht verarbeitet.

model = keras.Sequential()
# Add an Embedding layer expecting input vocab of size 1000, and
# output embedding dimension of size 64.
model.add(layers.Embedding(input_dim=1000, output_dim=64))

# Add a LSTM layer with 128 internal units.
model.add(layers.LSTM(128))

# Add a Dense layer with 10 units.
model.add(layers.Dense(10))

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 64)          64000     
_________________________________________________________________
lstm (LSTM)                  (None, 128)               98816     
_________________________________________________________________
dense (Dense)                (None, 10)                1290      
=================================================================
Total params: 164,106
Trainable params: 164,106
Non-trainable params: 0
_________________________________________________________________

Integrierte RNNs unterstützen eine Reihe nützlicher Funktionen:

  • Wiederkehrender Dropout über die Argumente dropout und recurrent_dropout
  • Möglichkeit, eine Eingabesequenz in umgekehrter Reihenfolge über das Argument go_backwards
  • Das Abrollen der Schleife (was bei der Verarbeitung kurzer Sequenzen auf der CPU zu einer großen Beschleunigung führen kann) erfolgt über das Argument zum unroll
  • ...und mehr.

Weitere Informationen finden Sie in der RNN-API-Dokumentation .

Ausgänge und Zustände

Standardmäßig enthält die Ausgabe einer RNN-Schicht einen einzelnen Vektor pro Probe. Dieser Vektor ist die RNN-Zellenausgabe, die dem letzten Zeitschritt entspricht und Informationen über die gesamte Eingabesequenz enthält. Die Form dieser Ausgabe ist (batch_size, units) wobei units dem units Argument entspricht, das an den Konstruktor der Ebene übergeben wird.

Eine RNN-Schicht kann auch die gesamte Sequenz von Ausgaben für jedes Sample zurückgeben (ein Vektor pro Zeitschritt pro Sample), wenn Sie return_sequences=True . Die Form dieser Ausgabe ist (batch_size, timesteps, units) .

model = keras.Sequential()
model.add(layers.Embedding(input_dim=1000, output_dim=64))

# The output of GRU will be a 3D tensor of shape (batch_size, timesteps, 256)
model.add(layers.GRU(256, return_sequences=True))

# The output of SimpleRNN will be a 2D tensor of shape (batch_size, 128)
model.add(layers.SimpleRNN(128))

model.add(layers.Dense(10))

model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, None, 64)          64000     
_________________________________________________________________
gru (GRU)                    (None, None, 256)         247296    
_________________________________________________________________
simple_rnn (SimpleRNN)       (None, 128)               49280     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 361,866
Trainable params: 361,866
Non-trainable params: 0
_________________________________________________________________

Darüber hinaus kann eine RNN-Schicht ihre endgültigen internen Zustände zurückgeben. Die zurückgegebenen Zustände können verwendet werden, um die RNN-Ausführung später fortzusetzen oder um eine andere RNN zu initialisieren . Diese Einstellung wird üblicherweise im Sequenzer-zu-Sequenz-Modell des Codierers und Decodierers verwendet, bei dem der Encoder-Endzustand als Anfangszustand des Decodierers verwendet wird.

Um eine RNN-Ebene so zu konfigurieren, dass sie ihren internen Status return_state , setzen Sie den Parameter return_state beim Erstellen der Ebene auf True . Beachten Sie, dass LSTM 2 Zustandstensoren hat, GRU nur einen.

Um den Anfangszustand der Ebene zu konfigurieren, rufen Sie die Ebene einfach mit dem zusätzlichen Schlüsselwortargument initial_state . Beachten Sie, dass die Form des Status mit der Einheitsgröße der Ebene übereinstimmen muss, wie im folgenden Beispiel.

encoder_vocab = 1000
decoder_vocab = 2000

encoder_input = layers.Input(shape=(None,))
encoder_embedded = layers.Embedding(input_dim=encoder_vocab, output_dim=64)(
    encoder_input
)

# Return states in addition to output
output, state_h, state_c = layers.LSTM(64, return_state=True, name="encoder")(
    encoder_embedded
)
encoder_state = [state_h, state_c]

decoder_input = layers.Input(shape=(None,))
decoder_embedded = layers.Embedding(input_dim=decoder_vocab, output_dim=64)(
    decoder_input
)

# Pass the 2 states to a new LSTM layer, as initial state
decoder_output = layers.LSTM(64, name="decoder")(
    decoder_embedded, initial_state=encoder_state
)
output = layers.Dense(10)(decoder_output)

model = keras.Model([encoder_input, decoder_input], output)
model.summary()
Model: "model"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_1 (InputLayer)            [(None, None)]       0                                            
__________________________________________________________________________________________________
input_2 (InputLayer)            [(None, None)]       0                                            
__________________________________________________________________________________________________
embedding_2 (Embedding)         (None, None, 64)     64000       input_1[0][0]                    
__________________________________________________________________________________________________
embedding_3 (Embedding)         (None, None, 64)     128000      input_2[0][0]                    
__________________________________________________________________________________________________
encoder (LSTM)                  [(None, 64), (None,  33024       embedding_2[0][0]                
__________________________________________________________________________________________________
decoder (LSTM)                  (None, 64)           33024       embedding_3[0][0]                
                                                                 encoder[0][1]                    
                                                                 encoder[0][2]                    
__________________________________________________________________________________________________
dense_2 (Dense)                 (None, 10)           650         decoder[0][0]                    
==================================================================================================
Total params: 258,698
Trainable params: 258,698
Non-trainable params: 0
__________________________________________________________________________________________________

RNN-Schichten und RNN-Zellen

Zusätzlich zu den integrierten RNN-Schichten bietet die RNN-API auch APIs auf Zellebene. Im Gegensatz zu RNN-Schichten, die ganze Stapel von Eingabesequenzen verarbeiten, verarbeitet die RNN-Zelle nur einen einzigen Zeitschritt.

Die Zelle ist das Innere der for Schleife einer RNN-Schicht. keras.layers.RNN Sie eine Zelle in eine keras.layers.RNN Schicht keras.layers.RNN , erhalten Sie eine Schicht, die RNN(LSTMCell(10)) von Sequenzen verarbeiten kann, z. B. RNN(LSTMCell(10)) .

Mathematisch RNN(LSTMCell(10)) das gleiche Ergebnis wie LSTM(10) . Tatsächlich wurde bei der Implementierung dieser Schicht in TF v1.x lediglich die entsprechende RNN-Zelle erstellt und in eine RNN-Schicht eingeschlossen. Jedoch mit dem eingebauten in GRU und LSTM Schichten ermöglichen die Verwendung von CuDNN und Sie können eine bessere Leistung sehen.

Es gibt drei eingebaute RNN-Zellen, von denen jede der passenden RNN-Schicht entspricht.

Die Zellabstraktion macht es zusammen mit der generischen Klasse keras.layers.RNN sehr einfach, benutzerdefinierte RNN-Architekturen für Ihre Forschung zu implementieren.

Batch-Statefulness

Wenn Sie sehr lange Sequenzen (möglicherweise unendlich) verarbeiten, möchten Sie möglicherweise das Muster der Batch-Cross-Statefulness verwenden .

Normalerweise wird der interne Zustand einer RNN-Schicht jedes Mal zurückgesetzt, wenn eine neue Charge angezeigt wird (dh es wird angenommen, dass jede von der Schicht gesehene Probe unabhängig von der Vergangenheit ist). Die Ebene behält nur während der Verarbeitung eines bestimmten Samples einen Status bei.

Wenn Sie jedoch sehr lange Sequenzen haben, ist es nützlich, diese in kürzere Sequenzen zu unterteilen und diese kürzeren Sequenzen nacheinander in eine RNN-Schicht einzuspeisen, ohne den Zustand der Schicht zurückzusetzen. Auf diese Weise kann die Ebene Informationen über die Gesamtheit der Sequenz beibehalten, obwohl jeweils nur eine Teilsequenz angezeigt wird.

Sie können dies tun, indem Sie im Konstruktor stateful=True .

Wenn Sie eine Sequenz s = [t0, t1, ... t1546, t1547] , würden Sie sie in z

s1 = [t0, t1, ... t100]
s2 = [t101, ... t201]
...
s16 = [t1501, ... t1547]

Dann würden Sie es verarbeiten über:

lstm_layer = layers.LSTM(64, stateful=True)
for s in sub_sequences:
  output = lstm_layer(s)

Wenn Sie den Status löschen möchten, können Sie layer.reset_states() .

Hier ist ein vollständiges Beispiel:

paragraph1 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph2 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph3 = np.random.random((20, 10, 50)).astype(np.float32)

lstm_layer = layers.LSTM(64, stateful=True)
output = lstm_layer(paragraph1)
output = lstm_layer(paragraph2)
output = lstm_layer(paragraph3)

# reset_states() will reset the cached state to the original initial_state.
# If no initial_state was provided, zero-states will be used by default.
lstm_layer.reset_states()

Wiederverwendung des RNN-Status

Die aufgezeichneten Zustände der RNN-Schicht sind nicht in der Schicht enthalten. layer.weights() . Wenn Sie den Status von einer RNN-Ebene wiederverwenden möchten, können Sie den layer.states von layer.states und über die Keras-Funktions-API wie new_layer(inputs, initial_state=layer.states) als Anfangsstatus für eine neue Ebene verwenden. oder Modellunterklassen.

Bitte beachten Sie auch, dass das sequentielle Modell in diesem Fall möglicherweise nicht verwendet wird, da es nur Ebenen mit einer einzelnen Eingabe und Ausgabe unterstützt. Die zusätzliche Eingabe des Anfangszustands macht eine Verwendung hier unmöglich.

paragraph1 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph2 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph3 = np.random.random((20, 10, 50)).astype(np.float32)

lstm_layer = layers.LSTM(64, stateful=True)
output = lstm_layer(paragraph1)
output = lstm_layer(paragraph2)

existing_state = lstm_layer.states

new_lstm_layer = layers.LSTM(64)
new_output = new_lstm_layer(paragraph3, initial_state=existing_state)

Bidirektionale RNNs

Bei anderen Sequenzen als Zeitreihen (z. B. Text) kann ein RNN-Modell häufig eine bessere Leistung erzielen, wenn es nicht nur Sequenzen von Anfang bis Ende, sondern auch rückwärts verarbeitet. Um beispielsweise das nächste Wort in einem Satz vorherzusagen, ist es oft nützlich, den Kontext um das Wort herum zu haben, nicht nur die Wörter, die davor stehen.

Keras bietet Ihnen eine einfache API zum Erstellen solcher bidirektionaler RNNs: den keras.layers.Bidirectional Wrapper.

model = keras.Sequential()

model.add(
    layers.Bidirectional(layers.LSTM(64, return_sequences=True), input_shape=(5, 10))
)
model.add(layers.Bidirectional(layers.LSTM(32)))
model.add(layers.Dense(10))

model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
bidirectional (Bidirectional (None, 5, 128)            38400     
_________________________________________________________________
bidirectional_1 (Bidirection (None, 64)                41216     
_________________________________________________________________
dense_3 (Dense)              (None, 10)                650       
=================================================================
Total params: 80,266
Trainable params: 80,266
Non-trainable params: 0
_________________________________________________________________

Unter der Haube kopiert Bidirectional die übergebene RNN-Ebene und go_backwards Feld go_backwards der neu kopierten Ebene um, sodass die Eingaben in umgekehrter Reihenfolge verarbeitet werden.

Die Ausgabe des Bidirectional RNN ist standardmäßig die Verkettung der Ausgabe der Vorwärtsschicht und der Ausgabe der Rückwärtsschicht. Wenn Sie ein anderes Zusammenführungsverhalten benötigen, z. B. Verkettung, ändern Sie den Parameter merge_mode im Konstruktor Bidirectional Wrapper. Weitere Informationen zu Bidirectional finden Sie in den API-Dokumenten .

Leistungsoptimierung und CuDNN-Kernel

In TensorFlow 2.0 wurden die integrierten LSTM- und GRU-Schichten aktualisiert, um CuDNN-Kernel standardmäßig zu nutzen, wenn eine GPU verfügbar ist. Mit dieser Änderung sind die vorherigen keras.layers.CuDNNLSTM/CuDNNGRU veraltet, und Sie können Ihr Modell erstellen, ohne sich Gedanken über die Hardware machen zu müssen, auf der es ausgeführt wird.

Da der CuDNN-Kernel mit bestimmten Annahmen erstellt wird, kann der Layer den CuDNN-Kernel nicht verwenden, wenn Sie die Standardeinstellungen der integrierten LSTM- oder GRU-Layer ändern . Z.B:

  • Ändern der activation von tanh auf etwas anderes.
  • Ändern der Funktion recurrent_activation von sigmoid zu etwas anderem.
  • Verwenden von recurrent_dropout > 0.
  • Setzen Sie unroll auf True, wodurch LSTM / GRU tf.while_loop die innere tf.while_loop in eine tf.while_loop for Schleife zu zerlegen.
  • Setzen Sie use_bias auf False.
  • Verwenden der Maskierung, wenn die Eingabedaten nicht genau richtig aufgefüllt sind (wenn die Maske genau richtig aufgefüllten Daten entspricht, kann CuDNN weiterhin verwendet werden. Dies ist der häufigste Fall).

Eine detaillierte Liste der Einschränkungen finden Sie in der Dokumentation zu den LSTM- und GRU- Ebenen.

Verwendung von CuDNN-Kerneln, sofern verfügbar

Lassen Sie uns ein einfaches LSTM-Modell erstellen, um den Leistungsunterschied zu demonstrieren.

Wir werden als Eingabesequenzen die Folge von Reihen von MNIST-Ziffern verwenden (wobei jede Reihe von Pixeln als Zeitschritt behandelt wird), und wir werden die Bezeichnung der Ziffer vorhersagen.

batch_size = 64
# Each MNIST image batch is a tensor of shape (batch_size, 28, 28).
# Each input sequence will be of size (28, 28) (height is treated like time).
input_dim = 28

units = 64
output_size = 10  # labels are from 0 to 9

# Build the RNN model
def build_model(allow_cudnn_kernel=True):
    # CuDNN is only available at the layer level, and not at the cell level.
    # This means `LSTM(units)` will use the CuDNN kernel,
    # while RNN(LSTMCell(units)) will run on non-CuDNN kernel.
    if allow_cudnn_kernel:
        # The LSTM layer with default options uses CuDNN.
        lstm_layer = keras.layers.LSTM(units, input_shape=(None, input_dim))
    else:
        # Wrapping a LSTMCell in a RNN layer will not use CuDNN.
        lstm_layer = keras.layers.RNN(
            keras.layers.LSTMCell(units), input_shape=(None, input_dim)
        )
    model = keras.models.Sequential(
        [
            lstm_layer,
            keras.layers.BatchNormalization(),
            keras.layers.Dense(output_size),
        ]
    )
    return model

Laden wir den MNIST-Datensatz:

mnist = keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
sample, sample_label = x_train[0], y_train[0]
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

Lassen Sie uns eine Modellinstanz erstellen und trainieren.

Wir wählen sparse_categorical_crossentropy als Verlustfunktion für das Modell. Die Ausgabe des Modells hat die Form [batch_size, 10] . Das Ziel für das Modell ist ein ganzzahliger Vektor, wobei jede der ganzen Zahlen im Bereich von 0 bis 9 liegt.

model = build_model(allow_cudnn_kernel=True)

model.compile(
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer="sgd",
    metrics=["accuracy"],
)


model.fit(
    x_train, y_train, validation_data=(x_test, y_test), batch_size=batch_size, epochs=1
)
938/938 [==============================] - 6s 5ms/step - loss: 1.2900 - accuracy: 0.5779 - val_loss: 0.5115 - val_accuracy: 0.8402
<tensorflow.python.keras.callbacks.History at 0x7f5cf00c6518>

Vergleichen wir nun mit einem Modell, das den CuDNN-Kernel nicht verwendet:

noncudnn_model = build_model(allow_cudnn_kernel=False)
noncudnn_model.set_weights(model.get_weights())
noncudnn_model.compile(
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer="sgd",
    metrics=["accuracy"],
)
noncudnn_model.fit(
    x_train, y_train, validation_data=(x_test, y_test), batch_size=batch_size, epochs=1
)
938/938 [==============================] - 32s 33ms/step - loss: 0.4511 - accuracy: 0.8632 - val_loss: 0.3877 - val_accuracy: 0.8686
<tensorflow.python.keras.callbacks.History at 0x7f5ce00c5748>

Wenn Sie auf einem Computer mit installierter NVIDIA-GPU und CuDNN ausgeführt werden, ist das mit CuDNN erstellte Modell viel schneller zu trainieren als das Modell, das den regulären TensorFlow-Kernel verwendet.

Das gleiche CuDNN-fähige Modell kann auch zum Ausführen von Inferenzen in einer Nur-CPU-Umgebung verwendet werden. Die tf.device Anmerkung zu tf.device erzwingt lediglich die Platzierung des Geräts. Das Modell wird standardmäßig auf der CPU ausgeführt, wenn keine GPU verfügbar ist.

Sie müssen sich einfach keine Gedanken mehr über die Hardware machen, auf der Sie arbeiten. Ist das nicht ziemlich cool?

import matplotlib.pyplot as plt

with tf.device("CPU:0"):
    cpu_model = build_model(allow_cudnn_kernel=True)
    cpu_model.set_weights(model.get_weights())
    result = tf.argmax(cpu_model.predict_on_batch(tf.expand_dims(sample, 0)), axis=1)
    print(
        "Predicted result is: %s, target result is: %s" % (result.numpy(), sample_label)
    )
    plt.imshow(sample, cmap=plt.get_cmap("gray"))
Predicted result is: [3], target result is: 5

png

RNNs mit Listen- / Diktat-Eingaben oder verschachtelten Eingaben

Verschachtelte Strukturen ermöglichen es Implementierern, mehr Informationen in einem einzigen Zeitschritt einzuschließen. Beispielsweise könnte ein Videorahmen gleichzeitig Audio- und Videoeingang haben. Die Datenform in diesem Fall könnte sein:

[batch, timestep, {"video": [height, width, channel], "audio": [frequency]}]

In einem anderen Beispiel könnten Handschriftdaten sowohl die Koordinaten x und y für die aktuelle Position des Stifts als auch Druckinformationen haben. Die Datendarstellung könnte also sein:

[batch, timestep, {"location": [x, y], "pressure": [force]}]

Der folgende Code enthält ein Beispiel für die Erstellung einer benutzerdefinierten RNN-Zelle, die solche strukturierten Eingaben akzeptiert.

Definieren Sie eine benutzerdefinierte Zelle, die verschachtelte Ein- / Ausgabe unterstützt

Weitere Informationen zum Schreiben eigener Ebenen finden Sie unter Erstellen neuer Ebenen und Modelle über Unterklassen .

class NestedCell(keras.layers.Layer):
    def __init__(self, unit_1, unit_2, unit_3, **kwargs):
        self.unit_1 = unit_1
        self.unit_2 = unit_2
        self.unit_3 = unit_3
        self.state_size = [tf.TensorShape([unit_1]), tf.TensorShape([unit_2, unit_3])]
        self.output_size = [tf.TensorShape([unit_1]), tf.TensorShape([unit_2, unit_3])]
        super(NestedCell, self).__init__(**kwargs)

    def build(self, input_shapes):
        # expect input_shape to contain 2 items, [(batch, i1), (batch, i2, i3)]
        i1 = input_shapes[0][1]
        i2 = input_shapes[1][1]
        i3 = input_shapes[1][2]

        self.kernel_1 = self.add_weight(
            shape=(i1, self.unit_1), initializer="uniform", name="kernel_1"
        )
        self.kernel_2_3 = self.add_weight(
            shape=(i2, i3, self.unit_2, self.unit_3),
            initializer="uniform",
            name="kernel_2_3",
        )

    def call(self, inputs, states):
        # inputs should be in [(batch, input_1), (batch, input_2, input_3)]
        # state should be in shape [(batch, unit_1), (batch, unit_2, unit_3)]
        input_1, input_2 = tf.nest.flatten(inputs)
        s1, s2 = states

        output_1 = tf.matmul(input_1, self.kernel_1)
        output_2_3 = tf.einsum("bij,ijkl->bkl", input_2, self.kernel_2_3)
        state_1 = s1 + output_1
        state_2_3 = s2 + output_2_3

        output = (output_1, output_2_3)
        new_states = (state_1, state_2_3)

        return output, new_states

    def get_config(self):
        return {"unit_1": self.unit_1, "unit_2": unit_2, "unit_3": self.unit_3}

Erstellen Sie ein RNN-Modell mit verschachtelter Eingabe / Ausgabe

Erstellen wir ein Keras-Modell, das eine keras.layers.RNN und die soeben definierte benutzerdefinierte Zelle verwendet.

unit_1 = 10
unit_2 = 20
unit_3 = 30

i1 = 32
i2 = 64
i3 = 32
batch_size = 64
num_batches = 10
timestep = 50

cell = NestedCell(unit_1, unit_2, unit_3)
rnn = keras.layers.RNN(cell)

input_1 = keras.Input((None, i1))
input_2 = keras.Input((None, i2, i3))

outputs = rnn((input_1, input_2))

model = keras.models.Model([input_1, input_2], outputs)

model.compile(optimizer="adam", loss="mse", metrics=["accuracy"])

Trainieren Sie das Modell mit zufällig generierten Daten

Da es für dieses Modell keinen guten Kandidatendatensatz gibt, verwenden wir zur Demonstration zufällige Numpy-Daten.

input_1_data = np.random.random((batch_size * num_batches, timestep, i1))
input_2_data = np.random.random((batch_size * num_batches, timestep, i2, i3))
target_1_data = np.random.random((batch_size * num_batches, unit_1))
target_2_data = np.random.random((batch_size * num_batches, unit_2, unit_3))
input_data = [input_1_data, input_2_data]
target_data = [target_1_data, target_2_data]

model.fit(input_data, target_data, batch_size=batch_size)
10/10 [==============================] - 1s 25ms/step - loss: 0.9178 - rnn_1_loss: 0.3211 - rnn_1_1_loss: 0.5968 - rnn_1_accuracy: 0.1097 - rnn_1_1_accuracy: 0.0382
<tensorflow.python.keras.callbacks.History at 0x7f5c391e43c8>

Mit der Keras- keras.layers.RNN wird nur erwartet, dass Sie die mathematische Logik für einzelne Schritte innerhalb der Sequenz definieren, und die keras.layers.RNN übernimmt die Sequenziteration für Sie. Es ist eine unglaublich leistungsstarke Methode, um schnell neue Arten von RNNs (z. B. eine LSTM-Variante) zu prototypisieren.

Weitere Informationen finden Sie in den API-Dokumenten .