本文转自:https://www.cnblogs.com/pinking/p/9362966.html
作者:禅在心中
出处:http://www.cnblogs.com/pinking/
本文版权归作者和博客园共有,欢迎批评指正及转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
LSTM(长短期记忆网络)及其tensorflow代码应用
本文主要包括:
一、什么是LSTM
Long Short Term 网络即为LSTM,是一种循环神经网络(RNN),可以学习长期依赖问题。RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。
如上为标准的RNN神经网络结构,LSTM则与此不同,其网络结构如图:
其中,网络中各个元素图标为:
LSTM 通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个 pointwise 乘法操作。LSTM 拥有三个门,来保护和控制细胞状态。
首先是忘记门:
如上,忘记门中需要注意的是,训练的是一个wf的权值,而且上一时刻的输出和当前时刻的输入是一个concat操作。忘记门决定我们会从细胞状态中丢弃什么信息,因为sigmoid函数的输出是一个小于1的值,相当于对每个维度上的值做一个衰减。
然后是信息增加门,决定了什么新的信息到细胞状态中:
其中,sigmoid决定了什么值需要更新,tanh创建一个新的细胞状态的候选向量Ct,该过程训练两个权值Wi和Wc。经过第一个和第二个门后,可以确定传递信息的删除和增加,即可以进行“细胞状态”的更新。
第三个门就是信息输出门:
通过sigmoid确定细胞状态那个部分将输出,tanh处理细胞状态得到一个-1到1之间的值,再将它和sigmoid门的输出相乘,输出程序确定输出的部分。
二、LSTM的曲线拟合
2.1 股票价格预测
下面介绍一个网上常用的利用LSTM做股票价格的回归例子,数据:
如上,可以看到用例包含:index_code,date,open,close,low,high,volume,money,change这样几个特征。提取特征从open-change个特征,作为神经网络的输入,输出即为label。整个代码如下:
?
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
|
这个过程并不难理解,下面分析其中维度变换,从而增加对LSTM的理解。
对于RNN的网络的构建,可以从输入张量的维度上理解,这里我们使用dynamic_rnn(当然可以注意与tf.contrib.rnn.static_rnn在使用上的区别):
?
1 2 3 4 5 6 7 8 9 10 11 |
|
其中:
cell:输入一个RNNcell实例
inputs:RNN神经网络的输入,如果 time_major == False (default),输入的形状是: [batch_size, max_time, embedding_size];如果 time_major == True, 输入的形状是: [ max_time, batch_size, embedding_size]
initial_state: RNN网络的初始状态,网络需要一个初始状态,对于普通的RNN网络,初始状态的形状是:[batch_size, cell.state_size]
2.2 正弦曲线拟合
对于使用LSTM做曲线拟合,参考https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-09-RNN3/,得到代码:
?
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
|
可以看到一个有意思的现象,下面是先后两个时刻的图像:
x值较小的点先收敛,x值大的收敛速度很慢。其原因主要是BPTT的求导过程,对于时间靠前的梯度下降快,可以参考:https://www.cnblogs.com/pinking/p/9418280.html 中1.2节。将网络结构改为双向循环神经网络:
?
1 2 3 4 5 6 7 8 9 |
|
发现收敛速度快了一些。不过这个问题主要还是是因为x的值过大导致的,修改代码,将原始的值的获取进行分段:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
然后可以具体观测某一段的收敛过程:
+ View Code?
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 32 33 34 35 36 37 38 39 |
|
可以看到,当设置的区间比较大,譬如BATCH_START = 3000了,那么就很难收敛了。
因此,这里需要注意了,LSTM做回归问题的时候,注意观测值与自变量之间不要差距过大。当我们改小一些x的值,可以看到效果如图:
三、LSTM的分类问题
对于分类问题,其实和回归是一样的,假设在上面的正弦函数的基础上,若y大于0标记为1,y小于0标记为0,则输出变成了一个n_class(n个类别)的向量,本例中两个维度分别代表标记为0的概率和标记为1的概率。需要修改的地方为:
首先是数据产生函数,添加一个打标签的过程:
?
1 2 3 4 5 6 7 8 9 10 11 |
|
然后修改损失函数,回归问题就不能用最小二乘的损失了,可以采用交叉熵损失函数:
?
1 2 |
|
当然,注意一下维度问题就可以了,效果如图:
例子代码 。
四、为什么LSTM有助于消除梯度消失
为了解决RNN的梯度问题,首先有人提出了渗透单元的办法,即在时间轴上增加跳跃连接,后推广成LSTM。LSTM其门结构,提供了一种对梯度的选择的作用。
对于门结构,其实如果关闭,则会一直保存以前的信息,其实也就是缩短了链式求导。
譬如,对某些输入张量训练得到的ft一直为1,则Ct-1的信息可以一直保存,直到有输入x得到的ft为0,则和前面的信息就没有关系了。故解决了长时间的依赖问题。因为门控机制的存在,我们通过控制门的打开、关闭等操作,让梯度计算沿着梯度乘积接近1的部分创建路径。
如上,可以通过门的控制,看到红色和蓝色箭头代表的路径下,yt+1的在这个路径下的梯度与上一时刻梯度保持不变。
对于信息增加门与忘记门的“+”操作,其求导是加法操作而不是乘法操作,该环节梯度为1,不会产生链式求导。如后面的求导,绿色路径和蓝色路径是相加的关系,保留了之前的梯度。
然而,梯度消失现象可以改善,但是梯度爆炸还是可能会出现的。譬如对于绿色路径:
还是存在着w导致的梯度爆炸现象。