Mạng thần kinh định kỳ (RNN) với Keras

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Giới thiệu

Mạng nơ-ron tuần hoàn (RNN) là một lớp mạng nơ-ron mạnh mẽ để lập mô hình dữ liệu chuỗi như chuỗi thời gian hoặc ngôn ngữ tự nhiên.

Sơ đồ, một lớp RNN sử dụng for vòng lặp để lặp qua timesteps của một chuỗi, trong khi duy trì một trạng thái nội bộ mã hóa thông tin về timesteps nó đã thấy cho đến nay.

Keras RNN API được thiết kế tập trung vào:

  • Dễ sử dụng: được xây dựng trong keras.layers.RNN , keras.layers.LSTM , keras.layers.GRU lớp cho phép bạn nhanh chóng xây dựng mô hình tái phát mà không cần phải có những lựa chọn cấu hình khó khăn.

  • Dễ tùy biến: Bạn cũng có thể xác định lớp của riêng tế bào RNN (phần bên trong của for vòng lặp) với hành vi tùy chỉnh, và sử dụng nó với generic keras.layers.RNN lớp (các for vòng lặp chính nó). Điều này cho phép bạn nhanh chóng tạo mẫu các ý tưởng nghiên cứu khác nhau một cách linh hoạt với mã tối thiểu.

Thành lập

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

Các lớp RNN tích hợp: một ví dụ đơn giản

Có ba lớp RNN tích hợp trong Keras:

  1. keras.layers.SimpleRNN , một RNN đầy đủ kết nối, nơi sản lượng từ timestep trước là để được làm thức ăn cho timestep tới.

  2. keras.layers.GRU , lần đầu tiên được đề xuất trong Chợ et al., 2014 .

  3. keras.layers.LSTM , lần đầu tiên được đề xuất trong Hochreiter & Schmidhuber, 1997 .

Vào đầu năm 2015, Keras đã có bản triển khai Python mã nguồn mở có thể tái sử dụng đầu tiên của LSTM và GRU.

Dưới đây là một ví dụ đơn giản của một Sequential mô hình mà các quy trình chuỗi các số nguyên, nhúng từng số nguyên vào một vector 64 chiều, sau đó xử lý các chuỗi các vectơ sử dụng một LSTM lớp.

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
_________________________________________________________________

RNN tích hợp hỗ trợ một số tính năng hữu ích:

  • Bỏ học thường xuyên, thông qua dropoutrecurrent_dropout luận
  • Khả năng xử lý một chuỗi đầu vào theo hướng ngược lại, thông qua go_backwards luận
  • Vòng unrolling (có thể dẫn đến sự tăng tốc lớn khi xử lý chuỗi ngắn trên CPU), thông qua unroll lập luận
  • ...và nhiều hơn nữa.

Để biết thêm thông tin, xem tài liệu RNN API .

Đầu ra và trạng thái

Theo mặc định, đầu ra của lớp RNN chứa một vectơ duy nhất trên mỗi mẫu. Vectơ này là đầu ra của ô RNN tương ứng với bước thời gian cuối cùng, chứa thông tin về toàn bộ chuỗi đầu vào. Hình dáng của sản lượng này là (batch_size, units) nơi units tương ứng với các units tham số được truyền cho constructor của lớp.

Một RNN lớp cũng có thể trả lại toàn bộ chuỗi các kết quả đầu ra cho mỗi mẫu (một vector mỗi bước thời gian cho mỗi mẫu), nếu bạn đặt return_sequences=True . Hình dáng của sản lượng này là (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
_________________________________________________________________

Ngoài ra, một lớp RNN có thể trả về (các) trạng thái bên trong cuối cùng của nó. Các trạng thái trở lại có thể được sử dụng để tiếp tục thực hiện RNN sau, hoặc để khởi tạo một RNN . Cài đặt này thường được sử dụng trong mô hình nối tiếp trình tự của bộ mã hóa-giải mã, trong đó trạng thái cuối cùng của bộ mã hóa được sử dụng làm trạng thái ban đầu của bộ giải mã.

Để cấu hình một lớp RNN trở về trạng thái nội bộ của mình, thiết lập return_state tham số để True khi tạo lớp. Lưu ý rằng LSTM có 2 tensors nhà nước, nhưng GRU chỉ có một.

Để cấu hình tình trạng ban đầu của lớp, chỉ cần gọi lớp với thêm tham số từ khóa initial_state . Lưu ý rằng hình dạng của trạng thái cần phải phù hợp với kích thước đơn vị của lớp, như trong ví dụ bên dưới.

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
__________________________________________________________________________________________________

Các lớp RNN và các ô RNN

Ngoài các lớp RNN được tích hợp sẵn, API RNN cũng cung cấp các API cấp độ ô. Không giống như các lớp RNN, xử lý toàn bộ loạt chuỗi đầu vào, ô RNN chỉ xử lý một bước thời gian duy nhất.

Các tế bào bên trong for vòng lặp của một lớp RNN. Gói một tế bào bên trong một keras.layers.RNN lớp mang đến cho bạn một lớp khả năng xử lý các lô trình tự, ví dụ như RNN(LSTMCell(10)) .

Về mặt toán học, RNN(LSTMCell(10)) tạo ra kết quả tương tự như LSTM(10) . Trên thực tế, việc triển khai lớp này trong TF v1.x chỉ là tạo ô RNN tương ứng và gói nó trong một lớp RNN. Tuy nhiên bằng cách sử dụng built-in GRULSTM lớp cho phép việc sử dụng các CuDNN và bạn có thể thấy hiệu suất tốt hơn.

Có ba ô RNN dựng sẵn, mỗi ô tương ứng với lớp RNN phù hợp.

Trừu tượng di động, cùng với generic keras.layers.RNN lớp, làm cho nó rất dễ dàng để thực hiện tùy chỉnh RNN kiến trúc cho nghiên cứu của bạn.

Trạng thái hàng loạt chéo

Khi xử lý chuỗi rất dài (có thể là vô hạn), bạn có thể muốn sử dụng các mô hình của statefulness cross-lô.

Thông thường, trạng thái bên trong của lớp RNN được đặt lại mỗi khi nó nhìn thấy một lô mới (tức là mọi mẫu mà lớp nhìn thấy được giả định là độc lập với quá khứ). Lớp sẽ chỉ duy trì một trạng thái trong khi xử lý một mẫu nhất định.

Tuy nhiên, nếu bạn có các trình tự rất dài, sẽ rất hữu ích nếu bạn chia chúng thành các trình tự ngắn hơn và nạp các trình tự ngắn hơn này tuần tự vào một lớp RNN mà không cần đặt lại trạng thái của lớp. Bằng cách đó, lớp có thể giữ lại thông tin về toàn bộ chuỗi, mặc dù nó chỉ nhìn thấy một chuỗi con tại một thời điểm.

Bạn có thể làm điều này bằng cách thiết lập stateful=True trong constructor.

Nếu bạn có một chuỗi s = [t0, t1, ... t1546, t1547] , bạn sẽ chia nó thành ví dụ

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

Sau đó, bạn sẽ xử lý nó qua:

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

Khi bạn muốn xóa tiểu bang, bạn có thể sử dụng layer.reset_states() .

Đây là một ví dụ đầy đủ:

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()

RNN State Reuse

Các trạng thái ghi của lớp RNN không bao gồm trong layer.weights() . Nếu bạn muốn sử dụng lại nhà nước từ một lớp RNN, bạn có thể lấy giá trị quốc gia bởi layer.states và sử dụng nó như tình trạng ban đầu cho một layer mới qua API chức năng Keras như new_layer(inputs, initial_state=layer.states) , hoặc phân lớp mô hình.

Cũng xin lưu ý rằng mô hình tuần tự có thể không được sử dụng trong trường hợp này vì nó chỉ hỗ trợ các lớp có đầu vào và đầu ra duy nhất, đầu vào bổ sung của trạng thái ban đầu khiến nó không thể sử dụng ở đây.

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)

RNN hai chiều

Đối với các trình tự khác với chuỗi thời gian (ví dụ: văn bản), thường là trường hợp mô hình RNN có thể hoạt động tốt hơn nếu nó không chỉ xử lý trình tự từ đầu đến cuối mà còn xử lý ngược lại. Ví dụ, để dự đoán từ tiếp theo trong một câu, thường hữu ích khi có ngữ cảnh xung quanh từ đó, không chỉ những từ đứng trước nó.

Keras cung cấp một API dễ dàng cho bạn để xây dựng RNNs hai chiều như: các 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
_________________________________________________________________

Dưới mui xe, Bidirectional sẽ sao chép các lớp RNN thông qua tại, và lật go_backwards lĩnh vực của lớp mới được sao chép, do đó nó sẽ xử lý đầu vào theo thứ tự ngược.

Đầu ra của Bidirectional RNN sẽ được, theo mặc định, nối các đầu ra lớp phía trước và đầu ra lớp lạc hậu. Nếu bạn cần một hành vi kết hợp khác nhau, ví dụ như nối, thay đổi merge_mode tham số trong Bidirectional constructor wrapper. Để biết thêm chi tiết về Bidirectional , hãy kiểm tra các tài liệu API .

Tối ưu hóa hiệu suất và hạt nhân CuDNN

Trong TensorFlow 2.0, các lớp LSTM và GRU tích hợp đã được cập nhật để tận dụng nhân CuDNN theo mặc định khi có GPU. Với sự thay đổi này, trước keras.layers.CuDNNLSTM/CuDNNGRU lớp đã bị phản đối, và bạn có thể xây dựng mô hình của bạn mà không cần lo lắng về phần cứng nó sẽ chạy trên.

Kể từ khi kernel CuDNN được xây dựng với một số giả định, các phương tiện này lớp sẽ không thể sử dụng hạt nhân CuDNN nếu bạn thay đổi giá trị mặc định của built-in LSTM hay GRU lớp. Ví dụ:

  • Thay đổi activation chức năng từ tanh đến cái gì khác.
  • Thay đổi recurrent_activation chức năng từ sigmoid đến cái gì khác.
  • Sử dụng recurrent_dropout > 0.
  • Thiết unroll là True, mà lực lượng LSTM / GRU để phân hủy bên trong tf.while_loop thành một trải ra for vòng lặp.
  • Thiết use_bias False.
  • Sử dụng mặt nạ khi dữ liệu đầu vào không được đệm đúng (nếu mặt nạ tương ứng với dữ liệu được đệm đúng, vẫn có thể sử dụng CuDNN. Đây là trường hợp phổ biến nhất).

Để xem danh sách chi tiết những hạn chế, vui lòng xem tài liệu cho LSTMGRU lớp.

Sử dụng hạt nhân CuDNN khi có sẵn

Hãy xây dựng một mô hình LSTM đơn giản để chứng minh sự khác biệt về hiệu suất.

Chúng tôi sẽ sử dụng làm trình tự đầu vào chuỗi các hàng chữ số MNIST (coi mỗi hàng pixel là một bước thời gian) và chúng tôi sẽ dự đoán nhãn của chữ số.

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

Hãy tải tập dữ liệu MNIST:

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]

Hãy tạo một thể hiện mô hình và đào tạo nó.

Chúng tôi chọn sparse_categorical_crossentropy như hàm tổn thất cho mô hình. Đầu ra của mô hình có hình dạng của [batch_size, 10] . Mục tiêu cho mô hình là một vectơ số nguyên, mỗi số nguyên nằm trong khoảng từ 0 đến 9.

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: 0.9510 - accuracy: 0.7029 - val_loss: 0.5633 - val_accuracy: 0.8209
<keras.callbacks.History at 0x7fc9942efad0>

Bây giờ, hãy so sánh với một mô hình không sử dụng hạt nhân CuDNN:

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 [==============================] - 34s 35ms/step - loss: 0.3894 - accuracy: 0.8846 - val_loss: 0.5677 - val_accuracy: 0.8045
<keras.callbacks.History at 0x7fc945fa2650>

Khi chạy trên máy có cài đặt GPU NVIDIA và CuDNN, mô hình được xây dựng bằng CuDNN được đào tạo nhanh hơn nhiều so với mô hình sử dụng nhân TensorFlow thông thường.

Mô hình hỗ trợ CuDNN tương tự cũng có thể được sử dụng để chạy suy luận trong môi trường chỉ dành cho CPU. Các tf.device chú thích dưới đây chỉ là buộc các vị trí thiết bị. Mô hình sẽ chạy trên CPU theo mặc định nếu không có sẵn GPU.

Đơn giản là bạn không phải lo lắng về phần cứng mà bạn đang sử dụng nữa. Điều đó không phải là khá tuyệt phải không?

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

RNN với đầu vào danh sách / dict hoặc đầu vào lồng nhau

Cấu trúc lồng nhau cho phép người triển khai bao gồm nhiều thông tin hơn trong một bước thời gian. Ví dụ: một khung video có thể có đầu vào âm thanh và video cùng một lúc. Hình dạng dữ liệu trong trường hợp này có thể là:

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

Trong một ví dụ khác, dữ liệu chữ viết tay có thể có cả tọa độ x và y cho vị trí hiện tại của cây bút, cũng như thông tin về áp suất. Vì vậy, biểu diễn dữ liệu có thể là:

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

Đoạn mã sau cung cấp một ví dụ về cách tạo một ô RNN tùy chỉnh chấp nhận các đầu vào có cấu trúc như vậy.

Xác định ô tùy chỉnh hỗ trợ đầu vào / đầu ra lồng nhau

Xem Làm lớp mới & Models qua subclassing để biết chi tiết về cách viết các lớp của riêng bạn.

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}

Xây dựng mô hình RNN với đầu vào / đầu ra lồng nhau

Hãy xây dựng một mô hình Keras có sử dụng một keras.layers.RNN lớp và các tế bào tùy chỉnh chúng ta vừa xác định.

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"])

Đào tạo mô hình với dữ liệu được tạo ngẫu nhiên

Vì không có tập dữ liệu ứng viên tốt cho mô hình này, chúng tôi sử dụng dữ liệu Numpy ngẫu nhiên để trình diễn.

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 26ms/step - loss: 0.7316 - rnn_1_loss: 0.2590 - rnn_1_1_loss: 0.4725 - rnn_1_accuracy: 0.1016 - rnn_1_1_accuracy: 0.0328
<keras.callbacks.History at 0x7fc5686e6f50>

Với Keras keras.layers.RNN lớp, Bạn chỉ được dự kiến để xác định logic toán cho bước cá nhân trong chuỗi, và keras.layers.RNN lớp sẽ xử lý lặp chuỗi cho bạn. Đó là một cách cực kỳ hiệu quả để nhanh chóng tạo nguyên mẫu các loại RNN mới (ví dụ như một biến thể LSTM).

Để biết thêm chi tiết, vui lòng truy cập tài liệu API .