语义依存分析是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://github.com/HIT-SCIR/SemEval-2016
安装OBS
https://support.huaweicloud.com/browsertg-obs/obs_03_1003.html
创建桶
订阅算法 , 图中是已订阅状态
在算法管理中找到语义分析
创建训练作业
部署
部署时 , 可以选择 「 在线服务 」 或者 「 批量服务 」。 实操演示完成 。
总结
语义依存分析是NLP中十分经典的任务 。 通过读论文 , 我们了解依存语法分析和依存语义分析的特点和不同点 ; 了解转移系统的原理 。 用代码进行了复现 。 最后在ModelArts上进行训练得到模型 , 并部署了在线服务 。