遞歸神經網絡 (Recurrent Neural Network, RNN) 是一種專門用於處理序列數據的神經網絡模型。與傳統的前饋神經網絡不同,RNN 能夠在每個時間步中將過去時間步的信息保留下來,這使其特別適合處理像時間序列、語音、文本等需要考慮上下文的數據。
輸入層 (Input Layer):接收序列數據的每個時間步輸入。
隱藏層 (Hidden Layer):在每個時間步處理當前輸入及前一時間步的隱藏狀態,並更新隱藏狀態。
輸出層 (Output Layer):基於隱藏層的輸出進行最終的預測或生成。
梯度消失問題:由於 RNN 的序列長度會隨著時間步增加,這導致梯度可能會在反向傳播時消失,特別是在處理長序列數據時。這是 RNN 的主要挑戰。
LSTM 和 GRU:為了解決梯度消失問題,提出了兩種改進的 RNN 變種:長短期記憶網絡 (LSTM) 和 門控循環單元 (GRU)。這些變種引入了門機制來控制信息的流動,使得 RNN 能夠在長序列上保留重要信息。
import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import matplotlib.pyplot as plt
path_to_file = tf.keras.utils.get_file("shakespeare.txt",
"https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt")
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
print(f'文本長度: {len(text)} 個字符')
vocab = sorted(set(text))
char2idx = {u: i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)
text_as_int = np.array([char2idx[c] for c in text])
seq_length = 100
examples_per_epoch = len(text) // seq_length
char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)
sequences = char_dataset.batch(seq_length + 1, drop_remainder=True)
def split_input_target(chunk):
input_text = chunk[:-1]
target_text = chunk[1:]
return input_text, target_text
dataset = sequences.map(split_input_target)
BATCH_SIZE = 64
BUFFER_SIZE = 10000
dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)
vocab_size = len(vocab)
embedding_dim = 256
rnn_units = 1024
def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
model = tf.keras.Sequential([
layers.Embedding(vocab_size, embedding_dim, batch_input_shape=[batch_size, None]),
layers.SimpleRNN(rnn_units, return_sequences=True, stateful=True, recurrent_initializer='glorot_uniform'),
layers.Dense(vocab_size)
])
return model
model = build_model(vocab_size=vocab_size, embedding_dim=embedding_dim, rnn_units=rnn_units, batch_size=BATCH_SIZE)
model.compile(optimizer='adam', loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True))
EPOCHS = 10
history = model.fit(dataset, epochs=EPOCHS)
def generate_text(model, start_string):
num_generate = 1000
input_eval = [char2idx[s] for s in start_string]
input_eval = tf.expand_dims(input_eval, 0)
text_generated = []
temperature = 1.0
model.reset_states()
for i in range(num_generate):
predictions = model(input_eval)
predictions = tf.squeeze(predictions, 0)
predictions = predictions / temperature
predicted_id = tf.random.categorical(predictions, num_samples=1)[-1, 0].numpy()
input_eval = tf.expand_dims([predicted_id], 0)
text_generated.append(idx2char[predicted_id])
return start_string + ''.join(text_generated)
print(generate_text(model, start_string="To be, or not to be, that is the question: "))
數據處理:首先,我們讀取莎士比亞的文本並將其轉換為索引序列。每個字符對應於一個唯一的索引,這使得文本可以被輸入到 RNN 中。
RNN 模型結構:
stateful=True
,這允許我們在序列之間保留狀態。訓練模型:模型使用 Sparse Categorical Crossentropy 作為損失函數,Adam 作為優化器來進行訓練。
生成文本:模型訓練後,我們可以輸入一段文字,並讓模型生成後續的文字。生成的過程中,每個字符都是基於當前的隱藏狀態和上一個字符預測出來的。
優化與應用