配置代码样式

Thursday, April 23, 2020

基于transformers、TensorFlow和Bert实现POS

基于transformers框架使用TensorFlow和Bert实现中文词性标注任务

上篇文章基于ALBERT实现中文NER讲述了如何使用https://github.com/google-research/albert/albert实现中文NER任务,这次使用一个awsome的框架(由huggingface开发的transformers)实现POS任务。
由于NER和POS都可以看作序列标注任务,所以实现思路上挺相似的。

声明

本文仅技术性分享,可以在google colab引入这份how_to_run.ipynb文件从零打造一款中文词性标注工具。里面包含文本数据的收集、数据预处理、模型训练到自定义句子测试等。对想熟悉深度学习的NLP新人应该是一份不错的入门实战经验。

数据搜集

本文使用1998人民日报数据集(仲多下载资源之一),请根据自身情况更换数据。使用其他领域的数据、甚至其他语言等数据都没问题的。

数据预处理

由于每个数据文本的格式各不相同,如该1998人民日报数据集每行开头都有一段明显不是人民日报原文的文字:
19980101-01-001-002/m  中共中央/nt  总书记/n  、/w  国家/n  主席/n  江/nr  泽民/nr  
19980101-01-001-003/m  (/w  一九九七年/t  十二月/t  三十一日/t  )/w  
因此,我们需要对数据集做一些预处理,统一格式后扔给机器训练模型。

词性符号

本人从网上整理了一些词性翻译表(不齐全),仅作为参考:
标签含义标签含义标签含义标签含义
n普通名词f方位名词s处所名词t时间
nr人名ns地名nt机构名nw作品名
nz其他专名v普通动词vd动副词vn名动词
a形容词ad副形词an名形词d副词
m数量词q量词r代词p介词
c连词u助词xc其他虚词w标点符号

统一数据集格式

该数据集虽然标识了词性,比如 中共中央/机构名, 总书记/名词,但机器自身并不知道一个句子,哪些字是一块的,所以人们定义了IOB标注模式(还有其他模式,如BMES等),标注句子中这个字是属于一个词的开头还是之中。
IOB,是inside,outside,begging缩写,其中B表示一个词的开头、I表示一个词的中间、O表示这个字不属于任何一块。
例如"中共中央总书记、国家主席江泽民",使用IOB标注后:
中 共 中 央 总 书 记 、 国 家 主 席 江 泽 民
B I I I B I I O B I B I O B I
这样机器就知道中共中央总书记是一个词了。

处理后的格式

我们最终的数据集格式是每行只包含一个字和对应的标识符(空格隔开),每个句子之间有一个空行区分:
中 O-NT
共 I-NT
中 I-NT
央 I-NT
总 B-N
书 I-N
记 I-N
、 O-W
国 B-N
家 I-N
主 B-N
席 I-N
江 O-NR
泽 B-NR
民 I-NR

( O-W
一 B-T
九 I-T
九 I-T
七 I-T
年 I-T
十 B-T
二 I-T
月 I-T
三 B-T
十 I-T
一 I-T
日 I-T
) O-W
这里每个字对应的标识符是BIO和词性的结合,如国家的国是这个词的开头,所以是B,因为是名词,所以是N,因此标识符就是B-N。

模型框架

深度学习用到的框架有很多,这里就用transformerstensorflow上搭建bert-pos模型吧。
代码已经上传到Github,欢迎各位吐槽。代码内容不多,熟悉TensorFlow的各位应该很快就知道运作原理了。不熟悉TensorFlow也没关系,官方已经提供足够的教程文档了,我就是从官方文档学习的。

测试结果

使用原模型参数训练1998人民日报语料库3个epochs,评测结果如下:
           precision    recall  f1-score   support

        N     0.9471    0.9542    0.9507     15824
        V     0.9287    0.9309    0.9298      9043
        A     0.9082    0.9228    0.9155      1684
       NR     0.9651    0.9677    0.9664      1486
        C     0.9002    0.9410    0.9202       441
       VN     0.8428    0.9038    0.8723      2735
        F     0.9423    0.9849    0.9631       398
        R     0.9821    0.9848    0.9834      1448
        B     0.8824    0.9071    0.8946       463
       NS     0.9296    0.9383    0.9339      2447
        J     0.7931    0.8125    0.8027       368
        L     0.4667    0.6609    0.5471       466
        T     0.9851    0.9874    0.9863      2145
       NT     0.9103    0.9511    0.9303      1003
        D     0.9246    0.9572    0.9406      1307
        M     0.9778    0.9857    0.9817      1609
        U     0.8108    1.0000    0.8955        30
        P     0.9031    0.8662    0.8843       269
        Q     0.9347    0.9841    0.9588       189
       NX     0.6757    0.9615    0.7937        26
       AD     0.9298    0.9636    0.9464       330
        Z     0.7532    0.8264    0.7881       144
       NZ     0.5942    0.6833    0.6357       180
        I     0.7780    0.8178    0.7974       450
       AN     0.8130    0.8288    0.8208       257
        S     0.8721    0.9091    0.8902       330
        W     0.8989    0.9302    0.9143        86
       VD     0.6471    0.6875    0.6667        32
        O     0.0000    0.0000    0.0000         7
        Y     0.4000    0.3333    0.3636         6

micro avg     0.9217    0.9395    0.9305     45203
macro avg     0.9243    0.9395    0.9315     45203
另外,我在github上提供了交互测试工具:terminal_predict.py注:运行该工具需要各位完成模型训练或email我获取相关pre-training model文件。里面其实就是一个循环,用户输入句子,程序输出对应的词性。以下列出一些测试结果:

新闻类测试:

当我整理这份分享教程时,我随便拿当天新闻做测试,并不是拿人民日报的内容:
  • 武汉动物园有序开放。
    • ['武汉动物园/B-NS', '有序/B-AD', '开放/B-V', '。/O-W']
  • 如今中国在建造隧道时遇到困难,三年时间只挖了4米,看到这里印度表示嘲笑,居然有中国完成不了的工程。
    • :['如今/B-T', '中国/B-NS', '在/O-P', '建造/B-V', '隧道/B-N', '时/O-NG', '遇到/B-V', '困难/B-AN', ',/O-W', '三/O-M', '年/O-Q', '时间/B-N', '只/O-D', '挖/O-V', '了/O-U', '4/O-M', '米/O-Q', ',/O-W', '看到/B-V', '这里/B-R', '印度/B-NS', '表示/B-V', '嘲笑/B-V', ',/O-W', '居然/B-D', '有/O-V', '中国/B-NS', '完成/B-V', '不/O-D', '了/O-V', '的/O-U', '工程/B-N', '。/O-W'] 
  • 最重要的是黄河这么多年来,水下的黄沙非常多,常年在水中,河床也非常松弛。
    • :['最/O-D', '重要/B-A', '的/O-U', '是/O-V', '黄河/B-NS', '这么/B-R', '多/O-M', '年/O-Q', '来/O-F', ',/O-W', '水下/B-S', '的/O-U', '黄沙/B-N', '非常/B-D', '多/O-A', ',/O-W', '常年/B-D', '在/O-P', '水中/B-S', ',/O-W', '河床/B-N', '也/O-D', '非常/B-D', '松弛/B-A', '。/O-W']

游戏类的评论测试:

随便从NGA进了一个讨论帖:
  • 本体没刷,今天刷了一天一把弓都炼不出来心态已经有点崩了,哪有那么大功夫在这抽卡,但是差距又这么明显,悲
    • ['本体/B-N', '没/O-D', '刷/O-V', ',/O-W', '今天/B-T', '刷/O-V', '了/O-U', '一/O-M', '天/O-Q', '一/O-M', '把/O-Q', '弓/O-N', '都/O-D', '炼/O-V', '不/O-D', '出来/B-V', '心态/B-N', '已经/B-D', '有点/B-D', '崩/O-V', '了/O-Y', ',/O-W', '哪/O-R', '有/O-V', '那么/B-R', '大/O-A', '功夫/B-N', '在/O-P', '这/O-R', '抽/O-V', '卡/O-N', ',/O-W', '但是/B-C', '差距/B-N', '又/O-D', '这么/B-R', '明显/B-A', ',/O-W', '悲/O-VG']
  • 我还做了一下真属会属解的凯罗弓,凯罗雷属解真属会也挺强的,就是配装很别扭
    • ['我/O-R', '还/O-D', '做/O-V', '了/O-U', '一下/B-M', '真属会/B-N', '属解/B-N', '的/O-U', '凯罗弓/B-N', ',/O-W', '凯/B-NR', '罗/I-N', '雷/I-NR', '属解/B-N', '真属会/B-N', '也/O-D', '挺/O-D', '强/O-A', '的/O-U', ',/O-W', '就是/B-D', '配装/B-V', '很/O-D', '别扭/B-A']
  • 据说刚射每一根差5点左右(帝王金各个属性有点差别),你等苍星应该也没用,苍星比现在银火多出的那些技能也拉不平那么多属性
    • ['据说/B-V', '刚/O-D', '射/O-V', '每/O-R', '一/O-M', '根/O-Q', '差/O-V', '5点/B-M', '左右/B-M', '(/O-W', '帝王金/B-N', '各个/B-R', '属性/B-N', '有/O-V', '点/O-Q', '差别/B-N', ')/O-W', ',/O-W', '你/O-R', '等/O-V', '苍星/B-N', '应该/B-V', '也/O-D', '没用/B-A', ',/O-W', '苍星/B-N', '比/O-P', '现在/B-T', '银/B-N', '火/O-N', '多/O-AD', '出/O-V', '的/O-U', '那些/B-R', '技能/B-N', '也/O-D', '拉/O-V', '不/O-D', '平/O-V', '那么/B-R', '多/O-A', '属性/B-N']

测试结果

本文重点是如何从零打造一个POS程序,从上面可以看出做对应领域的POS还是挺准的,但做其他领域的POS就稍微有些尴尬了,比如银火是个名词,这里程序预判是名词、名词😅。不过像真属会属解凯罗弓倒没预判错误😏。

参考资源

Sunday, April 19, 2020

基于ALBERT实现中文NER

基于ALBERT实现中文NER,提供测试代码和数据资源

声明

本文仅技术性分享,该模型google colab上能正常运行。如需转载,请注明来源。

什么是NER

命名实体识别,英语名称:Named Entity Recognition,简称NER,是指从文本中识别某类意义的实体,实体类型包含并不限于人名、地名、机构名、专有名词、时间、数量、货币、比例数值等文字。从非结构化文本(如新闻文章等)识别某些实体类型。
比如:
美国的华莱士,我和他谈笑风生。
经过NER处理后(输出格式视情况而定,这仅仅是个例子):
{
  "地区": [
    "美国"
  ],
  "人物": [
    "华莱士"
  ]
}

为什么需要NER

NER是NLP(自然语言处理)中一项关键任务。在信息检索、关系抽取、事件抽取、自动文本摘要、知识图谱、机器翻译、问答系统等NLP任务提供帮助。这里暂不详述,请另行研究。

NER实现方法

  • 采取自定义规则 - 依赖人工定制规则,一般基于句法、语法、词汇以及特定领域的知识等。设计好的规则一般无法套用其他领域。
  • 采取无监督学习 - 如使用聚类方式可以根据语义相似度,从聚集抽取命名实体。但需要巨大的语料库得到词汇资源。
  • 基于特征值采取监督学习 - 将NER任务视为序列标注任务,使用标注好的数据、特定领域知识和设计特征提取训练数据样本,将特征值用于训练机器学习模型使其学习规则。
  • 采取深度学习 - 深度学习具有非线性转转特点,在不需要复杂的特征工程上学习更复杂的特征。
本文采取深度学习方法

本文深度学习架构

本文采取ALBERT + BiLSTM + CRF架构实现NER任务,本文将以下代码拆分几部分:
  • 项目代码、训练数据、测试数据准备
  • 模型训练
  • 数据测试

项目代码、训练数据、测试数据准备

https://github.com/grallage/ALBERT-BiLSTM-CRF-NER已经包含简单的训练、测试样本,和模型训练、模型测试脚本,chinese model需另行下载(见Download chinese model)。

项目结构

|____albert-lstm-crf-ner
| |____lstm_crf_layer.py    定义LSTM & CRF layer
| |____run_ner.py           训练ner model
| |____optimization.py      
| |____tokenization.py      
| |____terminal_predict.py  预测测试
| |____README.md
| |____requirement.txt
| |____modeling.py          定义albert模型
| |____data                 train、eval、predict dataset
| | |____dev.txt
| | |____train.txt
| | |____test.txt

Download chinese model

https://github.com/google-research/albert,google官方已经提供资源。

运行模型

可以上传该ipynbgoogle colab,然后逐行运行即可。免除部署和硬件性能烦恼。

训练模型

python /content/ALBERT-BiLSTM-CRF-NER/run_ner.py \
    --task_name ner \
    --do_train true \
    --do_eval true \
    --data_dir /content/ALBERT-BiLSTM-CRF-NER/data \
    --vocab_file /content/albert_base/vocab_chinese.txt \
    --bert_config_file /content/albert_base/albert_config.json \
    --max_seq_length 128 \
    --train_batch_size 64 \
    --learning_rate 2e-5 \
    --num_train_epochs 2 \
    --do_predict true \
    --init_checkpoint /content/albert_base/model.ckpt-best \
    --output_dir /content/albert_base_ner_checkpoints
其中/content/ALBERT-BiLSTM-CRF-NER存放该项目代码和dataset,/content/albert_base存放chinese model,/content/albert_base_ner_checkpoints存放checkpoint相关数据,可根据自身情况更改。

测试模型

python /content/ALBERT-BiLSTM-CRF-NER/terminal_predict.py

源码分析

该项目核心是参考下方资源进行改动,run_ner.py是参考run_classifier.py改动的。若想阅读研究源代码,需要对TensorFlow的estimator有一定的熟悉,具体请参考官方或其他网站。

参考资源