自然语言处理(NLP):22 BERT中文命名实体识别

本文主要通过不同的数据集来进行 NER 模型验证验证,以及指定一些通过训练 NER 任务的一套标准,通过两条路线进行分析和总结。
(1)工业界场景-> 学术界 NER 论文-> BERT 实现 NER 方案以及源码分析
(2)预料数据-> 业务数据可视化分析-> 标准数据格式转换-> 模型训练-> 在线预测-> 序列标准任务优化和拓展

作者:走在前方
博客:https://wenjie.blog.csdn.net/
学习交流群:更多精彩内容加入“NLP技术交流群” 学习
专注于文本分类、关键词抽取、文本摘要、FAQ 问答系统、对话系统语义理解 NLU、知识图谱等。结合工业界具体案例和学术界最新研究成果实现 NLP 技术场景落地。


本文主要分享核心要点

  • 命名实体识别初识
    • 什么是 NER
    • NER 发展以及技术方案
  • 工业界应用场景
    • 人力资源检索系统
    • 电子病历系统
    • 聊天机器人对话系统
    • 其他(某团语音平台,某米音箱。。)
  • 学术界论文方案解读
    • BiLSTM-CRF
    • Att-BiLSTM-CRF
    • BERT
    • BERT-CRF
  • BERT 源码分析
    • 词潜入历史发展 word2vec、glove、ELMo、BERT
    • BERT 模型详细介绍
    • BERT 模型演变
  • NER 项目前准备工作
    • 数据库分析可视化 pyecharts、seaborn、matplotlib
    • NER 项目 CRF 模块
    • transformer 模型模块
    • NER 评估模块
  • 不同数据集实验
    • 案例 1:CoNLL2003 经典 NER 入门项目
    • 案例 2:航空旅游项目
    • 案例 3:新闻数据项目
    • 案例 4:NLP 比赛 音乐领域 NER 项目
    • 案例 5: 中文分词以及词性标注

命名实体识别初识

Named-entity recognition (NER) (also known as entity identification, entity chunking and entity extraction)

命名实体识别(Named Entity Recognition,简称 NER),又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。简单的讲,就是识别自然文本中的实体指称的边界和类别。

一些研究也涉及电影名、书名、项目名、研究领域名称、电子邮件地址、电话号码以及生物信息学领域的专有名词(如蛋白质、DNA、RNA 等)。甚至有一些工作不限定“实体”的类型,而是将其当做开放域的命名实体识别和分类。

NER 一直是 NLP 领域中的研究热点,从早期基于词典和规则的方法,到传统机器学习的方法,到近年来基于深度学习的方法,NER 研究进展的 大概趋势大致如下图 所示。

图片

工业界应用场景

简历自动检索系统

https://dataturks.com/blog/named-entity-recognition-in-resumes.php

图片

图片

人力资源检索系统,可以通过 NER 来完成,从三个方面提供给我们一些思路

1。简历自动汇总

2。优化搜索引擎算法

3。强大的推荐系统

4。简化客户支持

  • 简历自动汇总

图片

各公司人力资源部面临的一个关键挑战是评估一大堆求职者的简历。为了增加他们的亮点,申请者往往过于详细化他们的简历,其中大部分信息与评估者所寻求的无关。为了简化这一过程,通过我们的 NER 模型,我们可以方便地对简历进行快速评估,从而简化在一堆简历中筛选候选人所需的工作。

  • 优化搜索引擎算法

图片

为了设计一种搜索引擎算法,而不是在数百万篇在线文章和网站上搜索输入的查询,一种更有效的方法是对文章运行一次 NER 模型,并永久存储与之相关的实体。然后,可以将搜索查询中的关键标记与与网站文章关联的标记进行比较,以实现快速高效的搜索。

  • 强大的推荐系统

图片

NER 可用于开发推荐系统的算法,自动过滤我们可能感兴趣的相关内容,并据此指导我们根据以前的行为发现相关和未访问的相关内容。这可以通过提取与我们的历史或以前活动中的内容相关联的实体,并将它们与分配给其他未公开内容的标签进行比较,以筛选相关的实体来实现。

  • 简化客户支持

图片

NER 可用于识别客户投诉和反馈中的相关实体,如产品规格、部门或公司分支机构的详细信息,以便对反馈进行相应分类,并转发给负责识别产品的相应部门。

电子病例命名实体识别

电子病历结构化是让计算机理解病历、应用病历的基础。基于对病历的结构化,可以计算出症状、疾病、药品、检查检验等多个知识点之间的关系及其概率,构建医疗领域的知识图谱,进一步优化医生的工作. 对于给定的一组电子病历纯文本文档,识别并抽取出其中与医学临床相关的实体,并将它们归类到预先定义好的类别中。例如,我们可以识别含解剖部位、独立症状、症状描述、手术和药物等实体。

图片

举例说明,根据病例描述抽取信息:

  • 输入数据

女性,88 岁,农民,双滦区应营子村人,主因右髋部摔伤后疼痛****肿胀,活动受限 5 小时于 2016-10-29;11:12 入院。

  • 输出结果

右髋部 21 23 身体部位

疼痛 27 28 症状和体征

肿胀 29 30 症状和体征

聊天机器人的对话系统

图片图片图片

图片图片

对话系统在聊天机器人中应用以及发展历史

  • 1950: Turing Test
  • 1966: ELIZA, MIT chatbot
  • 1995: ALICE, pattern recognition chatbot
  • 2011-2012: Siri, Watson, Google Assistant
  • 2015: Amazon Alexa, Microsoft Cortana
  • 2016: Bot 元年:Microsoft Bot Framework, FB Messenger, Google Assistant …
  • 2017: 百度度秘,腾讯云小微,阿里小蜜 …

对话系统主要包括三个方面的内容

  • NLU 自然语言理解

对话系统中语义理解部分主要包括:领域分类、意图识别和槽位抽取。

领域分类:针对一个 query 的短文本分类

意图识别:也可以看成文本分类问题

槽位抽取:可以看成 NER 技术领域的问题

  • 领域分类

例如: 音乐、天气、指令。。。。

  • 意图识别(slot filling)

对于音乐来说,比如:播放,暂停,下一首等。。。

  • 槽位填充(命名实体识别)

例如: 播放一周周杰伦东风破。 {‘singer’:’'周杰伦 ,‘song’:'东风破 '}

  • DM 对话管理
  • NLG 自然语言生成

2018 年 Alexa Prize Challenge 亚马逊举办的聊天机器人大赛

2018 年冠军** **

Gunrock: Building A Human-Like Social Bot By Leveraging Large Scale Real User Data

图片

系统的整体架构

图片

学术界论文方案解读

BiLSTM-CRF vs Att-BiLSTM-CRF 论文

BiLSTM-CRF 论文

Attention+BiLSTM-CRF 论文

BiLSTM-CRF baidu

图片

Att-BiLSTM-CRF

图片

接下来我们重点看下 Att-BiLSTM-CRF 这篇论文,我们重点了解。

其中: 论文的代码

  • attention 的计算方法

https://github.com/lingluodlut/Att-ChemdNER/blob/81db44f5cbd5bbbb1d1dee72a528280425de7bc9/src/nn.py#L628

  • Att-BiLSTM-CRF VS 其他模型效果对比

该论文中提供了4个计算attention 的方法

图片

四种计算 attention 方法对比效果

图片

其他模型 VS Att-BiLSTM-CRf 对比

图片

BiLSTM-CRF VS Att-BiLSTM-CRF 架构

图片

The architectures of BiLSTM-CRF model and our Att-BiLSTM-CRF model.

(A) The basic BiLSTM-CRF model.

(B) Our Att-BiLSTM-CRF model. In the models, the BIO (Begin, Inside, Outside) tagging scheme are used. In the figure (B), only the attention weights of the target word are illustrated for clarity. The attention weight is larger when the word is more related to the target word, and the color of attention line is darker

BERT vs BERT-CRF 论文

2018 《 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》

2020 《 A New Active Learning Strategy for Bert-CRF Based Named Entity Recognition》

BERT 论文

图片

图片

BERT-CRF 论文

图片

图片

本论文我们主要关注几个核心点即可

论文主要通过增加一些策略机制来进行一些实验的实验

  • 实验证明 Bert-BiLSTM-CRF 和 Bert-CRF 这两种方式没有太大的区别,反而 Bert-BiLSTM-CRF 增加 BiLSTM 层使得模型训练和推理速度变慢。
  • BERT BIO 编码格式输入(注意:pad 补充),这里同 BERT 原始论文保持一致

图片

  • dropout 参数设置

在 fc 层减少过拟合设置 dropout = 0.9 ,后续我们实验也可以尝试 。

In the fully connected layer, we set the dropout rate to be 0.9 to prevent overfitting

  • 学习滤参数设置

learning rate to 0.00001

BERT 源码分析

BERT系列预训练模型

NER 项目准备

NER 评估标准

seqeval 是一个用于序列标记评估的 python 框架。seqeval 可以评估命名实体识别、词性标注、语义角色标注等分块任务的性能。

seqeval 支持格式:IOB 和 IOBES

seqeval 安装方法:pip install seqeval

安装完成后,为保持使用我们把源码拷贝到自己的工程下。

seqeval 代码使用

from seqeval.metrics import accuracy_score
from seqeval.metrics import classification_report
from seqeval.metrics import f1_score
y_true = [['O', 'O', 'O', 'B-MISC', 'I-MISC', 'I-MISC', 'O'], ['B-PER', 'I-PER', 'O']]
y_pred = [['O', 'O', 'B-MISC', 'I-MISC', 'I-MISC', 'I-MISC', 'O'], ['B-PER', 'I-PER', 'O']]
# score
print( f1_score(y_true, y_pred) )
# acc
print(accuracy_score(y_true, y_pred))
# report
print( classification_report(y_true, y_pred) )

上述代码运行的效果:

0.5
0.8
           precision    recall  f1-score   support

      PER       1.00      1.00      1.00         1
     MISC       0.00      0.00      0.00         1

micro avg       0.50      0.50      0.50         2
macro avg       0.50      0.50      0.50         2

BERT 预训练模型下载

**英文 BERT 预训练模型,预训练模型以及文件 rename 后 **

bert-base-uncased

├── config.json

├── pytorch_model.bin

└── vocab.txt

**BERT 预训练中文模型,预训练模型以及文件 rename 后 **

图片

BERT CRF 模块

直接使用 torchcrf

pip install torchcf

安装成功后,我们找到 torchcf 模块,拷贝自己的项目中即可直接使用了。

transformers

transformers下载 ,下载完成后,把项目拷贝到自己的项目中。

数据分析可视化

数据可视化可以帮助我们理解业务数据,重点选择 pyecharts、seaborn、matplotlib 工具库。

CoNLL2003 数据集项目

我们使用指定服务器,需要执行下面内容。

https://blog.csdn.net/ShiMengRan107/article/details/100152211

PS1='${debian_chroot:+($debian_chroot)}ailib@ubuntu:\w\$ '
export PATH=/usr/share/anaconda3/bin:$PATH
source activate
conda activate torch1.4-gpu
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:$LD_LIBRARY_PATH  
export CUDA_HOME=/usr/local/cuda-10.0:$CUDA_HOME  
export PATH=/usr/local/cuda-10.0/bin:$PATH  
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/extras/CUPTI/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

CoNLL2003 数据集[1]

实体被标注为四种类型:

LOC (location, 地名)

ORG (organisation, 组织机构名)

PER (person, 人名)

MISC (miscellaneous, 其他)

一条标注数据的组织形式如下:

[word][POS tag][chunk tag][NER tag]

DATA FORMAT

The data files contain one word per line. Empty lines have been usedfor marking sentence boundaries and a line containing the keyword-DOCSTART- has been added to thebeginning of each article in order to mark article boundaries. Each non-empty line contains the following tokens:

  1. the current word

  2. the lemma of the word (German only)

  3. the part-of-speech (POS) tag generated by a tagger

  4. the chunk tag generated by a text chunker

  5. the named entity tag given by human annotators

数据预处理

原始数据处理

提供 train.txt,dev.txt,test.txt 的数据格式如下


-DOCSTART- -X- -X- O

CRICKET NNP B-NP O
- : O O
LEICESTERSHIRE NNP B-NP B-ORG
TAKE NNP I-NP O
OVER IN B-PP O
AT NNP B-NP O
TOP NNP I-NP O
AFTER NNP I-NP O
INNINGS NNP I-NP O
VICTORY NN I-NP O
. . O O

LONDON NNP B-NP B-LOC
1996-08-30 CD I-NP O

上述数据处理生成三个文件

  • seq.in 每行表示一个完整的句子,然后以空格分割
CRICKET - LEICESTERSHIRE TAKE OVER AT TOP AFTER INNINGS VICTORY .
LONDON 1996-08-30
  • seq.out 对应每个单词的 TAG,空格分割
O O B-ORG O O O O O O O O
B-LOC O
  • slot_label.txt NER 标签的类型,这里增加 PAD 和 UNK 两个特殊的标签
PAD
UNK
O
B-LOC
I-LOC
B-MISC
I-MISC
B-ORG
I-ORG
B-PER
I-PER

特征工程

原始数据进行数字化表示

图片

定义保存 words 和 slot_labels 的类 ,我们把每个句子使用 InputExample 来表示

class InputExample(object):
    """
    A single training/test example for simple sequence classification.

    Args:
        guid: Unique id for the example.
        words: list. The words of the sequence.
        slot_labels: (Optional) list. The slot labels of the example.
    """

    def __init__(self, guid, words, slot_labels=None):
        self.guid = guid
        self.words = words
        self.slot_labels = slot_labels

模型训练

图片

python3 main.py \
--model_name_or_path ../pretrained_models/bert-base-uncased/ \
--task CoNLL-2003 \
--model_type bert \
--model_dir CoNLL-2003_model \
--do_train --do_eval --use_crf \
--num_train_epochs 5 \
--train_batch_size 64 \
--eval_batch_size 64 

这里对几个重要的参数进行说明

  • model_name_or_path

bert 的 pre_trained_model 的路径

  • task

指定数据集处理器

  • model_type

指定模型的类型,例如 bert,albert 等

  • do_train do_eval use_crf 分别为训练、验证和使用 crf 预测 tag
  • num_train_epoches 设置模型迭代的次数
  • train_batch_size,eval_batch_size 分别为训练和验证数据集每个批次加载的记录数

在线服务预测

在线服务启动

python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-uncased/ \
--task CoNLL-2003 \
--model_type bert \
--model_dir CoNLL-2003_model \
--use_crf 

这里我们使用的是 CoNLL2013 的数据集,如果是其它的数据,需要替换相应的目录

这里对几个重要的参数进行说明

  • model_name_or_path

bert 的 pre_trained_model 的路径

  • model_type

指定模型的类型,例如 bert,albert 等

  • use_crf 使用 crf 预测 tag
  • num_train_epoches 设置模型迭代的次数
  • train_batch_size,eval_batch_size 分别为训练和验证数据集每个批次加载的记录数
  • no_cuda 如果设置使用 cpu 进行推理,不设置的话如果有 cuda 可以 gpu 下推理

在线文本预测

curl -H “Content-Type:application/json” -X POST --data ‘{“text”: “Steve went to Paris”}’ http://localhost:8000/predict

返回结果

{ “errno”: 0, “errmsg”: “success”, “time”: 69, “data”: [{ “word”: “Steve”, “tag”: “B-PER” }, { “word”: “went”, “tag”: “O” }, { “word”: “to”, “tag”: “O” }, { “word”: “Paris”, “tag”: “B-LOC” }] }

预测代码分析

  • 数据输入

text = 'Steve went to Paris

  • 构建模型输入数据

图片

  • 特征数据离散化处理
tokenizer = load_tokenizer(args)
text_dataset = load_examples(args, tokenizer, text)

图片

获取三个字段数据分别

input_ids 文本中每个 token 在字典中表示

attention_mask 存在 token 的设置 1,不足 max_seq_len 长度的内容设置 0

token_type_ids 表示第一个句子,这全部 0

  • 预测 predict 函数定义(重点)

图片

航空旅游数据集项目

ATIS (Airline Travel Information System)

我们在完成 CoNLL2003 数据集下的 BERT-NER 训练和预测后,在进行别的数据集就非常容易了。关键在于我们的程序是通用的,唯一我们需要做的时候转换成一个数据集即可。

ATIS 数据集分析

首先,我们熟悉下处理成标准的格式数据(以后我们在处理 NER 问题时候,都可以处理成 CoNLL2003 中标准格式即可)

seq.in

seq.out

slot_label.txt

同时生成对应的 train、test、dev。 每个数据都对应上述 seq.in 和 seq.out,其中 slot_label.txt 是所有的 TAG 以及增加两个特殊的标签 PAD、UNK。

然后,需要对 seq.in seq.out 进行处理,针对每个句子处理后生成 tokens、input_ids、attention_mask、token_type_ids、slot_labels。

05/16/2020 23:19:06 - INFO - data_loader -   guid: dev-1
05/16/2020 23:19:06 - INFO - data_loader -   tokens: [CLS] show me all round trip flights between houston and las vegas [SEP]
05/16/2020 23:19:06 - INFO - data_loader -   input_ids: 101 2265 2033 2035 2461 4440 7599 2090 5395 1998 5869 7136 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
05/16/2020 23:19:06 - INFO - data_loader -   attention_mask: 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
05/16/2020 23:19:06 - INFO - data_loader -   token_type_ids: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
05/16/2020 23:19:06 - INFO - data_loader -   slot_labels: 0 2 2 2 98 99 2 2 73 2 114 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

我们分析后发现 slot_labels.txt 中每个标签数量差别很大,存在 TAG 分布不均衡问题。 我们在实际工作中如果入到这种问题,可以想办法补充,使其尽可能均衡(这里我们不在处理

ATIS 模型训练

模型采用 BERT-CRF 进行

图片

python3 main.py \
--model_name_or_path ../pretrained_models/bert-base-uncased/ \
--task atis \
--model_type bert \
--model_dir atis_model \
--do_train --do_eval --use_crf \
--num_train_epochs 15 \
--train_batch_size 64 \
--eval_batch_size 64 \
--max_seq_len 32   

我们这里训练 **15 **次迭代,训练完成后我们查看下效果。

  • 验证数据集效果

图片

  • 测试数据集下的效果

图片

我们的 f1 在 dev 数据集达到 97%+,在 test 数据集下也达到 94%+。证明我们 BERT -CRF 在 NER 效果上还是不错的。

注意:BERT-CRF 在 NER 领域效果已经非常好的了,我们唯一需要重点关注的是数据。如果使用过程某些地方需要处理,我们需要把 TAG 的数据进行扩展,是提升效果最重要的方法。切切记!!!

ATIS 模型预测

在线服务启动。 默认据服务器自动采用 cpu 还是 gpu 进行推理 (gpu 效果>> 好远 cpu)

图片

python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-uncased/ \
--task atis \
--model_type bert \
--model_dir atis_model \
--use_crf 

启动完成后,我们来进行预测

curl http://localhost:8000/predict \
-H "Content-Type:application/json" \
-X POST \
--data '{"text": "i want to fly boston to san francisco","lang":"en"}'

返回结果如

{
	"errno": 0,
	"errmsg": "success",
	"time": 13,
	"data": [{
			"word": "i",
			"tag": "O"
		},
		{
			"word": "want",
			"tag": "O"
		},
		{
			"word": "to",
			"tag": "O"
		},
		{
			"word": "fly",
			"tag": "O"
		},
		{
			"word": "boston",
			"tag": "B-fromloc.city_name"
		},
		{
			"word": "to",
			"tag": "O"
		},
		{
			"word": "san",
			"tag": "B-toloc.city_name"
		},
		{
			"word": "francisco",
			"tag": "I-toloc.city_name"
		}
	]
}

返回的结果:(其中 time 是在 cpu 推理的情况下花费 58 毫秒,cuda 运行在 17ms 左右,可以满足上线的条件)

同时我们看看服务端后端的日志记录

127.0.0.1 - - [16/May/2020 23:00:28] "POST /predict HTTP/1.1" 200 -
text =  i am flying from boston to the bay area
seq_len =  9
0	i	O
1	am	O
2	flying	O
3	from	O
4	boston	B-fromloc.city_name
5	to	O
6	the	O
7	bay	I-toloc.city_name
8	area	O

MSRA 新闻数据集项目

我们项目的数据集 中文数据集下载 ,点击下载即可,这个 MSRA-NER 数据集是在新闻语料上进行的序列标注。下载完成得到 dh_msra.zip,解压即可使用。

BiLSTM_CRF tensorflow 实现一个版本 ,这是我从 github 上找的一个版本,大家可以学习。

我们接下来会实现一个 BERT_CRF PyTorch 版本。主要考虑 PyTorch 语法简单易上手,BERT 在 NLP 领域各个比赛榜单都刷爆了。总之,BERT 重要,太重要了,学习 NLP 就必须掌握 BERT,并且在工业界得到了应用。

数据分析

对 dh_msra.zip 中文的数据集切分训练集、验证集、测试集。

关于数据分析我们通过 pyecharts 进行一个可视化分析,便于我们的效果展示。 我们实际算法工作中关于数据分析以及特征提取占用我们 70%左右的时间,故了解我们的业务数据非常重要的。

关于更多的 pyecharts 内容请参考

Python数据可视化 pyecharts实战

Python数据分析案例实战 视频课程

  • 数据 Example 分布

图片

这里给出训练数据、验证数据以及测试数据句子的长度

  • 标签类别数据分布
from pyecharts import  options as opts
from pyecharts.charts import Bar
def bar_charts()->Bar():
    c = Bar()
    c.add_xaxis(xaxis_data=keys)
    c.add_yaxis(series_name='train_TAG-数量统计',yaxis_data=train_tags) 
    return c
c = bar_charts()
c.render_notebook()

图片

图片

图片

从上述 train、dev、test 发现,数据的 TAG

  • 文章句子长度分布

通过分析自己业务句子的长度,可以在训练的时候 max_seq_len 进行设置合理的数值。

图片图片

通过上述分析:

数据长度最大的长度整体在 80 左右,我们在通过 boxplot 那么我们在训练 bert 的时候 max_seq_len 可以设置 60 左右

NER 模型训练

python3 main.py  \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  msra \
--model_type  bert \
--model_dir msra_bert_base_zh_model  \
--do_train  --do_eval --use_crf   \
--num_train_epochs  3 \
--train_batch_size 64 \
--eval_batch_size 64  \
--max_seq_len 64 

NVIDIA GeForce GTX 1080 12G 显存,我们 3 次迭代单卡运行 20 分钟 。如果大家是 cpu 环境下进行训练的话,可以自己抽取一部分小的数据进行训练,保障可以允许即可。如果机器资源允许的情况下,可以调大 train_batch_size ,可以加快训练的速度。训练结果如下:

INFO - train -   ***** Eval [**dev**] results 
INFO - train -              precision    recall  f1-score   support
      ORG       0.86      0.94      0.90      1601
      LOC       0.92      0.96      0.94      2562
      PER       0.97      0.97      0.97      1811
micro avg       0.92      0.96      0.94      5974
macro avg       0.92      0.96      0.94      5974

INFO - train -     loss = 1.0743800858999122
INFO - train -     sementic_frame_acc = 0.9231186685962374
INFO - train -     slot_**f1 = 0.9369517094367467**
INFO - train -     slot_precision = 0.918206652739836
INFO - train -     slot_recall = 0.9564780716437897

INFO - train -   ***** Eval [**test**] results *****
INFO - train -              precision    recall  f1-score   support
      LOC       0.95      0.93      0.94      2935
      PER       0.96      0.96      0.96      1998
      ORG       0.85      0.91      0.88      1426
micro avg       0.93      0.94      0.94      6359
macro avg       0.93      0.94      0.94      6359
INFO - train -     loss = 1.006102637312878
INFO - train -     sementic_frame_acc = 0.9249547920433996
INFO - train -     slot_**f1 = 0.9350995453832889**
INFO - train -     slot_precision = 0.9321769026410377
INFO - train -     slot_recall = 0.9380405724170467

NER 模型在线预测

我们通过 gpu 下训练的模型,也可以直接运行在 cpu 下。

python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  msra  \
--model_type  bert  \
--model_dir msra_bert_base_zh_model \
--use_crf 

注意:model_name_or_path 和 model_dir 换成自己预训练模型路径和模型文件路径

预测效率对比:gpu 单条记录预测 13ms 左右,cpu 大概 60ms(和服务器配置有关系)。对于 cpu 下推理速度慢的问题我们也可以针对模型进行优化(比如:albert-tiny…)

**在线预测命令行如下: **

curl http://127.0.0.1:8000/predict \
-H "Content-Type:application/json" \
-X POST \
--data '{"text": "沈福利毕业于北京工业大学,位于北京市朝阳区","lang":"zh"}'  

图片

返回结果 :


{

  "errno": 0, 

  "errmsg": "success", 

**  "time": 16, **

  "data": [

    {

      "word": "沈", 

      "tag": "B-PER"

    }, 

    {

      "word": "福", 

      "tag": "I-PER"

    }, 

    {

      "word": "利", 

      "tag": "I-PER"

    }, 

    {

      "word": "毕", 

      "tag": "O"

    }, 

    {

      "word": "业", 

      "tag": "O"

    }, 

    {

      "word": "于", 

      "tag": "O"

    }, 

    {

      "word": "北", 

      "tag": "B-ORG"

    }, 

    {

      "word": "京", 

      "tag": "I-ORG"

    }, 

    {

      "word": "工", 

      "tag": "I-ORG"

    }, 

    {

      "word": "业", 

      "tag": "I-ORG"

    }, 

    {

      "word": "大", 

      "tag": "I-ORG"

    }, 

    {

      "word": "学", 

      "tag": "I-ORG"

    }, 

    {

      "word": ",", 

      "tag": "O"

    }, 

    {

      "word": "位", 

      "tag": "O"

    }, 

    {

      "word": "于", 

      "tag": "O"

    }, 

    {

      "word": "北", 

      "tag": "B-LOC"

    }, 

    {

      "word": "京", 

      "tag": "I-LOC"

    }, 

    {

      "word": "市", 

      "tag": "I-LOC"

    }, 

    {

      "word": "朝", 

      "tag": "B-LOC"

    }, 

    {

      "word": "阳", 

      "tag": "I-LOC"

    }, 

    {

      "word": "区", 

      "tag": "I-LOC"

    }

  ]

}

我们看下后台服务器日志数据

图片

我们可以得出这样的结果:

**沈福利**毕业于北京工业大学,位于北京市朝阳区

我们就可以把每个类型的 TAG 都提取出来了。

NLP 比赛 音乐领域语义理解

数据是主要来自人机对话系统中音乐领域以及非音乐领域的真实用户请求记录。

音乐类槽位填充项目

中文分词以及词性标注

针对中文分词以及词性标注问题实际上是一个序列标注任务,属于 NER 功能,下面我们简单了解下。一般选择的方案:BiLSTM-CRF 或者 BERT_CRF.。下面我们采用 BERT_CRF 来进行实验,实际使用的过程,规则字典+模型一起来完成的,我们这里学习下如何使用NER 模型来进行分词( 大家可以尝试bilstm_crf ,目前工业界常用,主要基于推测性能来考虑的 ) ,本文实验我们选择了几种词性进行( [‘N’, ‘V’, ‘NZ’, ‘W’, ‘VN’, ‘MQ’, ‘D’, ‘T’, ‘UDE1’, ‘A’, ‘P’, ‘NR’, ‘VI’, ‘NNT’, ‘NT’, ‘NS’, ‘M’, ‘F’, ‘C’, ‘RR’])

数据分析

对 people-2014 人民日报 POS 词性标注数据数据集切分训练集、验证集、测试集。

关于数据分析我们通过 pyecharts 进行一个可视化分析,便于我们的效果展示。 我们实际算法工作中关于数据分析以及特征提取占用我们 70%左右的时间,故了解我们的业务数据非常重要的。

关于更多的 pyecharts 内容请参考

Python数据可视化 pyecharts实战

Python数据分析案例实战 视频课程

  • 数据 Example 分布

这里给出训练数据、验证数据以及测试数据句子的记录数

图片

  • 标签类别数据分布

图片

图片

图片

从上述 train、dev、test 发现,数据的 TAG

  • 文章句子长度分布

通过分析自己业务句子的长度,可以在训练的时候 max_seq_len 进行设置合理的数值。

图片图片

通过上述分析:

数据长度最大的长度整体在 200 左右,我们在通过 boxplot 那么我们在训练 bert 的时候 max_seq_len 可以设置 200 左右(多数据分布在 64 左右,为加速训练速度,可以训练时候可以设置一个比较小的数值)

NER 模型训练

这里给出 ubuntu 环境下 pytorch 配置环境

export PATH=/home/ubuntu/anaconda3/bin:$PATH

export PATH=/usr/local/cuda-9.0/bin:$PATH

export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64:$LD_LIBRARY_PATH

export LIBRARY_PATH=/usr/local/cuda-9.0/lib64:$LIBRARY_PATH

python3 main.py  \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  people-2014  \
--model_type  bert \
--model_dir people2014_bert_base_zh_model  \
--do_train  --do_eval --use_crf   \
--num_train_epochs 3  \
--train_batch_size 32 \
--eval_batch_size 64  \
--max_seq_len 64

我们实验使用单卡 GTX1080ti GPU,每个迭代1.5 小时。这里训练3次迭代效果(大家可以可以尝试更多):

 INFO - train -              precision    recall  f1-score   support

       NT       0.89      0.90      0.90      7307
        V       0.99      0.98      0.99    165986
        D       0.99      0.99      0.99     61665
        T       0.99      0.99      0.99     28097
     UDE1       1.00      1.00      1.00     51574
        N       0.97      0.97      0.97    185587
       VN       0.98      0.98      0.98     45969
       NZ       0.90      0.90      0.90     69613
        P       1.00      1.00      1.00     47142
      NNT       0.98      0.99      0.98     18146
        F       0.99      0.99      0.99     23310
        M       0.99      0.98      0.98     12727
       VI       0.98      0.98      0.98     22278
       MQ       0.98      0.99      0.99     34141
       RR       1.00      1.00      1.00     17288
       NR       0.97      0.97      0.97     21167
        A       0.98      0.98      0.98     31482
        C       1.00      1.00      1.00     14431
       NS       0.96      0.96      0.96     17992

micro avg       0.98      0.98      0.98    875902
macro avg       0.98      0.98      0.98    875902

INFO - train -     loss = 1.8359935450942124
INFO - train -     sementic_frame_acc = 0.8029136970713302
INFO - train -     slot_f1 = 0.9759650342340757
INFO - train -     slot_precision = 0.9765579723812039
INFO - train -     slot_recall = 0.975372815680293

大家可以自己尝试更多的参数进行训练

  • 增大 num_train_epochs
  • max_seq_len 可以设置 256(通过数据分析发现)
  • 在进行这类序列任务,如果有多卡,可以利用多卡并行提高训练数据

这里对主要的词性进行说明,更多可以参考 。 具体实际应用,大家可以标准更多地数据来进分词效果实验。

 NR(人名)    
 VI(动词)   
  DE1(的)    
  C( 连词)  
  V(动词)    
 NS(地名)    
 MQ     
  D       
  N(名词)    
  A(形容词)  
 NT(机构团体)
 NZ(其它专名)
 VN(名动词)  
   RR       
  T(时间词)  
  M(数词)    
  NNT       
  F(方位词)  
  P(介词)    

NER 模型在线预测

python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  people-2014  \
--model_type  bert  \
--model_dir people2014_bert_base_zh_model  \
--use_crf 

注意:model_name_or_path 和 model_dir 换成自己预训练模型路径和模型文件路径

预测效率对比:gpu 单条记录预测 13ms 左右,cpu 大概 60ms(和服务器配置有关系)。对于 cpu 下推理速度慢的问题我们也可以针对模型进行优化(比如:albert-tiny…)

**在线预测命令行如下: **

query = 从北京到上海怎么走

识别介词:从

识别地名:北京、上海

其他名词:怎么走

1)执行命令
curl http://127.0.0.1:8000/predict -H "Content-Type:application/json" -X POST --data '{"text": "从北京到上海怎么走","lang":"zh"}'2) 返回结果
text =  从北京到上海怎么走
seq_len =  9
0       从      S-P
1       北      B-NS
2       京      I-NS
3       到      S-V
4       上      B-NS
5       海      I-NS
6       怎      B-NZ
7       么      I-NZ
8       走      I-NZ
  • query = 我要去北京市海淀区中关村大街

地名识别 NS: 北京市、海淀区

专有名词: 中关村大街

(1)执行命令
curl http://127.0.0.1:8000/predict -H "Content-Type:application/json" -X POST --data '{"text": "我要去北京市海淀区中关村大街","lang":"zh"}'
(2)返回结果
text =  我要去北京市海淀区中关村大街
seq_len =  14
0       我      S-RR
1       要      S-V
2       去      O
3       北      B-NS
4       京      I-NS
5       市      I-NS
6       海      B-NS
7       淀      I-NS
8       区      I-NS
9       中      B-NZ
10      关      I-NZ
11      村      I-NZ
12      大      I-NZ
13      街      I-NZ
  • query =播放一首周杰伦的歌曲

动词: 播放

人名:周杰伦

普通名称: 歌曲

(1) 执行命令
curl http://127.0.0.1:8000/predict -H "Content-Type:application/json" -X POST --data '{"text": "播放一首周杰伦的歌曲","lang":"zh"}'
(2)返回结果
text =  播放一首周杰伦的歌
seq_len =  9
0       播      B-V
1       放      I-V
2       一      B-MQ
3       首      I-MQ
4       周      B-NR
5       杰      I-NR
6       伦      I-NR
7       的      S-UDE1
8       歌      B-N
9       曲      I-N

附录-拓展学习资料

下面给大家提供一些学习资料,供大家自己学习,作为课堂外的内容。

CoNLL-2003

https://www.aclweb.org/anthology/W03-0419.pdf

https://www.clips.uantwerpen.be/conll2003/ner/

https://yuanxiaosc.github.io/2018/12/26/%E5%91%BD%E5%90%8D%E5%AE%9E%E4%BD%93%E8%AF%86%E5%88%ABCoNLL2003/

https://github.com/yuanxiaosc/BERT-for-Sequence-Labeling-and-Text-Classification

如何训练小模型

NLPCC2020 NER 项目

https://github.com/CLUEbenchmark/CLUENER2020

https://www.cluebenchmarks.com/introduce.html

https://www.cluebenchmarks.com/NLPCC.html

https://zhuanlan.zhihu.com/p/102676719?utm_source=wechat_timeline

把BERT的推断速度提升17倍

下面我们做一些的尝试

1/9 的 bert_base < 12M

**数据 **

  • 160G+原始数据
  • 35G+的通用数据
  • 3700+预训练模型
  • 256 的预处理长度

模型

我们可以考虑 bert_base 修改 6 层看看效果 。

“num_hidden_layers”: 12-> “num_hidden_layers”: 6

“max_position_embeddings”: 512-> “max_position_embeddings”: 256

v100-32G 8 卡混合精度训练

wwm-mlm

结果

  • loss 在 1.5->1.8 抖动

2000qps 20gpu-> 2000qps 1gpu

推理优化方案

  • Tensorflow serving Batching
  • FP16 量化
  • Faster Transformer

中文版本 zh-albert

我们直接使用 albert_zh 中已经转好的版本, 点击下载

对话系统

[1] 小爱:语音识别和 NLP 在语音交互中的实践

[2] 美团对话理解技术及实践

[3] 小米NLU2018

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章