NLP-Beginner 任务四:基于LSTM+CRF的序列标注+pytorch
- 传送门
- 一. 介绍
- 1.1 任务简介
- 1.2 数据集
- 1.3 原数据解释
- 二. 特征提取——Word embedding(词嵌入)
- 三. 神经网络(LSTM+CRF)
- 3.1 LSTM层
- 3.2 CRF层(条件随机场Conditional Random Field)
- 3.2.1 转移矩阵 T r a n Tran Tran
- 3.2.2 CRF(最困难的部分)
- 3.2.2.1 真实得分——对应CRF.true_prob
- 3.2.2.2 全部得分——对应CRF.total_prob(难点)
- 3.2.2.3 Loss
- 3.2.2.4 预测序列——对应CRF.predict(难点)
- 四. 代码及实现
- 4.1 实验设置
- 4.2 结果展示
- 五. 总结
- 六. 自我推销
传送门
NLP-Beginner 任务传送门
我的代码/数据集传送门
原数据集介绍传送门
特征提取预训练模型
主要参考论文:Neural Architectures for Named Entity Recognition
辅助参考论文:End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF
一. 介绍
1.1 任务简介
本次的NLP(Natural Language Processing)任务是对一个英文句子进行序列标注,例子如下
1.2 数据集
我的代码/数据集传送门
原数据集介绍传送门
例子:
原数据:
EU NNP B-NP B-ORG
rejects VBZ B-VP O
German JJ B-NP B-MISC
call NN I-NP O
to TO B-VP O
boycott VB I-VP O
British JJ B-NP B-MISC
lamb NN I-NP O
. . O O
输入文本: EU rejects German call to boycott British lamb.
输出序列: B-ORG O B-MISC O O O B-MISC O O原数据:
Peter NNP B-NP B-PER
Blackburn NNP I-NP I-PER
输入文本: Peter Blackburn
输出序列: B-PER I-PER
1.3 原数据解释
The first item on each line is a word, the second a part-of-speech (POS) tag, the third a syntactic chunk tag and the fourth the named entity tag.
每行第一项是单词,第二项是POS标签,第三项是语法块标签,第四项是命名实体标签,也就是我们本次的任务。
具体命名实体的每一个标签代表的意思,可以参考原数据集介绍。
数据集共有三个文件:train.txt, test.txt 和 dev.txt。由于文件数据的组织方式比较松散,因此需要预处理,并且需要去掉文件中所有的:-DOCSTART- -X- -X- O(代表某一个文档开始)
二. 特征提取——Word embedding(词嵌入)
请参考NLP任务二
本次实战除了给定的各种序列类别之外,还要另外多加3个类别,分别是: < pad >,< start >,< end >,分别代表padding(即补位,使句子达到同一个长度),句子开头和句子结尾,总共C类标签。
三. 神经网络(LSTM+CRF)
本部分详细内容可以参考论文:Neural Architectures for Named Entity Recognition
3.1 LSTM层
3.2 CRF层(条件随机场Conditional Random Field)
3.2.1 转移矩阵 T r a n Tran Tran
注意:
- 句子开头< start >不可能到达< start >
- < end >代表句子结尾,不能再转移
- -< pad > 表示padding(即补位,使句子达到同一个长度)也只能转移到< pad >。
3.2.2 CRF(最困难的部分)
首先我们先明确一下目标,在LSTM层过后我们得到了得分矩阵,我们还要从输入得到一个loss(损失),从而优化整个网络的参数,而从得到loss的中间部分则是CRF层。
对于每一个句子,需要计算的数值如下:
- 真实得分:对真正序列的得分
- 全部得分:对于所有序列的得分
- softmax得分:,这个得分越高,就证明真正序列y的得分占比越大,而其它所有序列的指数加和占比越小,也就是说我们的模型更加正确。
- Loss:loss一般是越小越好,而softmax得分是越大越好,且比值方式可以利用性质变成减法,因此取得分
3.2.2.1 真实得分——对应CRF.true_prob
有 和 可以直接计算,非常简单,求和即可。
3.2.2.2 全部得分——对应CRF.total_prob(难点)
我们可以看到,我们需要计算所有序列的得分,如果一个句子的长度为,一共类标签,那么我们就有种情况需要遍历,这个复杂度是非常高的,代价非常大,因此参考了网上的方法,采用动态规划(DP)的思想进行计算(非常难以理解)。
具体请参考代码。
3.2.2.3 Loss
直接计算
3.2.2.4 预测序列——对应CRF.predict(难点)
除了训练网络参数,我们还需要进行预测,以在测试集上进行测试。
预测无非就是在所有序列得分中找到最大得分的序列,因此一开始的想法是遍历种情况,但显然复杂度非常高,因此采用非常常见且高效的动态规划算法——viterbi算法(建议先了解算法本身)。
具体请参考代码。
四. 代码及实现
4.1 实验设置
- 样本个数:train.txt与test.txt
- 训练集:测试集 : train.txt与test.txt
- 特征提取:Random / GloVe Embedding
- 学习率:10-3
- :50
- Batch 大小:128
- 训练轮数:50
4.2 结果展示
指标:单个句子的标注正确率的平均
比如:一个句子无论多少个词,只有标全对了,才记为1分,否则0分。
可以看到GloVe初始化比随机初始化明显地好,标注正确率随机最多只有55%,而GloVe最高能到76.23%,性能比较好。
五. 总结
自己编写CRF难度是非常大的,因此建议多去网上寻找相关的讲解,还有一种“逃课”的方法是,直接调包,好像pytorch是有现成的CRF包的,直接调用可以解决许多问题。
标注正确率不到80%其实不太高,模型有待改进,比如增大,更精确的指标可以参考原本论文的指标。
以上就是本次NLP-Beginner的任务四,全文难点在于全部得分和预测序列,需要多加琢磨。
谢谢各位的阅读,欢迎各位对本文章指正或者进行讨论,希望可以帮助到大家!
六. 自我推销
- 我的代码&其它NLP作业传送门
- LeetCode练习