2.2 实战演练之命名实体识别NER

目录

1 命名实体识别任务介绍

2 基于Transfromers的解决方案

2.1 模型结构:

2.2 评估函数:

3 代码实战演练

1)导包:

2)加载数据集

3)数据预处理

4)创建模型

5)常见评估函数

6)配置训练参数 

7)创建训练器

 8)模型训练 

9)模型预测

4 NER实战过程中需要注意的7点:


1 命名实体识别任务介绍

2 基于Transfromers的解决方案

使用不同的model head用于解决不同的任务,如果说我们需要对每一个词(token)去做一个标签预测的话,这个时候我们就需要用到xxxForTokenClassification

2.1 模型结构:

2.2 评估函数:

3 代码实战演练

1)导包:

2)加载数据集

可以看到数据集已经划分好了训练集、验证集和测试集,这就省去了我们接下来“数据划分”的步骤。

简单查看一下数据:

可以看到,ner_tag与token是一一对应的,也就是每个词都是一个token,每个token都对应一个标签,我们可以发现“厦门”和“金门”都是5、6,说明这两个都是实体。

通过上述查看数据集的features,我们可以很直观地看到id、tokens、ner_tags的属性,反别是一个值、序列、序列,另外,观察ner_tags:‘O’代表非实体,‘B-PER'和'I-PER’分别表示实体为人的开始和结束,‘B-ORG’和‘I-ORG’则表示实体为组织的开始和结束,‘B-LOC’和‘I-LOC’则表示实体为地点的开始和结束,这就刚好对应了之前的5和6。

取标签的list,便于下一步使用。 

3)数据预处理

前面我们查看数据的时候,可以发现数据已经做好tokenize了,也就是已经分词了,那么如果我们直接使用tokenizer,可能会造成如下结果:(每个token又有了一个101开头和102结尾,也就是把数据处理为了多个句子,而不是一个句子,我们并不希望这样,而希望整体是101开头,102结尾

因此,需要指定is_split_into_words=True

很好,现在我们已经得到了'input_ids'、'token_type_ids'、'attention_mask',那么我们如何获得标签呢?一个很直观的想法就是将原来的ner_tags直接拿来作为标签,反正是一一对应的。但是这样子其实并不行,原因在于一个token可能对应多个input_ids

这个“interesting word"只有两个token,但是input_ids却占了5个,如果我们直接把原来的ner_tags的两个拿过来,显然不是一一对应的。因此就需要我们顺序发掘input_ids中的每一个id到底对应于原来的哪一个token,然后再取对应的ner_tag即可。(相当于做一个映射拼接

还有一个问题就是如何确定input_ids中的每一个id到底属于哪个token呢,比如现在的interesting和word,这个其实可以用到word_ids()加以判断:

具体的映射过程如下: 

可以看到,此时的features中已经包含了labels 

我们可以打印浏览一下,此时的labels确实是正确的:

4)创建模型

 对于所有的非二分类任务,切记要指定num_labels,否则就会device错误,这是就需要用到我们上边保存标签的list了。

我们可以直观看到,此时模型的标签类别就是7类了。 

5)常见评估函数

导入seqeval:

 查看一下示例

现在,我们需要将预测结果转换为上述preidtions的形式,将id转换为原始的字符串类型的标签

6)配置训练参数 

7)创建训练器

 8)模型训练 

可以看到最后得到的'eval_f1': 0.9535934291581109,还是蛮不错的。 

在测试集上进行评估:

可以看到最后的f1也还不错

9)模型预测

 注意要指定id2label,换成我们自己的标签,而不是label_1,label_2这种。

如果我们不指定 aggregation_strategy参数的话,按照文档:(它将以none的形式一个个Token给出结果,并不直观)

指定aggregation_strategy="simple"以聚合形式给出  

但是上述还有一个问题,模型会检测到这个空格,并把这个空格也计算在内。如何解决这个问题呢?

和输入文本相匹配,去掉空格:

4 NER实战过程中需要注意的7点:

  1. tokenizer(ner_datasets["train"][0]["tokens"], is_split_into_words=True)   # 对于已经做好tokenize的数据,要指定is_split_into_words参数为True
  2. def process_function(examples):# 借助word_ids 实现标签映射
  3. model = AutoModelForTokenClassification.from_pretrained("hfl/chinese-macbert-base", num_labels=len(label_list))# 对于所有的非二分类任务,切记要指定num_labels,否则就会device错误
  4.     # 将id转换为原始的字符串类型的标签(也就是用真实字符串标签取代0、1这些)

        true_predictions = [

            [label_list[p] for p, l in zip(prediction, label) if l != -100]

            for prediction, label in zip(predictions, labels)

        ]

  5. # 使用pipeline进行推理,要指定id2label(换成我们自己的字符串标签,而不是label_1,label_2这种)

    model.config.id2label = {idx: label for idx, label in enumerate(label_list)}

  6. # 如果模型是基于GPU训练的,那么推理时要指定device

    # 对于NER任务,可以指定aggregation_strategy为simple,得到具体的实体的结果,而不是token的结果

    ner_pipe = pipeline("token-classification", model=model, tokenizer=tokenizer, device=0, aggregation_strategy="simple")

  7. #去掉空格,根据start和end取实际的结果

    ner_result = {}

    x = "小明在北京上班"

    for r in res:

        if r["entity_group"] not in ner_result:

            ner_result[r["entity_group"]] = []

        ner_result[r["entity_group"]].append(x[r["start"]: r["end"]])

    ner_result

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值