pytorch+bert NER任务踩坑记录

原文:https://zhuanlan.zhihu.com/p/295248694

本篇文章记录的是一个pytorch初学者在完成NER任务中踩过的坑。希望写下的这篇文章能帮助也在学习pytorch的同学。接下来,我将按照模型构建的过程逐一记录我所遇到的坑。希望能和大家交流心得。

1、如何方便的使用bert(或其他预训练模型)。
最优选的方法是,使用官方代码,仔细研读,并作为一个模块加入到代码中。可是通过这样的方式使用预训练模型,准备的周期较长。在这里我选择了一个次优选项-调包。“transformers”是一个目前很火的github项目,使用这个工具包能够很轻松的完成预训练模型的构建。同时transformers已经集成了几十种预训练模型,使用起来非常方便。transformers刚刚在EMNLP2020获得了最佳demo奖,大家值得一试。

但是transformers有一个需要注意的点是:需要注意transformers的版本及其对应的说明文档和示例。

写稿的当前时间为2020年11月15日,使用pip安装transformers的最新版本是3.4.0。当前版本的问题是:对于pytorch的要求是1.2版本以上(我的版本是1.7可用),tensorflow的版本要求是2.3以上(而不是官网上写的tensorflow2.0),因此使用最新版transformers的同学需要注意更新cuda版本到11左右,以免代码调用transformers的时候会发生tensorflow缺少文件的情况(忘记截图记录错误了)。在github的issure中有人提了和我相同的问题,作者的回复是将会在下一个版本修复这个问题。

另外一个就是transformers的前身是一个名为pytorch-transformers的库,transformers和transformers对于预训练模型的使用方法是有区别的。现在网上的教程和资源两者的资料是混在一起的,在大家参考教程的时候千万要看清调用的包是否是同一个。在这里有一个小小的建议是:我推荐使用transformers,放弃使用pytorch-transformers。因为目前pytorch-transformers的官方文档已经从github上下掉了,无论是使用还是后期维护都可能有潜在的问题。我建议大家如果想使用transformers,一定要在一开始就把transformers所需要的环境装好,而不要退而求其次去使用pytorch-transformers。

另外就是transformers对于很多常见的任务都已经预先设置好了不同的模型。只需要很简单的调用(整个代码100行)就能finetuning出一个分类模型。在获取baseline的时候,可以用transformers的预设模型方便的快速试错。

但是我不得不吐一个槽,官方文档放出来的示例代码实在是太少了。想要使用transformers往往需要参考很多网上的资料还有github上其他大神的代码。这也是我写这篇文章的初衷,希望同学们可以少走弯路。

2、使用transformers做bert的tokenizer
在官方文档中,bert的tokenizer有BertTokenizer, BertTokenizerFast。我比较推荐使用BertTokenizerFast。理由很简单,虽然中文bert是基于char级别实现的,可是对于数字、英文,完全拆分成[0-9a-zA-Z]的字符则完全没有任何意义。因此再做Tokennize的时候,我们需要知道哪些字符被tokenize到了一个input_id上,这样我们在做NER预测的时候,才能知道边界应该切在哪个位置。这种映射我们统一称为offset先。(当然如果是做分类或者seq2seq的时候,offset就不是那么必须的)。

BertTokenizerFast可以在帮助我们完成tokennize的同时输出我们需要的offset,就不用我们在寻找一遍映射关系了。

from transformers import BertTokenizerFast
tokenizer = BertTokenizerFast.from_pretrained(‘bert-base-chinese’)

可以按照最大长度进行截断,但是貌似不能自动做padding。并且会在开头和结尾添加[CLS]和[SEP]的tag

tokens:{

“input_ids”: list [batch_size,id*(length+2)]

“attention_mask”: [batch_size, [1]*(length+2)]

“token_type_ids”: [batch_size,[0]*(length+2)]

“offset_mapping”: [[0,0],[begin_index,end_index]*length,[0,0]]

tokens = tokenizer(string_list,
return_offsets_mapping=True,
max_length=max_seq_length,
truncation=True)
3、模型的输入
BERT的输入需要三个,inputids、input_mask、segment_ids(也就是token_type_ids)。除此之外根据NER实现的思路要准备不同格式的标签做对比。(1)seq识别,即使用softmax或者crf按照传统序列标注的方法识别的话,只需要输入id化后的每一个tokenize的label即可。(2)span识别,需要用两个序列分别标记槽位的begin位置和end位置,label需要两个list。

4、Bert模型的调用
from transformers import BertModel
self.bert = BertModel.from_pretrained(“bert-base-chinese”)

注意输入前做好padding

outputs = self.bert(input_ids = input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)

隐层向量输出

sequence_output = outputs[0]
5、模型存储
我建议使用torch.save储存模型,而不用transformers的包来做。

6、warm_up
def get_cosine_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=.5, last_epoch=-1):
“”" Create a schedule with a learning rate that decreases following the
values of the cosine function between 0 and pi * cycles after a warmup
period during which it increases linearly between 0 and 1.
“”"
def lr_lambda(current_step):
if current_step < num_warmup_steps:
return float(current_step) / float(max(1, num_warmup_steps))
progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))
return max(0., 0.5 * (1. + math.cos(math.pi * float(num_cycles) * 2. * progress)))

return LambdaLR(optimizer, lr_lambda, last_epoch)

scheduler = get_cosine_schedule_with_warmup(optimizer,
num_warmup_steps=num_warmup_step,
num_training_steps=num_training_steps)
7、实验曲线记录

tensorboardX 可以帮助我们在pytorch中使用tensorboard记录各种实验过程中的变化

启动方式和tensorboard启动方式一样:

tensorboard --logdir=log_path --host=0.0.0.0

from tensorboardX import SummaryWriter
writer = SummaryWriter(log_dir=os.path.join(args.output_dir, “writer_summary”))
writer.add_scalar(“loss/train”, tr_loss.item(), global_step)
8、梯度累积trick
由于bert模型较大,使用单卡跑模型的时候很容易out of memory。因此batch size会调的很小。batch size小了就可能个别case会造成loss的波动,影响模型收敛效果。使用梯度累积的trick,意思是再跑了多个batch之后,再一次性回传梯度。这样就可以达到和大batch size相同的效果,避免实验的偶然性。

9、向transformers bert中新增字符的方法
BertTokenizer.add_tokens([““”, “””])

BertModel.resize_token_embeddings(len(BertTokenizer))

10、计算指标的问题
实体识别评价指标为 precision、 recall、 f1,注意此处统计是针对“实体”为概念进行统计的。

在做暴力枚举的span base的时候,遇上的问题有:

(1)当golden标记为非实体,predict也为非实体时,不应算作混淆矩阵中的TP。原因是,在这种情况下,golden和predict都不判断此处有实体存在,因此没有一个所谓“实体”的概念可供统计。所以应该跳过,不参加评价打分。如果没有过滤此部分测试样本,那么会造成模型评测的结果异常的高,接近99.99%(因为负样本的数目远远大于正样本)。

(2)在计算golden标记为实体,而predict为非实体时,只增加recall的分母(因为预测不认为此处有实体,所以precision的分母不要加1)

在计算predict标记为实体,而golden为非实体时,只增加precision的分母(因为golden不认为此处有实体,所以golden的分母不要加1)

如果此处有问题,可能的表现是,评价指标偏低

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: BERT-NER-PyTorch是一个基于PyTorch深度学习框架的BERT命名实体识别(NER)模型。BERT是一种在大规模未标记文本上训练的预训练模型,它可以用于各种自然语言处理任务BERT-NER-PyTorch利用已经使用大量标记数据进行预训练的BERT模型的表示能力,进行命名实体识别任务。命名实体识别是指从文本中识别特定实体,如人名、地名、组织、日期等。通过使用BERT-NER-PyTorch,我们可以利用预训练的BERT模型来提高命名实体识别的性能。 BERT-NER-PyTorch的实现基于PyTorch深度学习框架,PyTorch是一个用于构建神经网络的开源框架,具有易于使用、动态计算图和高度灵活的特点。通过在PyTorch环境下使用BERT-NER-PyTorch,我们可以灵活地进行模型训练、调整和部署。 使用BERT-NER-PyTorch,我们可以通过以下步骤进行命名实体识别: 1. 预处理:将文本数据转换为适合BERT模型输入的格式,例如分词、添加特殊标记等。 2. 模型构建:使用BERT-NER-PyTorch构建NER模型,该模型包括BERT预训练模型和适当的输出层。 3. 模型训练:使用标记的命名实体识别数据对NER模型进行训练,通过最小化损失函数来优化模型参数。 4. 模型评估:使用验证集或测试集评估训练得到的NER模型的性能,例如计算准确率、召回率和F1分数等指标。 5. 模型应用:使用训练好的NER模型对新的文本数据进行命名实体识别,识别出关键实体并提供相应的标签。 总之,BERT-NER-PyTorch是一个基于PyTorchBERT命名实体识别模型,通过利用预训练的BERT模型的表示能力,在命名实体识别任务中提供了灵活、高效和准确的解决方案。 ### 回答2: bert-ner-pytorch是一个基于PyTorch框架的BERT命名实体识别模型。BERT是一种基于Transformer架构的预训练模型,在自然语言处理任务中取得了很好的效果。NER代表命名实体识别,是一项重要的自然语言处理任务,旨在从文本中识别和标注出特定类型的命名实体,如人名、地点、组织等。 bert-ner-pytorch利用预训练的BERT模型作为输入,结合神经网络模型进行命名实体识别。它通过将输入文本转化为BERT模型能够接受的格式,并在其上进行微调训练来提高NER的性能。具体来说,该模型首先使用BERT模型对文本进行编码,将文本中的每个单词转化为其对应的向量表示。然后,这些向量通过一层或多层的神经网络模型,以预测每个单词是否属于某个命名实体类别。 利用bert-ner-pytorch模型,我们可以将其应用于各种实际场景中,如信息抽取、问题回答、智能问答系统等。通过对输入文本进行命名实体识别,我们可以更好地理解文本中所包含的实体信息,从而为后续的处理与分析提供更多的潜在价值。 需要注意的是,bert-ner-pytorch模型是一个基础的NER模型,它需要根据具体的任务和数据进行进一步的训练和优化。同时,BERT模型本身也有一些限制,如较高的计算资源要求和模型大小。因此,在实际使用时,我们可能需要结合具体需求,对模型进行调整和优化,以适应不同的场景和数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值