目录
1. 循环神经网络的基本概念
循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能 力的神经网络。在循环神经网络中,神经元不但可以接受其他神经元的信息,也 可以接受自身的信息,形成具有环路的网络结构。
循环神经网络是一类专门用于处理序列数据的神经网络。与传统的前馈神经网络不同,RNN引入了循环连接,使网络具备了处理时序信息的能力。在处理每个时间步的输入时,网络不仅考虑当前输入,还会利用之前的历史信息。

从结构上看,RNN的核心是一个循环单元,它在每个时间步接收两个输入:当前时刻的输入数据和前一时刻的隐藏状态。这两个输入经过加权组合和非线性变换,生成当前时刻的新隐藏状态。具体来说,在每个时间步t,网络会执行以下计算:h_t = tanh(W_xh * x_t + W_hh * h_{t-1} + b_h),其中激活函数通常选择tanh或ReLU。
我们通过一个完整的Python实现来深入理解简单循环网络的工作机制:
import numpy as np
class SimpleRNN:
def __init__(self, input_size, hidden_size, output_size):
# 初始化网络参数
self.hidden_size = hidden_size
self.W_xh = np.random.randn(input_size, hidden_size) * 0.01
self.W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
self.W_hy = np.random.randn(hidden_size, output_size) * 0.01
self.b_h = np.zeros((1, hidden_size))
self.b_y = np.zeros((1, output_size))
# 用于存储反向传播所需的中间值
self.hidden_states = []
self.inputs = []
def forward(self, input_sequence):
# 初始化隐藏状态
h = np.zeros((1, self.hidden_size))
self.hidden_states = [h]
self.inputs = input_sequence
outputs = []
# 前向传播
for x in input_sequence:
h = np.tanh(np.dot(x, self.W_xh) +
np.dot(h, self.W_hh) +
self.b_h)
y = np.dot(h, self.W_hy) + self.b_y
self.hidden_states.append(h)
outputs.append(y)
return outputs
def backward(self, d_outputs, learning_rate=0.01):
# 初始化梯度
dW_xh = np.zeros_like(self.W_xh)
dW_hh = np.zeros_like(self.W_hh)
dW_hy = np.zeros_like(self.W_hy)
db_h = np.zeros_like(self.b_h)
db_y = np.zeros_like(self.b_y)
# 反向传播
dh_next = np.zeros((1, self.hidden_size))
for t in reversed(range(len(self.inputs))):
# 输出层的梯度
dy = d_outputs[t]
dW_hy += np.dot(self.hidden_states[t+1].T, dy)
db_y += dy
# 隐藏层的梯度
dh = np.dot(dy, self.W_hy.T) + dh_next
dh_raw = (1 - self.hidden_states[t+1] ** 2) * dh
dW_xh += np.dot(self.inputs[t].T, dh_raw)
dW_hh += np.dot(self.hidden_states[t].T, dh_raw)
db_h += dh_raw
dh_next = np.dot(dh_raw, self.W_hh.T)
# 更新参数
self.W_xh -= learning_rate * dW_xh
self.W_hh -= learning_rate * dW_hh
self.W_hy -= learning_rate * dW_hy
self.b_h -= learning_rate * db_h
self.b_y -= learning_rate * db_y
在自然语言处理中,它可以用于实现基础的语言模型我们可以训练网络预测句子中的下一个词:
def create_language_model():
vocab_size = 5000 # 词汇表大小
embedding_size = 128
hidden_size = 256
model = SimpleRNN(embedding_size, hidden_size, vocab_size)
return model
def train_language_model(model, sentences, word_to_idx):
for sentence in sentences:
# 将句子转换为词嵌入序列
input_sequence = [word_to_embedding[word_to_idx[word]]
for word in sentence[:-1]]
target_sequence = [word_to_idx[word] for word in sentence[1:]]
# 前向传播
outputs = model.forward(input_sequence)
# 计算损失和梯度
d_outputs = []
for t, output in enumerate(outputs):
target = np.zeros((1, vocab_size))
target[0, target_sequence[t]] = 1
d_outputs.append(output - target)
# 反向传播
model.backward(d_outputs)
在时间序列预测领域,简单循环网络可以用于预测股票价格、天气等连续值:
def time_series_prediction(data, sequence_length):
model = SimpleRNN(input_size=1, hidden_size=32, output_size=1)
# 准备训练数据
sequences = []
targets = []
for i in range(len(data) - sequence_length):
sequences.append(data[i:i+sequence_length])
targets.append(data[i+sequence_length])
# 训练模型
for epoch in range(num_epochs):
for seq, target in zip(sequences, targets):
outputs = model.forward(seq)
d_outputs = [output - target for output in outputs]
model.backward(d_outputs)
虽然简单循环网络在这些应用中表现出了一定的能力,但它也存在明显的局限性。主要问题包括:
- 梯度消失和爆炸:在反向传播过程中,梯度会随着时间步的增加而衰减或爆炸。
- 长程依赖问题:网络难以捕捉距离较远的依赖关系。
- 信息瓶颈:所有历史信息都需要压缩在固定大小的隐藏状态中。