15 只生成语言模型之RNN与LSTM

在前一篇中,我们讨论了语言模型中的N-gram模型,它通过基于词的n个前一个词的条件概率来捕捉语言的统计特性。然而,N-gram模型存在词汇稀疏和上下文信息不足的问题。在这篇文章中,我们将深入探讨基于循环神经网络(RNN)和长短期记忆(LSTM)网络的语言模型,这些模型能够更好地处理序列数据,并有效捕捉长程依赖关系。

循环神经网络(RNN)

RNN是一种用于处理序列数据的神经网络架构。在传统的神经网络中,输入的每一项都是独立的,而在RNN中,网络的输出不仅与当前输入有关,还与之前的状态(即之前的输入)相关。这种结构使得RNN能够处理可变长度的序列。

RNN的工作原理

在每个时间步骤,RNN接收输入向量$x_t$和前一个隐藏状态$h_{t-1}$,并生成当前的隐藏状态$h_t$. 这个过程可以用以下公式表示:

$$
h_t = f(W_h h_{t-1} + W_x x_t + b)
$$

其中,$W_h$ 和 $W_x$ 是权重矩阵,$b$是偏置项,$f$是激活函数(通常使用tanhReLU)。

最后,RNN会通过一个输出层生成当前时间步骤的输出$y_t$:

$$
y_t = W_y h_t + b_y
$$

示例:简单RNN语言模型

假设我们要生成一句话,“我爱自然语言处理”。在训练过程中,我们可以将这句话转换为一个字符序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

# 简单的字符到索引的映射
chars = '我爱自然语言处理'
char_to_idx = {ch: i for i, ch in enumerate(chars)}
idx_to_char = {i: ch for i, ch in enumerate(chars)}

# 超参数
hidden_size = 10
learning_rate = 0.01

# 初始化权重
W_h = np.random.randn(hidden_size, hidden_size) * 0.01
W_x = np.random.randn(hidden_size, len(chars)) * 0.01
W_y = np.random.randn(len(chars), hidden_size) * 0.01

# 训练过程等...

长短期记忆网络(LSTM)

虽然RNN在序列处理方面表现优越,但它在学习长程依赖时常常会遇到“梯度消失”或“梯度爆炸”的问题。为了解决这一问题,LSTM被提出。

LSTM的结构

LSTM通过引入三个门(输入门、遗忘门和输出门)来控制信息的流动,以此来保持长期的记忆。LSTM的工作机制可以通过以下公式描述:

  1. 遗忘门(Forget Gate):

$$
f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)
$$

  1. 输入门(Input Gate):

$$
i_t = \sigma(W_i [h_{t-1}, x_t] + b_i)$$

$$
\tilde{C}t = \tanh(W_C [h{t-1}, x_t] + b_C)$$

  1. 当前单元状态:

$$
C_t = f_t * C_{t-1} + i_t * \tilde{C}_t$$

  1. 输出门(Output Gate):

$$
o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)$$

  1. 当前隐藏状态:

$$
h_t = o_t * \tanh(C_t)$$

示例:LSTM语言模型

对于生成语言模型,LSTM模型同样可以应用于序列生成。以下是一个简单的LSTM实现示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np

class LSTM:
def __init__(self, input_size, hidden_size):
self.W_f = np.random.randn(hidden_size, input_size + hidden_size) * 0.01 # Forget gate
self.W_i = np.random.randn(hidden_size, input_size + hidden_size) * 0.01 # Input gate
self.W_C = np.random.randn(hidden_size, input_size + hidden_size) * 0.01 # Cell gate
self.W_o = np.random.randn(hidden_size, input_size + hidden_size) * 0.01 # Output gate

self.hidden_size = hidden_size
self.C_prev = np.zeros((hidden_size, 1))
self.h_prev = np.zeros((hidden_size, 1))

def forward(self, x):
combined = np.vstack((self.h_prev, x))

f_t = self.sigmoid(np.dot(self.W_f, combined))
i_t = self.sigmoid(np.dot(self.W_i, combined))
C_hat_t = np.tanh(np.dot(self.W_C, combined))
self.C_prev = f_t * self.C_prev + i_t * C_hat_t
o_t = self.sigmoid(np.dot(self.W_o, combined))
self.h_prev = o_t * np.tanh(self.C_prev)

return self.h_prev

@staticmethod
def sigmoid(x):
return 1 / (1 + np.exp(-x))

# 使用LSTM生成字符序列...

总结

本文介绍了基于RNN和LSTM的语言模型。与N-gram模型相比,这些模型能够更有效地捕捉序列中的上下文信息和长程依赖性。在下篇文章中,我们将探讨更先进的语言模型 —— Transformers。这一模型引入了自注意力机制,并已成为现代自然语言处理的重要组成部分。通过不断改进,我们希望能实现更高性能的语言生成和理解任务。

15 只生成语言模型之RNN与LSTM

https://zglg.work/nlp-zero/15/

作者

IT教程网(郭震)

发布于

2024-08-10

更新于

2024-08-11

许可协议

分享转发

交流

更多教程加公众号

更多教程加公众号

加入星球获取PDF

加入星球获取PDF

打卡评论