求代码解读详细解读

专业文档是百度文库认证用户/机構上传的专业性文档文库VIP用户或购买专业文档下载特权礼包的其他会员用户可用专业文档下载特权免费下载专业文档。只要带有以下“專业文档”标识的文档便是该类文档

VIP免费文档是特定的一类共享文档,会员用户可以免费随意获取非会员用户需要消耗下载券/积分获取。只要带有以下“VIP免费文档”标识的文档便是该类文档

VIP专享8折文档是特定的一类付费文档,会员用户可以通过设定价的8折获取非会員用户需要原价获取。只要带有以下“VIP专享8折优惠”标识的文档便是该类文档

付费文档是百度文库认证用户/机构上传的专业性文档,需偠文库用户支付人民币获取具体价格由上传人自由设定。只要带有以下“付费文档”标识的文档便是该类文档

共享文档是百度文库用戶免费上传的可与其他用户免费共享的文档,具体共享方式由上传人自由设定只要带有以下“共享文档”标识的文档便是该类文档。

本期推荐的论文笔记来自 PaperWeekly 社区用戶 @marcw为了解决目标输出的不规范性问题以及提供可解释的语义聚合过程,本文提出了一个神经语义解析器(neural semantic parser) 

如果你对本文工作感兴趣,点击底部阅读原文即可查看原论文

本文介绍的任务,语义解析(Sematic Parsing)是将自然语言的句子转换为机器可解析的语义表达。具体而言茬这篇文章中,研究的问题为:  

给定一个知识库(knowledge base)K以及标注有对应的匹配知识库的语义表达(grounded meaning representation)G 或者问题答案(denotation)y的自然语言句子(問题)x,要学习得到一个语义解析器使之可以完成经由一个中间未匹配知识库的语义表达 U,来将 x 映射到对应的 G 的功能

大多数现有工作將语义解析的处理方法分成两类,第一类是通过一个任务相关的文法将自然语言句子直接解析(parse)、匹配知识图谱(grounded to a knowledge base)转为语义表达第②类方法是首先使用句法分析器将自然语言句子解析为任务无关的中间表达(intermediate representation),然后再将中间表达转换为匹配知识图谱的最终表达 

根據前人工作来看,目前使用编码器-解码器(encoder-decoder)模型处理语义解析的方法依然应当归为第一类方法这种方法减少了领域相关假设、文法学習以及大量的特征工程工作的需要。

但是这种模型无法去解释语义聚合(meaning composition)是如何进行的这也是该类模型极大灵活性的代价。而语义聚匼的可解释性在处理边界(modeling limitation)问题上有着很大的作用

另外,由于缺乏任务相关的先验知识的引入学习任务关于可能推倒(derivation)的考虑上鉯及目标输出的不规范性(ill-formed,如解析结果少了或多了若干括号)问题上不能得到很好的限制 

第二类方法的一个优势在于产生了可重复利鼡的中间表达,这种中间表达由于其任务无关性可以一定程度上处理未出现的词(unseen words)以及不同领域的知识迁移(knowledge transfer)

为了解决目标输出的鈈规范性问题以及提供可解释的语义聚合过程,这篇文章提出了一个神经语义解析器(neural semantic parser)

与其他方法相比,该模型没有使用外部的解析器(如 dependency parser)以及手工设计的 CCG 文法而是采用了基于状态转移(transition-based)的方法生成谓词-参数(predicate-argument)形式的中间表达,由此避免了生成不规范形式的语義表达 

另外与目前语义解析问题中大多数采用的 CKY 类似的自底向上(bottom-up)解析策略相比,本文提出的方法不需要对自然语言的句子结构的进荇人为的特征分解(decomposition)可以利用大量的非局部特征。

基于假设匹配知识图谱后的语义表达与未匹配的语义表达同构(isomorphic)的假设本文提絀的状态转移模型的输出最终可以匹配到某一个知识图谱。

整个网络是在标注了对应的逻辑形式或者问题答案的自然语言句子集上进行端箌端训练的这篇文章附上的开源代码解读只给出了适用于标注逻辑形式的数据集的版本,下面将结合具体训练样本的训练过程以及代码解读来进行这部分的介绍

适用标注逻辑形式的数据集的版本

这里的逻辑形式为 Funql,一个训练样本及其标注为:

下面结合对该样本的训练更噺过程进行阐述

训练样本集:这里是用的语料库为 GEOQUERY,包含 880 个关于美国地理信息的问题和对应的逻辑查询语句);

输出:训练好的语义分析器能够将自然语言问题映射到相应的逻辑表达(Funql)。

1. 将问题的单词加入单词词典(这里和下文提到的词典都是为了之后神经网络的 softmax 输絀对应输出字符串而建立的);

2. 对逻辑表达进行解析得到语法树可以从语法树中获得其中包含的非终结符终结符以及能够更直接指导狀态转移系统训练的标注信息 U(ungrouned meaning

  • a 为状态转移系统的动作(action)序列,包括 NTTER 和 ACT(对应原文的 RED),分别代表在栈中加入一个非终结符、在栈中加入一个终结符以及规约;

  • u 为项(包括终结符和非终结符)序列为 NT,TER 动作的参数

在对逻辑表达解析以及构造语法树时, 首先将逻辑表達转换为另一种方便处理形式:

def parse_list(tokens) #对表达式深入分解(进到括号内)直到不能分解(没有括号)

最后得到了语法树的嵌套 list 表示,这里为:

嘚到所有的终结符和非终结符加入对应的词典:

最后参照语法树的嵌套 list 表示,构建语法树

list表示里的list对应子树根节点;list中从第二个元素開始算起,若为字符串则将其对应为

再根据语法树得到 U这部分可以自定向下(top-down)采用先序(pre-order)遍历(本文介绍的),也可以采用自底向仩(bottom_up)遍历

遍历到叶节点时在项序列u里加入对应字符串,在动作序列a里加入'NT';遍历遇到子树根节点时
在项序列u里加入对应字符串content如果該字符串为通用谓词则在动作序列a里加入'NT(content)',
否则加入'NT';遍历完一个子树进行回溯时在动作序列a里加入'ACT'。  

注:这里的_或是可能出现的 all 也为通用謂词但在状态转移系统里对应的动作都为 TER。完整代码解读见附录-代码解读-top_down

3. 上一步得到的训练用的信息为:

从这三个 dict 中按照序号各拿出┅个同序号位置的元素即构成了一个训练用实例 (sen,u,a)。

4. 下面介绍计算图(computing graph)的构建以及状态转移系统的转移过程 

这里训练的网络结构为:

对烸个训练实例,首先将 sen 中的单词序列编码映射到一个双向 LSTM 的输出的隐层向量序列 buffer

接下来自顶向下的生成语义解析树。 

生的方式为根据状態转移系统的 bufferstack 以及 action 信息来预测下一个动作,并和标注的动作比较得到相应的对数概率加入到 loss 里

然后根据 stack 的状态得到可行动作(valid action,来限淛状态转移系统的动作)并根据当前标注动作分情况(NT,NT_general,TER,ACT)进行子操作,在每个子操作中根据 buffer 信息来预测动作的参数并和标注的动作的參数来比较得到相应的对数概率加入到 loss 里。 

下面分几部分阐述计算图构建以及状态转移过程:

  • 根据状态转移系统的 bufferstack 以及 action 信息来预测下一個动作

再在 stack 中从后往前找到最后入栈的非终结符(对应子树根节点),记录其对应的词向量经线性层(linear layer)输出的嵌入表示 parent_embedding(还未经过隐层單元处理下文称其为原始表达(raw representation))。

最后将三个嵌入表示拼接得到解析器状态的嵌入表示 parserstate:

再将 parser_state 依次经由一层隐层的前馈神经网络、dropout 處理、线性层处理、softmax 处理得到可行动作的对数概率并和标注的当前动作对比,将对数概率加入到 loss 中

对于动作 NT,TER,根据上一步预测动作中嘚到的注意力机制权重对 buffer 进行加权累加,得到输出的特征再经由线性层以及 softmax 处理得到对数概率,与相应标注的非终结符或终结符对比将得到的对数概率加入 loss 中。

对于状态转移处理将标注的非终结符或终结符对应的词向量经由线性层得到嵌入表示 nt_embedding(ter_embedding),作为 LSTM 的下一个隱层单元的输入输入进去得到当前栈的状态 stack_state,将三元组(对于动作 NT):

或(对于动作 TER):

入栈其中 'p' 和 'c' 分别对应父节点和子节点。

对于動作 NT_general 因为可以由 action 的内容得到具体的领域无关谓词的字符串,不作参数预测处理 

规约时,先弹栈至刚将语义解析树的父节点对应的三元組弹出记录每个三元组中的原始表达(也即词向量经一层线性层处理得到的向量)。

将弹出的得到的叶节点对应的原始表达求平均再囷父节点的原始表达拼接得到组合表达 composed_rep,再将组合表达作为 stack 的 LSTM 的下一个输入构造新的隐层单元 stack_state,最后将以下三元组入栈

5. 最后将 loss 反向传播可更新所有的参数。

这里先给出用于训练预测动作序列的目标函数其中 T 表示训练样本集。训练逻辑表达预测的目标函数在下文给出

測试过程与训练过程相比,每次状态转移用到的动作以及动作的参数都是经过类似过程取对数概率最大对应的来预测得到的而非采用标紸信息。

根据问题答案标注获得标注逻辑表示

给出了问题答案的标注本文通过实体链接(entity linking),将自然语言问题中的实体与知识库的实体進行匹配可以得到一些候选子图,这些子图可以生成候选的逻辑表示最终选择可以搜索的到正确答案的逻辑表示作为标注逻辑表示指導训练。 

对于没有经过实体链接的训练集本文使用 7 个手工模版,配合知识库将训练集的实体标注出来,然后用这些实体去训练结构化感知机(structrued perceptron)来进行实体消歧 

中间逻辑表示与最终逻辑表示

对于有逻辑表示标注的训练样本,最终逻辑表示(也即匹配了知识库的逻辑表礻)和中间逻辑表示是一样的;而适用于仅仅标注了答案的训练样本的版本的代码解读没有完全给出(一些重要的部分没有再代码解读里實现)这里结合作者引用的另外一文章来讨论可能的具体实现方式。

representation)之间的映射关系:作者给出了一个假设假设两种同样语义的逻輯表示是同构的,也即两种表示的语法树相同只是谓词或者终结符的字符串可能不同。所以在这种假设下两者之间的转换仅仅变成了┅个词汇映射的问题。 

映射关系建模:使用双线性神经网络来刻画中间逻辑表示项 ut(ungrounded term)到最终逻辑表示项 gt(grounded term)的后验概率:

其中为上文提到的以自然语言问题输入为输入的双向 LSTM 的关于某一个中间逻辑表示项的输出;为最终逻辑表示项的嵌入表示,Wug

domain):对于特定领域作者認为中间层的逻辑表示已经可为语义解析提供足够多的上下文信息,可以直接选择对应上述后验概率最大的最终表达作为输出(在特定领域内一个中间表示项一般只匹配一个最终表示项);而对于开放领域,如Freebase这种表示得建模显得有些乏力。 

对于开放领域语义解析本攵设计训练了一个额外的排序模型,对可能的最终表示进行排序取序最靠前的解这个排序模型使用最大熵分类器,以手工设计的关于两種逻辑表示之间的关系的信息表示为特征优化以使得预测的最终逻辑表示在知识库上搜索的到的答案准确率最高。 

目标函数:由于逻辑Φ间表示项是隐变量(latent variable)作者采用最大化逻辑最终表示项的期望对数似然 p(u|x)logp(g|u,x) 的方式来构建优化目标:

结合上文提到的对动作预测的优化目標 La,可以得到最终的优化目标:

目标函数优化:作者采用了另一篇文献优化有隐变量的模型的算法在这篇引用文章中,处理的问题是文夲分类和本文的模型结构类似,有两层结构(涉及到一个生成器和一个编码器生成器生成中间变量),中间连接的变量是隐变量

这篇引用文章的求解任务是想要对文本提取一些原文的片段(对应 gen(?),generate)作为梗概信息(rationales)使得这些梗概信息尽量短的前提下尽可能与原始文本作为输入进行文本分类(对应 enc(?),encode)的效果一致这就涉及到了生成梗概信息的问题,而引用文章的作者又试图想把生成器和编码器一起训练(训练enc(gen(x)))

引用文章的最终的目标函数为:

其中,z,x,y 分别表示梗概信息原始输入以及标注结果;L 惩罚编码器和标注结果的距离,Ω 惩罚中间生成的梗概的长度由于中间项在训练过程中不能被提供,所以作者试图最小化期望损失(相当于把 z 消掉):

其中 θeθg 分別表示编码器和生成器的参数。作者假设用生成器采样中间项对于问题是可行的借助恒等式:

可以求得上述期望损失对两个参数的导数:

这样对 z 使用生成器进行采样,固定 z 就可以求得上述两式里边的微分进而可以求得对期望损失的微分,最后使用梯度优化的算法来更新參数

从两个微分等式可以看出,生成 z可以利用编码器的预测结果指导更新生成器的参数;生成器被优化后,中间项的分布发生了改变又会指导编码器的优化过程,类似于 EM 算法交互更新来学习隐变量的过程

类比引用文章的求解方式,可以假定使用之前提到的双向 LSTM 来对邏辑中间表示项进行采样可以满足问题需求则有:

其中,BiLSTM(x) 为逻辑中间表示的生成器θu 为生成器的参数。

GEOQUERY:关于美国地理的 880 个问题以及知识库并标注有逻辑表示。这些问题句子虽然组合性(compositional)强但语言过于简单,词汇量过于小大多数问题涉及实体不超过一个。

SPADES:包含 93,319 个从数据集 CLUEWEB09 通过随机去除实体获得的问题集合仅仅标注有问题答案。虽然语料的组合性不强但规模很大,并且每个句子包含 2 个或多個实体

WEBQUESTIONS:包含 5810 个问题-答案对。同样组合性不强但问题均来源于真实的网络数据。

本文使用准确率以及 F1 值作为评价指标这里通过计算預测得到的语义表达与真实标注的一致比率来得到。

Table 5:下边隔开的一块内的模型均为神经模型Dong and Lapata (2016) 将语义解析问题视为序列预测问题,使用 LSTM 矗接将自然语言句子映射到逻辑形式 

Table 6:这里之前的工作与本系统处理的总体思路类似,均是将自然语言句子映射到中间逻辑表示然后再匹配知识库 

learning)的思想,提出了一个复杂的基于智能体(agenda-based)的解析器Reddy et al. (2016) 与本文概念上相似,也是通过语义中间表示来训练一个语义解析器其中这个中间表示基于依存关系解析器的输出构建。 

隔开的第二块内的模型为一些神经系统Xu et al. (2016) 在这个数据集上到了目前最好的性能,他們的系统利用维基百科来过滤掉从 Freebase 抽取的错误候选答案 

Table 4:比较的是三个符号系统和一个神经系统基准。

这里进行了一些额外的实验来检驗逻辑中间表示的生成质量

Table 7:作者手工标注了一些逻辑中间表示,以此来观察人的介入对逻辑中间表示的生成效果的影响三行结果分別对应了不同的匹配标准。 

Table 8:为了在其他 3 个数据集上也能够进行类似的实验作者将评价方式换为对比生成的逻辑中间表示与句法分析器汾析结果。作者用 EasyCCG 将自然语言问题句子转换为事件-参数(event-argument)的结构分析看出对于组合性强的数据集

Table 9:展示了一些谓词预测结果的事例,並与 EasyCCG 的结果相对比对于例子:

本文的系统会难以区分控制(control)动词和真正的谓词。

适用于 GEOQUERY 的通用谓词表如下:(还需要再进行扩展才能够使用于通用领域)


点击标题查看更多论文解读: 

▲ 戳我查看招聘详情

PaperWeekly 是一个推荐、解读、讨论、报道人工智能前沿论文成果的学术平囼。如果你研究或从事 AI 领域欢迎在公众号后台点击「交流群」,小助手将把你带入 PaperWeekly 的交流群里

本文假定你已经对有了一定的了解至少使用过属性动画。下面我们就从属性动画最简单的使用开始

相信这段代码解读对你一定不陌生,代码解读中有几个地方是本文Φ将要重点关注的、、在源代码解读中是如何被使用的。另外我们也将重点关注Android中属性动画是如何一步步地实现动画效果的(精确到烸一帧(frame))。最后啰嗦几句本文中使用的代码解读是Android 4.2.2。

上面代码解读的作用就是生成一个属性动画根据ofInt()我们知道只是一个属性值类型为Int嘚View的动画。先放过其他的函数从ObjectAnimator的函数开始。

从代码解读中我们知道它调用了父类的方法,也就是这个方法内部又调用了自身类内蔀的start(boolean playBackwards)方法。

* 可能为true有一点需要注意的是,这个方法必须从UI主线程调用

对代码解读中几个值的解释

mStarted是Animator中一个额外用于标识播放状态的徝,用来指示这个动画是否需要延时执行

这个函数在animation开始前,设置它的初始值这个函数用于设置animation进度为指定时间点。playTime应该介于0到animation的总時间之间包括animation重复执行的时候。如果animation还没有开始那么它会等到被设置这个时间后才开始。如果animation已经运行那么setCurrentTime()会将当前的进度设置为這个值,然后从这个点继续播放

这个函数一看就觉得跟初始化动画有关。这个函数在处理动画的第一帧前就会被调用如果startDelay不为0,这个函数就会在就会在延时结束后调用它完成animation最终的初始化。

values)方法没有介绍官方文档中对这个方法的解释是:构造并返回一个在int类型的values数徝之间ObjectAnimator对象。当values只有一个值的时候这个值就作为animator的终点值。如果有两个值的话那么这两个值就作为开始值和结束值。如果有超过两个鉯上的值的话那么这些值就作为开始值,作为animator运行的中间值以及结束值。这些值将均匀地分配到animator的持续时间

接下来让我们深入ofInt(...)的内蔀看看。

target 就是将要进行动画的对象

propertyName 就是这个对象属性将要进行动画的属性名

values 一组值随着时间的推移,动画将根据这组值进行变化

这个函数其实跟我们前面介绍到的 PropertyValueHolder的构造函数相似,它就是设置动画过程中需要的值如果只有一个值,那么这个值就假定为animator的终点值动画嘚初始值会自动被推断出来,通过对象的getter方法得到。当然如果所有值都为空,那么同样的这些值也会在动画开始的时候也会自动被填上這套自动推断填值的机制只在PropertyValuesHolder对象跟ObjectAnimator一起使用的时候才有效,并且有一个能从propertyName自动推断出的getter方法这些条件都成立的时候才能用不然PropertyValuesHolder没有辦法决定这些值是什么。

接下来我们看到KeyframeSet.ofInt(values)方法这个类持有Keyframe的集合,在一组给定的animator的关键帧(keyframe)中会被ValueAnimator用来计算值这个类的访问权限为包可見,因为这个类实现Keyframe怎么被存储和使用的具体细节外部不需要知道。

在这个方法里面我们看见从最开始的ObjectAnimator.ofInt(target,propName,values[]),也就是我们在文章的开头使用系统提供的动画初始化函数中传入的int数组在这里得到了具体的使用。先不关心具体的使用Keyframe.ofInt(...)从这里我们就可以知道原来Android

从这个构造函数中我们又可以了解到刚刚初始化后的Keyframe数组的第一项和最后一项(也就是第一帧和最后一帧)得到了优先的待遇,作为在KeyframeSet中的字段估計是为了后面计算动画开始和结束的时候方便。

我们绕了很久不知道是否把你弄晕了,这里稍稍总结一下我们就不从调用的顺序一步步分析下来了,太长了我直接说说ObjectValue、PropertyValueHolder、KeyframeSet之间的关系。这三个类比较有特点的地方ObjectAnimator无疑是对的API接口,ObjectAnimator持有PropertyValuesHolder作为存储关于将要进行动画的具体对象(通常是View类型的控件)的属性和动画期间需要的值而PropertyValueHolder又使用KeyframeSet来保存animator从开始到结束期间关键帧的值。这下子我们就了解animator在执行期间用來存储和使用的数据结构废话一下,从PropertyValueHolder、KeyframeSet这个两个类的源代码解读来看这三个类的API的设计挺有技巧的,他们都是通过将具有特定类型嘚实现作为一个大的概况性的类的内部实现通过这个大的抽象类提供对外的API(例如,PropertyValuesHolder.ofInt(...)的实现)

看来这个函数就是调整了一些参数,真囸的处理函数还在animationFrame(...)中我们跟进去看看。

这个内部函数对给定的animation的一个简单的动画帧进行处理currentTime这个参数是由定时脉冲(先不要了解这个萣时脉冲是什么,后面我们会涉及)通过handler发送过来的(当然也可能是初始化的时候被程序调用的,就像我们的分析过程一样)它用于計算animation已运行的时间,以及已经运行分数值这个函数的返回值标识这个animation是否应该停止(在运行时间超过animation应该运行的总时长的时候,包括重複次数超过的情况)

1f)注意到函数里面的这句话,当animator开始需要重复执行的时候那么就需要执行这个if判断里面的东西,这里面主要就是记錄和改变重复执行animator的一些状态和变量为了不让这篇文章太复杂,我们这里就不进行分析了通过最简单的animator只执行一次的情况来分析。那麼接下来就应该执行animateValue(fraction)了

在每一个animator的帧,这个函数都会被调用结合传入的参数:已运行时间分数(fraction)。这个函数将已经运行的分数转为interpolaterd分数然后转化成一个可用于动画的值(通过evaluator、这个函数通常在animation update的时候调用,但是它也可能在end()函数调用的时候被调用用来设置property的最终值)。

Interpolator:鼡来定义animator变化的速率它让基础的动画效果(渐变、拉伸、平移、旋转)有加速、减速、重复等效果。在源代码解读中其实interpolation的作用就是根据某一个时间点来计算它的播放时间分数,具体见。

evaluator: evaluator全部继承至它只有一个。它用来返回你要进行动画的那个属性在当前时间点所需要的屬性值

我们可以把动画的过程想象成是一部电影的播放,电影的播放中有进度条Interpolator就是用来控制电影播放频率,也就是快进快退要多少倍速然后Evaluator根据Interpolator提供的值计算当前播放电影中的哪一个画面,也就是进度条要处于什么位置

通过Interpolator计算出动画运行时间的分数

我们先只关紸if (mNumKeyframes == 2)这种情况,因为这种情况最常见还记的我们使用ObjectAnimator.ofInt(...)传入的int[]数组吗?我们一般就传入动画开始值和结束值也就是这里的mNumKeyframes ==2 的情况。这里通過mEvaluator来计算我们看看代码解读(的代码解读)。

我要回帖

更多关于 代码解读 的文章

 

随机推荐