无监督循环神经网络文法 (URNNG) | NAACL19

简介: NAACL19 关于无监督循环神经网络文法的论文解读,在语言模型和无监督成分句法分析上都取得了非常不错的结果

雷锋网 AI 科技评论按,本文作者[韦阳](https://www.zhihu.com/people/godweiyang/posts "韦阳"),本文首发于知乎专栏[自然语言处理与深度学习](https://zhuanlan.zhihu.com/godweiyang "自然语言处理与深度学习"),雷锋网 AI 科技评论获其授权转载。 **论文地址:**[Unsupervised Recurrent Neural Network Grammars](http://arxiv.org/abs/1904.03746) **代码地址:**[github](https://github.com/harvardnlp/urnng) # 介绍 --- 这篇是新鲜出炉的 NAACL19 的关于无监督循环神经网络文法(URNNG)的论文,在语言模型和无监督成分句法分析上都取得了非常不错的结果,主要采用了变分推理和 RNNG。本文公式量较大,因此我也推了好久,算法也挺多的,首先上一张我推导的公式笔记: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5ccfe8d71f197.jpg) 我这篇博客就不按照论文的顺序来讲了,就按照我上面这张笔记讲一讲我的理解吧,很多细节可能会忽略,请参见原文吧。 首先对于无监督成分句法分析,常规做法就是学习一个生成模型![](https://static.leiphone.com/uploads/new/article/740_740/201905/5ccff4c4e9ea9.png),就比如 RNNG 就是一个生成模型,但是缺少句法树 z 的监督信号怎么办呢?现在给你的输入只有句子 x,那么只能用语言模型![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0018247697.png)来做监督了。习惯上我们喜欢取对数,也就是: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0019a1a3ae.png) 这里就存在几个问题,比如 z 的状态空间太大了,不可能穷举所有的,所以接下来按步骤讲解如何求解。 # URNNG模型 --- 先上一张模型图,让大家对整体模型有个大概的认知: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd001d48aec7.png) 左边是一个推理网络(Inference Network),用来根据输入 x 推理出隐变量也就是句法树 z 的概率分布![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0022261540.png)。右边是一个生成模型(Generative Model),用来计算从推理网络中采样出来的句法树 z 的联合概率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0023ebd1a7.png),最后根据上面语言模型算出句子的概率,最大化这个概率即可。 接下来分别讲解这两个部分和具体的优化方法。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd002c44eea8.png) 首先将词向量![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0031285a42.png)和位置向量![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00322db624.png)拼接,作为推理网络 LSTM 的输入: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0034a094fe.png) 然后算出![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0036de95e8.png)的得分,计算方式和以往一样,用 BiLSTM 前后向输出做差,然后通过一个前馈神经网络得到分数: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0056fdb506.png) 接下来就需要计算句法树的概率分布了,这里不直接计算句法树 z,而是计算它的邻接矩阵 B 的概率分布,这个邻接矩阵意思就是如果![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0059732fb2.png)存在,那么![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005b539800.png),否则的话![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005ca68054.png)。然后就可以用 CRF 计算出邻接矩阵 B 对应的概率: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005f4dd93b.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0060b1878b.png)是配分函数,也就是用来将概率归约到 0 到 1 之间的: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00620c7d27.png) 注意这里的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0064462a9e.png)并不是所有的 01 矩阵集合,而是必须满足能产生合法句法树的矩阵,情况也很多,不能穷举求解,在这里采用经典的 inside 算法来求解这个配分函数: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00669436e2.jpg) 不过我觉得这里是错的!就是这里的两处![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006c10dc7e.png)应该改成![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006d1b4efd.png)。不过具体代码实现的时候并没有这么做,初始值一样都是![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006e5cf5f9.png),但是递推的时候采用了如下式子: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00703cf397.png) 其实就是用![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd007198598f.png)来取代![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00744ca553.png)了,化简后就是代码实现这个式子,应该是为了防止数值溢出。 然后就是采样了,推理网络的目的就是计算出句法树的概率分布,然后根据这个分布采样出若干个句法树,那么现在给定一棵句法树可以根据上面的算法计算出它的概率了,那怎么采样呢?其实还是可以通过刚刚计算得出的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0076183c1a.png)数组来采样,采样算法如下: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd008cad79c7.jpg) 其实就是自顶向下的根据概率分布来采样每个 span 的 split,用一个队列来保存所有还没有采样出 split 的 span,然后把所有采样出的 span 在邻接矩阵中的对应值标为1。 最后推理网络采样出了若干个句法树 z,然后根据 CRF 计算出每个句法树的概率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00937a3d16.png),后面的事情就交给生成网络了。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0094a504bb.png) 上面的推理网络采样出了若干个句法树 z,生成网络的目的就是计算它的联合概率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd009d0b7269.png)。这个其实不难,在之前的 RNNG 论文笔记中,我已经大致讲过了,可以去复习一下:[Recurrent Neural Network Grammars](https://godweiyang.com/2018/09/02/RNNG/),这里稍稍做了一些改进。 首先需要定义一个栈用来存放转移的历史状态,这里定义栈里放的元素为二元组(h, g),一个是 stack-LSTM 编码的输出,一个是子树的结构表示。首先需要预测下一步的 action 是什么,所以取出栈顶的元素![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a0993c7a.png),预测 action 的时候只要用到隐含层输出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a2527fe7.png) 然后根据这个概率预测 action 是 SHIFT 还是 REDUCE,下面分两种情况讨论。 如果是 SHIFT,那么因为是生成模型,所以需要预测下一个移进的单词是什么: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a9b68a11.png) 然后将单词 x 的词向量输入到 stack-LSTM 中得到下一个时刻的隐含层输出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00acb80148.png) 最后将![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00adcd092c.png)推进栈里。 如果是 REDUCE,那么首先需要取出栈顶的两个元素![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00b3f16ad7.png)和![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00b4d004fb.png),然后用 TreeLSTM 计算出两个子结点合并后的子树的表示: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00be43318f.png) 接着还是计算 stack-LSTM 下一个时刻的隐含层输出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00bfb2133e.png) 最后将![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c0f3cf6c.png)推进栈里。 为了防止数值溢出,常规上我们计算联合概率的对数: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c27f19cf.png) 从这个式子可以看出,联合概率定义为所有给定某段单词和 action 预测下一个单词和给定某段单词和 action 预测下一个 action 的概率之积。 如果是监督任务比如 RNNG,那么只需要最大化这个联合概率就足够了,但是现在要做无监督,没有 z,注意别搞混了,推理网络采样出的 z 可不能用来监督哦,因为那本来就不是正确的,所以接下来要采用语言模型来作为最终的目标函数。 ## Variational Inference 句子 x 的对数概率定义为: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c637b136.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0192ac578b.png)是所有合法句法树的集合,但是这里不可能穷举所有的句法树,所以就要用到变分推理,具体的理论知识不仔细介绍了,可以去查阅变分推理相关知识,下面直接推导。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0194ced2d8.png) 其中最后一行叫做先验![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd019b000b7e.png)的证据下界(ELBO),要想最大化先验,可以最大化这个 ELBO,如果我们对这个 ELBO 变化一下形式可以得到: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd019dd14ef4.png) 所以这个 ELBO 和先验就相差了一个 KL 散度,最大化 ELBO 的话等价于最小化 KL 散度,也就是使推理网络产生句法树的概率分布和生成模型尽量接近。 但是这个 ELBO 还是不好算,尽管它把![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a6b14e49.png)移到了求和符号也就是期望里面,所以转换一下形式: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a586f2ef.png) 因为模型一共有两组参数,一个是推理网络的参数![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a8852ffc.png),一个是生成网络的参数![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a96dfd87.png),所以下面分别对两个参数求导。 首先对![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01aac8c546.png)求偏导,因为只有第一项有这个参数,所以偏导为: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01abef116c.png) 这个偏导可以按照概率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01ad0d3953.png)采样得到: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01afc11128.png) 然后对![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b1a34d63.png)求偏导,因为有两项含有这个参数,分别求偏导。第二项是熵,它的值其实可以用之前的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b2fa2a6b.png)数组算出来,算法如下: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b4d4da00.jpg) 然后偏导可以交给深度学习库的自动微分,就不用你自己求啦。 至于第一项的偏导可以用类似于策略梯度的方法解决: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bac0deb4.png) 这里最后也是转化为了采样,和策略梯度做法类似,这里加入 baseline 来提升性能: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bc65131a.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bd90b591.png)定义为所有其他的对数联合概率的均值: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bec80a30.png) 至此所有偏导都已求出来了,两个通过采样得到,一个通过 inside 算法结果自动微分得到,所以去掉导数符号并相加就得到了最终的损失函数: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c03b63c7.png) 一定要注意,这里的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0290b4e43e.png)在代码实现的时候不能传入梯度,不然的话对![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c2b70fc5.png)的偏导就会多出这一项的偏导了! # 实验 --- 实验结果这里就不多说了,细节具体看论文吧,就贴两个结果,一个是语言模型: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c41e1884.jpg) 可以看出在标准的 PTB 数据集上,URNNG 效果只比监督学习的 RNNG 和用 URNNG 损失函数微调后的 RNNG 效果略差一点,但是在大数据集上,URNNG 的优势就体现出来了。 另一个是无监督成分句法分析,这里是用的全部长度的测试集: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c6670faa.jpg) 这个任务上 URNNG 效果是最好的。 # 结论 --- 和之前两篇语言模型做无监督成分句法分析类似,这篇论文用推理网络学习句法树的概率分布并采样句法树,再用生成网络计算这些句法树和句子的联合概率,最后用变分推理最大化句子的概率,也就是学习出一个好的语言模型。 雷锋网 (公众号:雷锋网)

雷锋网版权文章,未经授权禁止转载。详情见转载须知。

目录
相关文章
|
机器学习/深度学习 算法 大数据
论文赏析[NAACL19]无监督循环神经网络文法 (URNNG)(二)
这篇是新鲜出炉的NAACL19的关于无监督循环神经网络文法(URNNG)的论文,在语言模型和无监督成分句法分析上都取得了非常不错的结果,主要采用了变分推理和RNNG。
446 0
论文赏析[NAACL19]无监督循环神经网络文法 (URNNG)(二)
|
机器学习/深度学习 算法
论文赏析[NAACL19]无监督循环神经网络文法 (URNNG)(一)
这篇是新鲜出炉的NAACL19的关于无监督循环神经网络文法(URNNG)的论文,在语言模型和无监督成分句法分析上都取得了非常不错的结果,主要采用了变分推理和RNNG。
199 0
论文赏析[NAACL19]无监督循环神经网络文法 (URNNG)(一)
|
1月前
|
机器学习/深度学习 数据采集 人工智能
m基于深度学习网络的手势识别系统matlab仿真,包含GUI界面
m基于深度学习网络的手势识别系统matlab仿真,包含GUI界面
40 0
|
1月前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
|
1月前
|
机器学习/深度学习 算法 计算机视觉
m基于深度学习网络的性别识别系统matlab仿真,带GUI界面
m基于深度学习网络的性别识别系统matlab仿真,带GUI界面
29 2
|
1月前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的视频手部检测算法matlab仿真
基于yolov2深度学习网络的视频手部检测算法matlab仿真
|
1月前
|
机器学习/深度学习 算法 数据库
基于CNN卷积网络的MNIST手写数字识别matlab仿真,CNN编程实现不使用matlab工具箱
基于CNN卷积网络的MNIST手写数字识别matlab仿真,CNN编程实现不使用matlab工具箱
|
1月前
|
传感器 算法 Go
基于EKF扩展卡尔曼滤波的传感器网络目标跟踪matlab仿真
基于EKF扩展卡尔曼滤波的传感器网络目标跟踪matlab仿真

热门文章

最新文章