应用BERT模型做命名实体识别任务

作者:陆平

1. 命名实体识别任务概述

人工智能技术的应用领域日趋广泛,新的智能应用层出不穷。本项目将利用人工智能技术来对快递单文字中的命名实体信息进行识别,包括姓名、电话、省、市、区、详细地址等实体。相关工作者使用该方法,能够从快递单文本信息中自动提取关键命名实体,期望有助于提升快递物流中信息处理效率。

本项目旨在构建BERT模型,来做命名实体识别。部分代码参考了『PaddleNLP预热』04。

这里我们采用PaddleNLP2.0模块,使用pip安装PaddleNLP2.0命令如下:

#安装paddlenlp2.0
!pip install paddlenlp

接着,导入必要的模块。

import paddle
import paddlenlp as ppnlp
from paddlenlp.data import Stack, Pad, Tuple
from paddlenlp.metrics import ChunkEvaluator
import paddle.nn.functional as F
import numpy as np
from functools import partial #partial()函数可以用来固定某些参数值,并返回一个新的callable对象

2. 创建项目和挂载数据

在创建项目时,可以为该项目挂载“快递单数据集”,即便项目重启,该挂载的数据集也不会被自动清除。具体方法如下:首先采用notebook方式构建项目,项目创建框中的最下方有个数据集选项,选择“+添加数据集”。然后,弹出搜索框,在关键词栏目输入“快递单数据”,便能够查询到该数据集。最后,选中该数据集,可以自动在项目中挂载该数据集了。

需要注意的是,每次重新打开该项目,data文件夹下除了挂载的数据集,其他文件都将被删除。

被挂载的数据集会自动出现在data目录之下,通常是压缩包的形式。在data/data16246目录,其中有一个压缩文件,express_ner.tar.gz。大家也可以利用AI Studio Notebook下载功能把数据集下载到本地。

#本项目已经挂载了快递单数据,可以使用tar命令把数据集解压到/home/aistudio/文件
!tar -zxvf /home/aistudio/data/data16246/express_ner.tar.gz -C /home/aistudio/
express_ner/
express_ner/test.txt
express_ner/dev.txt
express_ner/train.txt

3. 初探快递单数据集

要让机器自动学会识别快递单信息中的实体,需要让它去学习那些已经标注好标签的数据集。

快递单数据集中,“姓名、电话、省、市、区、详细地址”等命名实体,对应的标签集为:

label = {P, T, A1, A2, A3, A4, O}

其中,P代表姓名,T代表电话,A1代表省份,A2代表城市,A3代表县区,A4代表详细地址。O代表无关字符。

快递单数据集是按字符来打标签的。

假设有一个快递信息如下:北 京 北 京 市 南 城 区 北 草 厂 街 戊 0 0 号 1 2 3 4 5 6 7 8 9 0 1 王 五

它对应的标签为:B-A1 I-A1 B-A2 I-A2 I-A2 B-A3 I-A3 I-A3 B-A4 I-A4 I-A4 I-A4 I-A4 I-A4 I-A4 I-A4 B-T I-T I-T I-T I-T I-T I-T I-T I-T I-T I-T B-P I-P

"B-A1"代表省份起始位置,"I-A1"代表省份中间位置或结束位置。

"B-A2"代表城市起始位置,"I-A2"代表城市中间位置或结束位置。

"B-A3"代表县区起始位置,"I-A3"代表县区中间位置或结束位置。

"B-A4"代表详细地址起始位置,"I-A4"代表详细地址中间位置或结束位置。

"B-T"代表电话号码起始位置,"I-T"代表电话号码中间位置或结束位置。

"B-P"代表姓名的起始位置,"I-P"代表姓名的中间位置或结束位置。

def load_dict(dict_path):"""加载词汇表"""vocab = {}for line in open(dict_path, 'r', encoding='utf-8'):value, key = line.strip('\n').split('\t')vocab[key] = int(value)return vocabclass Reader(paddle.io.Dataset):def __init__(self, file_path):#加载label标签self.label_vocab = load_dict('./tag.dic')self.examples = []with open(file_path, 'r', encoding='utf-8') as f:next(f)for line in f.readlines():data = line.strip('\n').split('\t')#样本中的字由\002字符分割text = data[0].split('\002')label = data[1].split('\002')self.examples.append([text, label])self.num_label = max(self.label_vocab.values()) + 1def __getitem__(self, index):return self.examples[index]def __len__(self):return len(self.examples)
# 训练集数据
train_dataset = Reader('./express_ner/train.txt')
# 验证集数据
dev_dataset = Reader('./express_ner/dev.txt')
# 测试集数据
test_dataset = Reader('./express_ner/test.txt')#分别打印前两条数据
print("训练集数据:{}\n".format(train_dataset[0:2]))
print("验证集数据:{}\n".format(dev_dataset[0:2]))
print("测试集数据:{}\n".format(test_dataset[0:2]))
训练集数据:[[['1', '6', '6', '2', '0', '2', '0', '0', '0', '7', '7', '宣', '荣', '嗣', '甘', '肃', '省', '白', '银', '市', '会', '宁', '县', '河', '畔', '镇', '十', '字', '街', '金', '海', '超', '市', '西', '行', '5', '0', '米'], ['B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'B-P', 'I-P', 'I-P', 'B-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4']], [['1', '3', '5', '5', '2', '6', '6', '4', '3', '0', '7', '姜', '骏', '炜', '云', '南', '省', '德', '宏', '傣', '族', '景', '颇', '族', '自', '治', '州', '盈', '江', '县', '平', '原', '镇', '蜜', '回', '路', '下', '段'], ['B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'B-P', 'I-P', 'I-P', 'B-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4']]]验证集数据:[[['喻', '晓', '刚', '云', '南', '省', '楚', '雄', '彝', '族', '自', '治', '州', '南', '华', '县', '东', '街', '古', '城', '路', '3', '7', '号', '1', '8', '5', '1', '3', '3', '8', '6', '1', '6', '3'], ['B-P', 'I-P', 'I-P', 'B-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T']], [['1', '3', '4', '2', '6', '3', '3', '8', '1', '3', '5', '寇', '铭', '哲', '黑', '龙', '江', '省', '七', '台', '河', '市', '桃', '山', '区', '风', '采', '路', '朝', '阳', '广', '场'], ['B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'B-P', 'I-P', 'I-P', 'B-A1', 'I-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4']]]测试集数据:[[['黑', '龙', '江', '省', '双', '鸭', '山', '市', '尖', '山', '区', '八', '马', '路', '与', '东', '平', '行', '路', '交', '叉', '口', '北', '4', '0', '米', '韦', '业', '涛', '1', '8', '6', '0', '0', '0', '0', '9', '1', '7', '2'], ['B-A1', 'I-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'B-P', 'I-P', 'I-P', 'B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T']], [['广', '西', '壮', '族', '自', '治', '区', '桂', '林', '市', '雁', '山', '区', '雁', '山', '镇', '西', '龙', '村', '老', '年', '活', '动', '中', '心', '1', '7', '6', '1', '0', '3', '4', '8', '8', '8', '8', '羊', '卓', '卫'], ['B-A1', 'I-A1', 'I-A1', 'I-A1', 'I-A1', 'I-A1', 'I-A1', 'B-A2', 'I-A2', 'I-A2', 'B-A3', 'I-A3', 'I-A3', 'B-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'I-A4', 'B-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'I-T', 'B-P', 'I-P', 'I-P']]]
#调用ppnlp.transformers.BertTokenizer进行数据处理,tokenizer可以把原始输入文本转化成模型model可接受的输入数据格式。
tokenizer = ppnlp.transformers.BertTokenizer.from_pretrained("bert-base-chinese")#数据预处理
def convert_example(example,tokenizer,label_vocab,max_seq_length=256,is_test=False):if is_test:text = exampleelse:text, label = example#tokenizer.encode方法能够完成切分token,映射token ID以及拼接特殊tokenencoded_inputs = tokenizer.encode(text=text, max_seq_len=None, pad_to_max_seq_len=False)input_ids = encoded_inputs["input_ids"]segment_ids = encoded_inputs["segment_ids"]seq_len = encoded_inputs["seq_len"]if not is_test:label = ['O'] + label + ['O']label = [label_vocab[x] for x in label]return input_ids, segment_ids, seq_len, labelelse:return input_ids, segment_ids, seq_len#使用partial()来固定convert_example函数的tokenizer, label_vocab, max_seq_length等参数值
trans_fn = partial(convert_example, tokenizer=tokenizer, label_vocab=train_dataset.label_vocab, max_seq_length=128)
batchify_fn = lambda samples, fn=Tuple(Pad(axis=0,pad_val=tokenizer.vocab[tokenizer.pad_token]),Pad(axis=0, pad_val=tokenizer.vocab[tokenizer.pad_token]), Stack(),Pad(axis=0, pad_val=-1)):fn(list(map(trans_fn, samples)))
#训练集迭代器
train_loader = paddle.io.DataLoader(dataset=train_dataset,batch_size=64,shuffle=True,return_list=True,collate_fn=batchify_fn)dev_loader = paddle.io.DataLoader(dataset=dev_dataset,batch_size=64,return_list=True,collate_fn=batchify_fn)test_loader = paddle.io.DataLoader(dataset=test_dataset,batch_size=64,return_list=True,collate_fn=batchify_fn)print(train_dataset.label_vocab)
[2021-01-28 13:41:31,100] [    INFO] - Downloading bert-base-chinese-vocab.txt from https://paddle-hapi.bj.bcebos.com/models/bert/bert-base-chinese-vocab.txt
100%|██████████| 107/107 [00:00<00:00, 3253.45it/s]{'B-P': 0, 'I-P': 1, 'B-T': 2, 'I-T': 3, 'B-A1': 4, 'I-A1': 5, 'B-A2': 6, 'I-A2': 7, 'B-A3': 8, 'I-A3': 9, 'B-A4': 10, 'I-A4': 11, 'O': 12}

4. BERT预训练模型加载

#加载预训练BERT模型用于token分类任务的Fine-tune网络BertForTokenClassification。
model = ppnlp.transformers.BertForTokenClassification.from_pretrained("bert-base-chinese", num_classes=train_dataset.num_label)
[2021-01-28 13:41:36,463] [    INFO] - Downloading http://paddlenlp.bj.bcebos.com/models/transformers/bert/bert-base-chinese.pdparams and saved to /home/aistudio/.paddlenlp/models/bert-base-chinese
[2021-01-28 13:41:36,514] [    INFO] - Downloading bert-base-chinese.pdparams from http://paddlenlp.bj.bcebos.com/models/transformers/bert/bert-base-chinese.pdparams
100%|██████████| 696494/696494 [00:10<00:00, 67881.74it/s]
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1245: UserWarning: Skip loading for classifier.weight. classifier.weight is not found in the provided dict.warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1245: UserWarning: Skip loading for classifier.bias. classifier.bias is not found in the provided dict.warnings.warn(("Skip loading for {}. ".format(key) + str(err)))

5.模型训练

#设置训练超参数#学习率
learning_rate = 1e-5
#训练轮次
epochs = 20
#学习率预热比率
warmup_proption = 0.1
#权重衰减系数
weight_decay = 0.01num_training_steps = len(train_loader) * epochs
num_warmup_steps = int(warmup_proption * num_training_steps)def get_lr_factor(current_step):if current_step < num_warmup_steps:return float(current_step) / float(max(1, num_warmup_steps))else:return max(0.0,float(num_training_steps - current_step) /float(max(1, num_training_steps - num_warmup_steps)))
#学习率调度器
lr_scheduler = paddle.optimizer.lr.LambdaDecay(learning_rate, lr_lambda=lambda current_step: get_lr_factor(current_step))#优化器
optimizer = paddle.optimizer.AdamW(learning_rate=lr_scheduler,parameters=model.parameters(),weight_decay=weight_decay,apply_decay_param_fun=lambda x: x in [p.name for n, p in model.named_parameters()if not any(nd in n for nd in ["bias", "norm"])])#损失函数
criterion = paddle.nn.loss.CrossEntropyLoss()
#评估函数
metric = ChunkEvaluator(train_dataset.label_vocab.keys(), suffix=True)
#评估函数
def evaluate(model, metric, data_loader):model.eval()metric.reset()for input_ids, seg_ids, lens, labels in data_loader:logits = model(input_ids, seg_ids)preds = paddle.argmax(logits, axis=-1)n_infer, n_label, n_correct = metric.compute(None, lens, preds, labels)metric.update(n_infer.numpy(), n_label.numpy(), n_correct.numpy())precision, recall, f1_score = metric.accumulate()print("评估准确度: %.6f - 召回率: %.6f - f1得分: %.6f" % (precision, recall, f1_score))model.train()metric.reset()
global_step = 0
for epoch in range(1, epochs+1):for step, (input_ids, segment_ids, seq_lens, labels) in enumerate(train_loader, start=1):logits = model(input_ids, segment_ids)preds = paddle.argmax(logits, axis=-1)n_infer, n_label, n_correct = metric.compute(None, seq_lens, preds, labels)metric.update(n_infer.numpy(), n_label.numpy(), n_correct.numpy())precision, recall, f1_score = metric.accumulate()loss = paddle.mean(criterion(logits.reshape([-1, train_dataset.num_label]), labels.reshape([-1])))global_step += 1if global_step % 10 == 0 :print("训练准确度: %.6f, 召回率: %.6f, f1得分: %.6f" % (precision, recall, f1_score))loss.backward()optimizer.step()lr_scheduler.step()optimizer.clear_gradients()evaluate(model, metric, dev_loader)
训练准确度: 0.774794, 召回率: 0.479581, f1得分: 0.592449
训练准确度: 0.804517, 召回率: 0.533068, f1得分: 0.641248
评估准确度: 0.935560 - 召回率: 0.836417 - f1得分: 0.883215
训练准确度: 0.921431, 召回率: 0.822775, f1得分: 0.869313
训练准确度: 0.949503, 召回率: 0.884844, f1得分: 0.916034
训练准确度: 0.958352, 召回率: 0.916231, f1得分: 0.936818
评估准确度: 0.978279 - 召回率: 0.984861 - f1得分: 0.981559
训练准确度: 0.984211, 召回率: 0.980084, f1得分: 0.982143
训练准确度: 0.985173, 召回率: 0.982851, f1得分: 0.984010
评估准确度: 0.985368 - 召回率: 0.991169 - f1得分: 0.988260
训练准确度: 0.988482, 召回率: 0.990037, f1得分: 0.989259
训练准确度: 0.991358, 召回率: 0.990666, f1得分: 0.991012
训练准确度: 0.991933, 召回率: 0.990791, f1得分: 0.991362
评估准确度: 0.993272 - 召回率: 0.993272 - f1得分: 0.993272
训练准确度: 0.994360, 召回率: 0.992537, f1得分: 0.993448
训练准确度: 0.994568, 召回率: 0.994178, f1得分: 0.994373
评估准确度: 0.995370 - 召回率: 0.994533 - f1得分: 0.994952
训练准确度: 0.995550, 召回率: 0.992950, f1得分: 0.994248
训练准确度: 0.995984, 召回率: 0.995115, f1得分: 0.995549
训练准确度: 0.996229, 召回率: 0.995291, f1得分: 0.995760
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.996071, 召回率: 0.996593, f1得分: 0.996332
训练准确度: 0.996402, 召回率: 0.996011, f1得分: 0.996206
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.995557, 召回率: 0.996599, f1得分: 0.996077
训练准确度: 0.994865, 召回率: 0.995732, f1得分: 0.995298
训练准确度: 0.995713, 召回率: 0.996442, f1得分: 0.996077
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.996076, 召回率: 0.996598, f1得分: 0.996337
训练准确度: 0.996604, 召回率: 0.996994, f1得分: 0.996799
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.997381, 召回率: 0.996337, f1得分: 0.996859
训练准确度: 0.997384, 召回率: 0.996950, f1得分: 0.997167
训练准确度: 0.997384, 召回率: 0.997332, f1得分: 0.997358
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.997647, 召回率: 0.997386, f1得分: 0.997517
训练准确度: 0.998627, 召回率: 0.998366, f1得分: 0.998496
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.998168, 召回率: 0.996604, f1得分: 0.997386
训练准确度: 0.997733, 召回率: 0.997385, f1得分: 0.997559
训练准确度: 0.997908, 召回率: 0.998116, f1得分: 0.998012
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.998168, 召回率: 0.998168, f1得分: 0.998168
训练准确度: 0.998495, 召回率: 0.998234, f1得分: 0.998364
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 1.000000, 召回率: 1.000000, f1得分: 1.000000
训练准确度: 0.999389, 召回率: 0.999041, f1得分: 0.999215
训练准确度: 0.998953, 召回率: 0.998849, f1得分: 0.998901
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.999607, 召回率: 0.999346, f1得分: 0.999476
训练准确度: 0.998691, 召回率: 0.998299, f1得分: 0.998495
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.998955, 召回率: 0.998955, f1得分: 0.998955
训练准确度: 0.999128, 召回率: 0.998779, f1得分: 0.998953
训练准确度: 0.998953, 召回率: 0.998849, f1得分: 0.998901
评估准确度: 0.993277 - 召回率: 0.994113 - f1得分: 0.993695
训练准确度: 0.998691, 召回率: 0.999214, f1得分: 0.998953
训练准确度: 0.998365, 召回率: 0.998888, f1得分: 0.998627
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.997910, 召回率: 0.997910, f1得分: 0.997910
训练准确度: 0.998430, 召回率: 0.997734, f1得分: 0.998082
训练准确度: 0.998901, 召回率: 0.998483, f1得分: 0.998692
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 0.998040, 召回率: 0.999084, f1得分: 0.998562
训练准确度: 0.998824, 召回率: 0.999477, f1得分: 0.999150
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533
训练准确度: 1.000000, 召回率: 1.000000, f1得分: 1.000000
训练准确度: 0.999390, 召回率: 0.999564, f1得分: 0.999477
训练准确度: 0.999267, 召回率: 0.999163, f1得分: 0.999215
评估准确度: 0.994533 - 召回率: 0.994533 - f1得分: 0.994533

这里采用『PaddleNLP预热』04项目中的parse_decodes模块。

def parse_decodes(dataset, decodes, lens):decodes = [x for batch in decodes for x in batch]lens = [x for batch in lens for x in batch]id_label = dict(zip(dataset.label_vocab.values(), dataset.label_vocab.keys()))outputs = []for idx, end in enumerate(lens):sent = dataset.examples[idx][0][:end]tags = [id_label[x] for x in decodes[idx][1:end]]sent_out = []tags_out = []words = ""for s, t in zip(sent, tags):if t.startswith('B-') or t == 'O':if len(words):sent_out.append(words)tags_out.append(t.split('-')[1])words = selse:words += sif len(sent_out) < len(tags_out):sent_out.append(words)outputs.append(' '.join([str((s, t)) for s, t in zip(sent_out, tags_out)]))return outputsdef predict(model, data_loader, dataset):pred_list = []len_list = []for input_ids, seg_ids, lens, labels in data_loader:logits = model(input_ids, seg_ids)pred = paddle.argmax(logits, axis=-1)pred_list.append(pred.numpy())len_list.append(lens.numpy())preds = parse_decodes(dataset, pred_list, len_list)return predspred = predict(model, test_loader, test_dataset)
# 前10个预测数据的预测标签
for results in pred[:10]:print(results)
('黑龙江省', 'A1') ('双鸭山市', 'A2') ('尖山区', 'A3') ('八马路与东平行路交叉口北40米', 'A4') ('韦业涛', 'P') ('18600009172', 'T')
('广西壮族自治区', 'A1') ('桂林市', 'A2') ('雁山区', 'A3') ('雁山镇西龙村老年活动中心', 'A4') ('17610348888', 'T') ('羊卓卫', 'P')
('15652864561', 'T') ('河南省', 'A1') ('开封市', 'A2') ('顺河回族区', 'A3') ('顺河区', 'A4') ('公园路32号', 'A4') ('赵本山', 'P')
('河北省', 'A1') ('唐山市', 'A2') ('玉田县', 'A3') ('无终大街159号', 'A4') ('18614253058', 'T') ('尚汉生', 'P')
('台湾', 'A1') ('台中市', 'A2') ('北区', 'A3') ('北区锦新街18号', 'A4') ('18511226708', 'T') ('蓟丽', 'P')
('廖梓琪', 'P') ('18514743222', 'T') ('湖北省', 'A1') ('宜昌市', 'A2') ('长阳土家族自治县', 'A3') ('贺家坪镇贺家坪村一组临河1号', 'A4')
('江苏省', 'A1') ('南通市', 'A2') ('海门市', 'A3') ('孝威村孝威路88号', 'A4') ('18611840623', 'T') ('计星仪', 'P')
('17601674746', 'T') ('赵春丽', 'P') ('内蒙古自治区', 'A1') ('乌兰察布市', 'A2') ('凉城县', 'A3') ('新建街', 'A4')
('云南省', 'A1') ('临沧市', 'A2') ('耿马傣族佤族自治县', 'A3') ('鑫源路法院对面', 'A4') ('许贞爱', 'P') ('18510566685', 'T')
('四川省', 'A1') ('成都市', 'A2') ('双流区', 'A3') ('东升镇北仓路196号', 'A4') ('耿丕岭', 'P') ('18513466161', 'T')

开源项目详见百度AI Studio:
https://aistudio.baidu.com/aistudio/projectdetail/1477098

应用BERT模型做命名实体识别任务相关推荐

  1. 用深度学习做命名实体识别(五)-模型使用

    通过本文,你将了解如何基于训练好的模型,来编写一个rest风格的命名实体提取接口,传入一个句子,接口会提取出句子中的人名.地址.组织.公司.产品.时间信息并返回. 核心模块entity_extract ...

  2. 用深度学习做命名实体识别(四)——模型训练

    通过本文你将了解如何训练一个人名.地址.组织.公司.产品.时间,共6个实体的命名实体识别模型. 准备训练样本 下面的链接中提供了已经用brat标注好的数据文件以及brat的配置文件,因为标注内容较多放 ...

  3. 使用bert的预训练模型做命名实体识别NER

    前言 在上一篇博客提到了如何使用blstm-crf模型来训练本地数据集,完成命名实体提取的任务,还详细解析了代码和对应的原理.针对特定的任务,垂直的领域,可能需要使用特定数据集去训练,从而使得模型有一 ...

  4. 用隐马尔可夫模型(HMM)做命名实体识别——NER系列(二)

    上一篇文章里<用规则做命名实体识别--NER系列(一)>,介绍了最简单的做命名实体识别的方法–规则.这一篇,我们循序渐进,继续介绍下一个模型--隐马尔可夫模型. 隐马尔可夫模型,看上去,和 ...

  5. 用隐马尔可夫模型(HMM)做命名实体识别——NER系列(一)

    原博python2写的,文末是我改的python3代码 隐马尔可夫模型,看上去,和序列标注问题是天然适配的,所以自然而然的,早期很多做命名实体识别和词性标注的算法,都采用了这个模型. 这篇文章我将基于 ...

  6. 用CRF做命名实体识别——NER系列(三)

    在上一篇文章<用隐马尔可夫模型(HMM)做命名实体识别--NER系列(二)>中,我们使用HMM模型来做命名实体识别,将问题转化为统计概率问题,进行求解.显然,它的效果是非常有限的. 在深度 ...

  7. 【项目调研+论文阅读】基于BERT的中文命名实体识别方法[J] | day6

    <基于BERT的中文命名实体识别方法>王子牛 2019-<计算机科学> 文章目录 一.相关工作 二.具体步骤 1.Bi-LSTM 2.CRF结构 三.相关实验 1.数据集 2. ...

  8. python调用Hanlp做命名实体识别以及词性标注

    之前需要做一个中文命名实体识别的api,看完了一些相关论文以后觉得短时间内自己实现不大现实,于是找了一些开源工具,其中哈工大的LTP效果是很好的,但是免费使用限流量,需要给钱才行: NLPIR的pyn ...

  9. 基于知识图谱的问答系统,BERT做命名实体识别和句子相似度

    向AI转型的程序员都关注了这个号

最新文章

  1. dropdownlist总是获取第一个值
  2. 华为Mate20首支预告片爆出,30秒内包含太多黑科技
  3. Delphi程序员代码编写标准指南
  4. bootstrap-datepicker 日期格式设置
  5. iptables(上)
  6. illegal to have multiple occurrences of contentType with different values 解决
  7. BZOJ2017[USACO 2009 Nov Silver 1.A Coin Game]——DP+博弈论
  8. 访问网址(使用CDN)时 智能DNS调度 与 用户定位调度(根据IP定位)
  9. C++ 学生信息管理系统课程设计报告
  10. 古文觀止卷七_獲麟解_韓愈
  11. 网络投票中的作弊与反作弊
  12. 关于电厂设备巡检的方法和注意事项有哪些
  13. Uniapp返回上一页触发页面更新
  14. Maven项目插件飘红解决方案
  15. Python基础:第015课——弹跳的小球(优化版),条件语句和常量
  16. 万豪、希尔顿、凯悦、万达、首旅如家旗下酒店年末扎堆开业 | 中国酒店业周刊...
  17. html网页启动不了404错误,造成网页 404 错误的几大原因介绍
  18. 腾讯WiFi码推广,扫码连WiFi小程序代理入驻后如何推广使用教程!
  19. EventBus的介绍和使用
  20. 最新|神秘的互联网大厂薪资和职级!

热门文章

  1. 1000部电影艺术的刺杀和横行-1柴系媛
  2. d3 v4版本画基本图
  3. 在自己的电脑上搭建服务器,发布自己的网站(学习之用)
  4. CCD/CMOS的成像原理(内含rgb元件如何分布)
  5. 医院导航怎么做?医院地图导航如何实现院内智能导航导诊?
  6. zabbix监控硬件
  7. 铜陵新松工业机器人项目_新松机器人智慧产业园项目占地面积6.2万平方米
  8. 云顶之弈法机器人_云顶之弈机器人怎么用最好 云顶之弈机器人使用技巧
  9. Telink 825x - SDK软件结构
  10. TVU云导播全新亮相BIRTV 2018