![8ce9bee3002d36a7b926fdc45f77b200.png](https://i-blog.csdnimg.cn/blog_migrate/afe0f8001ac44faade0e0255a57304ef.jpeg)
1. 背景
查阅lstm相关资料,发现很多博客写得语焉不详,内容也多有雷同。笔者从以下几个问题,尽量用精简的语言,梳理lstm的原理。
- rnn/lstm的结构
- rnn/lstm的梯度计算表达式
- paddle使用lstm。
2. rnn/lstm的结构
rnn(英文名recurrent neural network)递归神经网络,输入序列数据(文章里统一指代时间序列数据),一般为三维(batch_size, time_steps, shape)数据,这点和全连接神经网络是不同的,如图1所示为rnn单元简单的结构。
![e90c5f0380c2097863520816eadc3957.png](https://i-blog.csdnimg.cn/blog_migrate/ec715c65e393823162825c3d0ffaa48a.png)
- y(t)—t时刻的输出
- x(t)—t时刻的输入
- y(t-1)—t-1时刻的输出
由A可看出y(t)相当于t-1时刻输出与t时刻输入的一个加权平均,而神经网络优化的是权重矩阵的数值,从而使w1和w2收敛到一组权重系数,使得在指定测试集上,获得一个良好的评测指标(如准确率或者f1)。这和传统的特征工程所处理时序数据思路是类似的,不同的是传统的特征工程由人凭经验去指定一组权重系数,类似于像加权平均数,而lstm中权重是梯度下降法优化所得到。如果把图1展开成图2更容易理解一些,实际是将t-1时刻的输出作为到t时刻输入。
![7d7f36eb25104b25dfe6f9e9ca7ad368.png](https://i-blog.csdnimg.cn/blog_migrate/f92ea79db9632e8dcd6794c8b41c98da.png)
但是rnn在长序列的情况下,会出现梯度消失或者梯度爆炸的情况,而lstm可以有效减轻这种情况(文中不去推导这部分内容)。lstm在简单的rnn的基础上增加了一个Ct变量,由t-1时刻的y(t-1)和xt以及C(t-1)进行更新,最终t时刻输出yt也是由它控制,结构如图3所示。内部更新公式如B所示。
![88efed4bef7f688b611483983bc05232.png](https://i-blog.csdnimg.cn/blog_migrate/aa58630b20c021a108b93ddc45f8dd5f.jpeg)
更加形象化的理解更新公式,lstm作者在论文中提出了和遗忘门以及输出门三个概念,称ft对应遗忘门,it和Ct对应记忆门,yt对应输出门。参考[1]中将门结构图形化如图4。
![004a08978aefcbb1e0e7358753659804.png](https://i-blog.csdnimg.cn/blog_migrate/adfb1775a7aeb1bcd60bd82a3f29f516.png)
图4中符号示意如下:
![b88ba7b037fd75591bbfcd61547073e3.png](https://i-blog.csdnimg.cn/blog_migrate/5e42c4cd1f66d4ce8c12d0c6e64b8bb9.png)
3. rnn/lstm的梯度表达式
假定一个简单rnn单元更新公式如下:
![d1bc87bf5ca9b2566a32e4e22de31359.png](https://i-blog.csdnimg.cn/blog_migrate/668ec9adfcb8f5778d002d942aee23ea.png)
则损失函数为:
![181d517ad57353f4d6613e3ce75dc0df.png](https://i-blog.csdnimg.cn/blog_migrate/26f28196045041256e5b8b81ea09d929.png)
因为每一时刻的损失函数都对最后时刻的损失函数所影响,所以进行求和为最终的损失函数
对上述的五个参数矩阵w1,w2,w3,b0,b1的求导如下:
![b10d544a54f58ceb617528718232b65a.png](https://i-blog.csdnimg.cn/blog_migrate/9a1a6da01513041b9e81e25725ba6cdf.jpeg)
这里不做化简,lstm的公式和这个比较类似,只不过参数更多,更新的公式复杂,求导过程复杂。
4. paddle调用lstm
代码参考paddlepaddle官网
import paddle.fluid as fluid
import paddle.fluid.layers as layers
emb_dim = 256
vocab_size = 10000
data = fluid.layers.data(name='x', shape=[-1, 100, 1],
dtype='int64')
emb = fluid.layers.embedding(input=data, size=[vocab_size, emb_dim], is_sparse=True)
batch_size = 20
max_len = 100
dropout_prob = 0.2
hidden_size = 150
num_layers = 1
init_h = layers.fill_constant( [num_layers, batch_size, hidden_size], 'float32', 0.0 )
init_c = layers.fill_constant( [num_layers, batch_size, hidden_size], 'float32', 0.0 )
rnn_out, last_h, last_c = layers.lstm(emb, init_h, init_c, max_len, hidden_size, num_layers, dropout_prob=dropout_prob)
rnn_out.shape # (-1, 100, 150)
last_h.shape # (1, 20, 150)
last_c.shape # (1, 20, 150)
5. 结论
文中粗略介绍了lstm的结构原理,以及求梯度表达式的方法,但是对于rnn的存在梯度爆炸以及消失以及lstm如何解决rnn的梯度爆炸和消失的问题等问题并未详细说明。
参考资料
[1] https://colah.github.io/posts/2015-08-Understanding-LSTMs
欢迎关注公众号:布宜诺斯艾利斯的数据挖掘者