LSTM入门学习笔记
功能
长短期记忆(LSTM)是一种特殊的RNN,相比于普通的RNN主要解决了长序列输入的任务中,在训练过程中出现的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。
LSTM主要应用在以下领域:
- 语音识别,即从长序列的语音信号中获取信息
- 机器翻译,这个不用解释了吧
- 情感分析,即给出一个句子,判断句子中包含的情感倾向
原理
传统的RNN仅有一个传递状态h,而LSTM则在原有的RNN基础上增加了一个传递状态c。
这两个传递状态的区别在于,传递状态h在每次传递过程中变化比较大(大到相邻两个h几乎不一样),而传递状态c在每次传递过程中变化比较小。结合“长短期记忆”这个名字来理解,h代表了新输入的x给整体产生的会在后期逐渐消失的短时新鲜记忆,而c代表了对前期记忆的不断加工,锤炼和理解,沉淀下来的长期记忆。
详细的数学过程因为我个菜菜能力有限,看不明白,就先贴到这里吧,这是论文中引用的[23]内容,好像是最初提出LSTM模型的论文。
https://www.bioinf.jku.at/publications/older/2604.pdf
拼接获取四个状态
$z^f$, $z^i$,$z^o$是由拼接向量乘以权重矩阵之后,再通过一个$sigmod$激活函数转换成0到1之间的数值,来作为一种门控状态。而$z$则是将结果通过一个$tanh$激活函数将转换成-1到1之间的值,这里使用$tanh$是因为这里是将其做为输入数据,而不是门控信号。
- $\odot$是Hadamard Product,即矩阵中对应的元素相乘,要求两个相乘矩阵同型。
- $\oplus$代表进行矩阵加法。
忘记
这一阶段主要使用的是上文计算出的$z^f$,上标 f 表示forget,使之与$c^{t-1}$相乘(不是矩阵乘法),以达到选择性忘记其中部分内容的效果。
这一步中没有对$h^{t-1}$进行操作,即只根据短期记忆的结果,影响了长期记忆,实现了长期记忆随着时间而逐步淡化的过程。
选择记忆
这一阶段主要使用的是上文计算出的$z^i$,上标 i 表示input,使之与$x^t$计算得到的$z$相乘(不是矩阵乘法),以达到选择其中重要部分记忆的效果。
将以上两部分相加,意义上是将长期记忆的遗忘与当前记忆的更新结合起来,形成新的长期记忆,即通过上图中的第一个式子,得到了新的长期记忆$c^t$。
输出
从上文可见,LSTM的输出总共有三个部分,$c^t$、$h^t$和$y^t$,前者已经通过前两部分生成了。
这一阶段主要使用了上文计算得出的$z^o$,上标 o 表示output,使之与经过$tanh$处理的$c^t$相乘(不是矩阵乘法),以达到综合当前输入以及长期记忆生成短期记忆h的效果。而与一般的RNN类似,当前输出$y^t$是$h^t$通过上图中第三个式子计算得到的。
具体实现 TensorFlow
Colab 使用LSTM对TensorFlow官网上给出的IMDB影评信息进行分类
在搜索资料过程中发现的新想法
- 使用GRU能够达到与LSTM相当的效果,并且相比之下更容易进行训练,能够很大程度上提高训练效率
论文中的LSTM
上文说到,代码碎片是代码生成的AST中的一个子树,其根节点是总AST的一个非叶子节点,其深度始终为2。
前文已经通过一些方法将代码转换成AST并从中提取了所有可能的代码碎片,并通过AST的前序遍历将代码碎片组合成了一个个序列。
在训练LSTM模型的过程中,为了避免总词汇表中包含过多不常见代码碎片,这里选用了常用的处理方法,即将出现频率少于5次的代码碎片标记为OoV即不在词汇表中,不参与后续训练与生成。
训练目标
总体上说,训练目标是得到一个模型,依次输入一个代码碎片的序列,模型会输出下一个代码碎片的概率分布情况。
这里的总目标是是适应于后期代码生成的,后期代码生成即参考概率最大的前k个可能的代码碎片生成新的AST
该模型的两个训练目标如下:
- 预测下一个有着最大输出概率的正确的代码碎片
- 优先提供与实际情况下有着相同type的代码碎片
其中,代码碎片的type指的是,代码碎片对应的子树的根节点的类型。
LSTM模型
这里的语言模型总共是用了三层
- 一层映射层,即将代码碎片通过嵌入(embedding)的方式映射成了32维的向量
- 一层LSTM层,基本内容同上文介绍的LSTM内容
- 一层输出层
这里有一些和上文介绍的LSTM内容不一致的地方,LSTM层会输出当前记忆$h^t$,该内容会和下一个代码碎片的type的嵌入向量、下一个代码碎片的父代码碎片的嵌入向量进行连接,然后再投入到输出层去生成对下一个代码碎片的预测信息。
损失函数
这里的损失函数也没有使用TensorFlow或者pytorch常用的损失函数,而是重新定义了一个适应于模型训练目标的损失函数。
这里主要采用的是经验风险最小化的原则,对模型的复杂度没有设置正则化项。
具体的损失函数$l_1$、$l_2$内容如下:
即,前者采用的是交叉熵损失函数,用于在多分类问题中度量两个概率分布(预测概率分布与实际概率分布)之间的相似性,最小化该项可以达到模型训练的第一个目的。后者采用的是一个名为type error的损失函数,用于衡量预测结果的type与实际结果type的相似度(总概率之差),最小化该项可以达到模型训练的第二个目的。
与其他fuzz工具的不同点
区别于其他使用概率语言模型的方法,Montage的独特之处在于引入了代码碎片这个概念,其他同类方法一般采用的是逐个节点生成AST的方式,而这样的生成方式的语言模型往往会丢失一些上下文节点中的语义信息。使用代码碎片这个粒度的生成方式,可以比较好的利用这些信息。