【云驻共创】基于转移的语义Parser分享

语义依存分析是NLP中十分经典的任务 。 它可以分析一个自然语言句子中的语言单位成分之间的依存关系 。 得到的依存关系可以应用在NLP下游的任务中 。 比如机器翻译 , 事件抽取 , 语义角色标注等等 。


本文分为下面几个部分 :

  • 论文解读
    • 什么是语义分析 , 介绍常用方法 。
  • 代码复现
    • 拆分讲解代码关键点 。
  • 使用方法介绍
    • 在ModelArts上实操 。

论文解读

论文基本信息

《A Neural Transition-Based Approach for Semantic Dependency Graph Parsing》

AAAI-18 (The Association for the Advance of Artificial Intelligence)


作者

YuXuan Wangl yxwang@ir.hit.edu.cn

Wanxiang Che* car@ir.hit.edu.cn


哈尔滨工业大学SCIR实验室 http://ir.hit.edu.cn/

http://people.csail.mit.edu/jiang_guo/papers/aaai2018-nnsdp.pdf


研究背景

依存句法分析

关注句子的语法结构 。 比如主谓宾 , 定状补 。


依存语义分析

关注句子深层的语义信息 。 跨过语法结构 , 直接获取更深层次的语义信息 。

这个例子是一份分析结果 。 上面的是依存句法分析 , 下面是依存语义分析 。


依存句法分析 中 :

  • “在餐厅”和“用勺子”都是状语 。
  • “喝”是谓语 。
  • “我”是主语 。
  • “玉米汤”是宾语 。


句法parsing是要解析得到一个句法树 。 更关注句法结构 。 句法结构中有一个父节点 , 它是树结构 。


依存语义分析

“餐厅”、“勺子”都是“喝”的论元 。 “餐厅”指的是地点 , “勺子”指的是工具 。

需要关注的是 , 语义依存是图结构 , 而不是树结构 。 它的每个节点可能会有多个头 。 一个单词在句子中可能会作为多种成分 。


语义依存图

这个例子中 , 主要的英文数据集有DM、PAS、PSD、EDS、UCCA、AMR 。

DM和PSD比较类似 , 都以词为节点 。

EDS与UCCA比较像 , 都以语义片段为节点 。

AMR有一些抽象的语义表示 。

可以在这里看到详细说明 :http://mrp.nlpl.eu/2019/index.php?page=4#training


在本篇论文复现中,实验的中文数据集是SemEval-2016 Task 9中的TEXT和NEWS 。

这两个是中文数据集 。 参考 :https://github.com/HIT-SCIR/SemEval-2016

上面蓝色的是依存句法分析 , 下面紫色的是依存语义分析 。


我们看下面紫色的是依存语义分析 :

“小丽”同时作为“帮助”和“学习”这两个谓词的论元 。 导致“小丽”有两个头节点 。


转移系统

转移算法: List-based Arc-eager算法(Choi and McCallum 2013)


如上图所示 , 需要用 2 个栈 , Stack和Buffer 。 还有一个队列 。

有 7 种转移动作对栈和队列进行操作 , 来标记出一个完整的语义依存图 。


转移动作:

1) LEFT-REDUCE

2) RIGHT-SHIFT

3) NO-SHIFT

4) NO-REDUCE

5) LEFT-PASS

6) RIGHT-PASS

7) NO-PASS


转移动作中 , 横杠 「-」 前后表示的是不同的操作 。

前面指的是要产生什么样的弧 。

后面指的是如何操作栈和队列 。


前半部分有 :

LEFT: 从Stack栈顶和Buffer头部产生一个向左的弧

RIGHT: 从Stack栈顶和Buffer头部产生一个向右的弧

NO: 不产生弧


后半部分有 :

REDUCE: 销毁Stack栈顶数据

SHIFT: Buffer头部数据拿出来压入Stack栈顶

PASS: Stack拿出栈顶放入Deque中


词嵌入(Word Embedding)

词向量:100维+预训练词向量( 对模型性能提升很大 )

字向量:50维

词性:50维

lemma :50维

其它:词向量扩充词典;shuffle;dropout;随机初始化等调优操作

编码层

在转移系统中的对每一步进行编码 。

如下图 , 上部分图里Stack有 3 个词 , Buffer里有 2 个 。 模型需要知道现在的情况才能输出 。 对Stack 、 Deque和Buffer进行编码 。



编码层 : Buffer

上图是 Bi-LSTM Subtraction的编码过程

在论文中介绍了 Bi-LSTM Subtraction模块 。 Buffer中是一个连续的完整的单词串 , 先用Bi - LSTM编码整个句子 。



编码层 : Stack

RecNN 递归神经网络

在处理较深的子结构时可能会出现梯度消失问题 。

本篇论文提出用 Tree-LSTM 对子结构进行建模 。


Tree-LSTM 能合并节点和子节点 。


建模的子结构不一定是树 。 依存图中不存在环 , 我们能够使用LSTM 。

基于转移的依存分析中 , 我们可以一个个找到节点 ( 弧 )。


Tree-LSTM的编码过程


每当找到一个新的节点 , 把它们合并 。 如上图 (1), a+b来作为原来A的代表 。

Tree-LSTM用这种方法把标记出来的结构进行编码 。


编码层 : Deque和Action

Stack LSTM:拥有pop、push等栈操作,可以动态计算LSTM


参考论文


论文:Transition-Based Dependency Parsing with Stack Long Short-Term Memory

论文地址: https://aclanthology.org/P15-1033/


论文:Parallelizable Stack Long Short-Term Memory

论文地址:https://aclanthology.org/W19-1501/



总体结构


上图是模型的总体结构 。

左边是Stack ; buffer是右边 ; 下面是队列和转移动作 。

把它们的整个表示用向量进行拼接 。 把得到的全部表示用线性压缩增加激活函数 。 最后预测概率 。


但这种编码方式会有错误传播的问题 。 后文会提到 。


评价指标

有 4 种评价指标 。 先看F值的说明


以下是 4 种指标 :

LF(labeled F-score) 带标签的F值

UF(unlabeled F-score) 不带标签的F值

NLF(non-local dependencies LF) 多头结点的LF值

NUF(non-local dependencies UF) 多头结点的UF值


LF比UF更加严格 , 弧和标签都要预测对 。



实验

第一行都是baseline 。

+ BS行的结果能比baseline高零点几 。 在NUF项提升很大 。

+ IT的结果表现也比baseline好 。

+ BS & IT是两个模块都用 , 各个指标都有了不小的提升 。

我们认为是对模块提供了很多结构信息 , 多头结点的弧预测提高了很多 。


需要注意的是 , TEXT中 + IT的NUF项反而降低了 。


上表是解码速度 , 单位是 tokens/s, 可以和其他转移方法进行比较 。

可以看出 , 添加了BS或者IT后 , 解码速度会降低 。


其他 基于图方法

BiAffine Parser


图方法是一个端到端的方法 。 从输入层直接送到编码层 。 编码层可以是SelfAtt也可以是BiLSTM 。 输出的隐藏层直接送到MLP中压缩 。 再用 B iaffine进行打分 。

非常适合大矩阵运算 。 图方法适合深度学习时代 。



其它:Batch化困难

基于转移的语义分析 , 准确率比图方法稍差 。 难用上大规模矩阵操作 , 训练推理速度非常慢 。


原因:

1. 同一个batch中的各个转移动作不一致

2. 各个句子的转移动作序列长度不一致 ( 每个句子不能使用同样的矩阵操作 )



错误传播

错误产生后 , 离正确结果偏移的越来越远 。 一种解决方法是采用Dynamic oracle进行训练。

一般来说转移路径都是用static oracle ( 静态 ) 来训练 。 出现错误的话 , 得到的结果会偏离 。

用Dynamic oracle进行训练 。

在训练时加入一些模型同位的状态 , 让模型去适应真实场景 。 即训练过程中加入噪声 。

其它 栈指针方法

Transition-based Semantic Dependency Parsing with Pointer Networks.

2020 ACL.

代码复现

初始化

3 个依赖包

  • AllenNLP:数据载入
  • MoXing:与OBS存储交互
  • PyTorch:深度学习框架


依赖包的官网

  • AllenNLP: https://docs.allennlp.org/main/
  • MoXing: https://support.huaweicloud.com/moxing-devg-modelarts/modelarts_11_0002.html
  • PyTorch: https://pytorch.org/


AllenNLP不能直接加载 , 要用代码加载一下 , 可能涉及到权限问题 。


ModelArts上可能会遇到路径问题 。 按照ModelArts指定的目录来存放数据 。

/home/work/modelarts/inputs/SDP_data

/home/work/modelarts/outputs/SDP_output/


编码层


解码层

贪心解码


计算当前分值:

得到 4 个表示 :stack_emb, buffer_emb, action_emb, deque_emb

把它们用 torch.cat 进行拼接得到向量 p_t, 用 tanh 函数进行压缩

LOSS




基于ModelArts实操演示

首先在AiGallery上订阅算法 。

案例指导 : https://bbs.huaweicloud.com/forum/thread-92854-1-1.html


简要流程如下 :

  • 订阅算法后 , 可以在算法管理中找到已订阅的算法 。 可以创建训练作业 。 把OBS的路径进行设置 。
  • 开始训练 。 能看到运行成功的状态 。 在模型管理中 , 把刚才创建好的模型导入 。
  • TEXT训练时间比NEWS稍微多一些 , NEWS训练集比较小 。
  • 部署 。 搭建起一个服务 。


以下是几个步骤的截图 :

https://marketplace.huaweicloud.com/markets/aihub/modelhub/detail/?id=0e7f6c71-e289-4737-8709-d0af17e789f5




准备数据集

https://github.com/HIT-SCIR/SemEval-2016


安装OBS

https://support.huaweicloud.com/browsertg-obs/obs_03_1003.html



创建桶


订阅算法 , 图中是已订阅状态




在算法管理中找到语义分析


创建训练作业







部署



部署时 , 可以选择 「 在线服务 」 或者 「 批量服务 」。 实操演示完成 。


总结

语义依存分析是NLP中十分经典的任务 。 通过读论文 , 我们了解依存语法分析和依存语义分析的特点和不同点 ; 了解转移系统的原理 。 用代码进行了复现 。 最后在ModelArts上进行训练得到模型 , 并部署了在线服务 。

(完)