基于transformers框架实践Bert系列6-完形填空

本系列用于Bert模型实践实际场景,分别包括分类器、命名实体识别、选择题、文本摘要等等。(关于Bert的结构和详细这里就不做讲解,但了解Bert的基本结构是做实践的基础,因此看本系列之前,最好了解一下transformers和Bert等)

本篇主要讲解完形填空应用场景。本系列代码和数据集都上传到GitHub上:https://github.com/forever1986/bert_task

1 环境说明

1)本次实践的框架采用torch-2.1+transformer-4.37

2)另外还采用或依赖其它一些库,如:evaluate、pandas、datasets、accelerate等

2 前期准备

Bert模型是一个只包含transformer的encoder部分,并采用双向上下文和预测下一句训练而成的预训练模型。可以基于该模型做很多下游任务。

2.1 了解Bert的输入输出

Bert的输入:input_ids(使用tokenizer将句子向量化),attention_mask,token_type_ids(句子序号)、labels(结果)

Bert的输出:
last_hidden_state :最后一层encoder的输出;大小是(batch_size, sequence_length, hidden_size)(注意:这是关键输出,本次任务就需要获取该值,可以取出那个被mask掉的token,获取其前几个,取score最高的(当然也可以使用top_k或者top_p方式获取一定随机性)
pooler_output :这是序列的第一个token(classification token)的最后一层的隐藏状态,输出的大小是(batch_size, hidden_size),它是由线性层和Tanh激活函数进一步处理的。(通常用于句子分类,至于是使用这个表示,还是使用整个输入序列的隐藏状态序列的平均化或池化,视情况而定)。
hidden_states : 这是输出的一个可选项,如果输出,需要指定config.output_hidden_states=True,它也是一个元组,它的第一个元素是embedding,其余元素是各层的输出,每个元素的形状是(batch_size, sequence_length, hidden_size)
attentions:这是输出的一个可选项,如果输出,需要指定config.output_attentions=True,它也是一个元组,它的元素是每一层的注意力权重,用于计算self-attention heads的加权平均值。

2.2 数据集与模型

1)数据集来自:ChnSentiCorp(该数据集本身是做情感分类,但是我们只需要取其text部分即可)

2)模型权重使用:bert-base-chinese

2.3 任务说明

完形填空其实就是在一段文字中mask掉几个字,让模型能够自动填充字。这里本身就是bert模型做预训练是所做的事情之一,因此就是让数据给模型做训练的过程。

2.4 实现关键

1)数据集结构是一个带有text和label两列的数据,我们只需要获取到text部分即可。

2)随机mask掉部分数据,这个本身也是bert的训练过程,因此在transforms框架中DataCollatorForLanguageModeling已经实现了,你也可以自己实现随机mask掉你的数据进行训练

3 关键代码

3.1 数据集处理

数据集不需要做过多处理,只需要将text部分进行tokenizer,并制定max_length和truncation即可

python 复制代码
def process_function(datas):
    tokenized_datas = tokenizer(datas["text"], max_length=256, truncation=True)
    return tokenized_datas
new_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)

3.2 模型加载

python 复制代码
model = BertForMaskedLM.from_pretrained(model_path)

注意:这里使用的是transformers中的BertForMaskedLM,该类对bert模型进行封装。如果我们不使用该类,需要自己定义一个model,继承bert,增加分类线性层。另外使用AutoModelForMaskedLM也可以,其实AutoModel最终返回的也是BertForMaskedLM,它是根据你config中的model_type去匹配的。

这里列一下BertForMaskedLM的关键源代码说明一下transformers帮我们做了哪些关键事情

python 复制代码
# 在__init__方法中增加增加了BertOnlyMLMHead,BertOnlyMLMHead其实就是一个二层神经网络,一层是BertPredictionHeadTransform(包括linear+geluAct+ln),一层是decoder(hidden_size*vocab_size大小的linear)。
self.bert = BertModel(config, add_pooling_layer=False)
self.cls = BertOnlyMLMHead(config)
python 复制代码
# 将输出结果outputs取第一个返回值,也就是last_hidden_state
sequence_output = outputs[0]
# 将last_hidden_state输入到cls层中,获得最终结果(预测的score和词)
prediction_scores = self.cls(sequence_output)

3.3 自动并随机mask数据

关键代码在于DataCollatorForLanguageModeling,该类会实现自动mask。参考torch_mask_tokens方法。

python 复制代码
trainer = Trainer(model=model,
                  args=train_args,
                  train_dataset=new_datasets["train"],
                  data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=True, mlm_probability=0.15),
                  )

4 整体代码

python 复制代码
"""
基于BERT做完形填空
1)数据集来自:ChnSentiCorp
2)模型权重使用:bert-base-chinese
"""
# step 1 引入数据库
from datasets import DatasetDict
from transformers import TrainingArguments, Trainer, BertTokenizerFast, BertForMaskedLM, DataCollatorForLanguageModeling, pipeline

model_path = "./model/tiansz/bert-base-chinese"
data_path = "./data/ChnSentiCorp"

# step 2 数据集处理
datasets = DatasetDict.load_from_disk(data_path)
tokenizer = BertTokenizerFast.from_pretrained(model_path)


def process_function(datas):
    tokenized_datas = tokenizer(datas["text"], max_length=256, truncation=True)
    return tokenized_datas


new_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)


# step 3 加载模型
model = BertForMaskedLM.from_pretrained(model_path)


# step 4 创建TrainingArguments
# 原先train是9600条数据,batch_size=32,因此每个epoch的step=300
train_args = TrainingArguments(output_dir="./checkpoints",      # 输出文件夹
                               per_device_train_batch_size=32,  # 训练时的batch_size
                               num_train_epochs=1,              # 训练轮数
                               logging_steps=30,                # log 打印的频率
                               )


# step 5 创建Trainer
trainer = Trainer(model=model,
                  args=train_args,
                  train_dataset=new_datasets["train"],
                  # 自动MASK关键所在,通过DataCollatorForLanguageModeling实现自动MASK数据
                  data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=True, mlm_probability=0.15),
                  )


# Step 6 模型训练
trainer.train()

# step 7 模型评估
pipe = pipeline("fill-mask", model=model, tokenizer=tokenizer, device=0)
str = datasets["test"][3]["text"]
str = str.replace("方便","[MASK][MASK]")
results = pipe(str)
# results[0][0]["token_str"]
print(results[0][0]["token_str"]+results[1][0]["token_str"])

5 运行效果

注:本文参考来自大神:https://github.com/zyds/transformers-code

相关推荐
chnyi6_ya9 小时前
论文阅读:CogVideoX: Text-to-Video Diffusion Models with An Expert Transformer
论文阅读·深度学习·transformer
大连好光景10 小时前
BCELoss + sigmoid 换成 BCEWithLogitsLoss
人工智能·深度学习·机器学习
weixin_4684668511 小时前
纳米 AI 搜索新手极速上手指南
人工智能·python·深度学习·搜索引擎·ai·语言模型·自然语言处理
春日见14 小时前
五分钟入门 强化学习---DQN(Deep Q Net)算法与实现
人工智能·python·深度学习·算法·microsoft·机器学习
万俟淋曦15 小时前
【论文速递】2026年第02周(Jan-04-10)(Robotics/Embodied AI/LLM)
人工智能·深度学习·机器人·大模型·论文·robotics·具身智能
apcipot_rain15 小时前
计科八股20260530——文本输入模型步骤、CNN权重共享、Resnet、Transformer、RNN
人工智能·深度学习·神经网络·数学建模·自然语言处理
bonechips17 小时前
深入理解 JavaScript的历史包袱——变量提升(Hoisting)
javascript·深度学习
春日见18 小时前
五分钟入门 强化学习---Q-Learning算法与实现
人工智能·python·深度学习·算法·机器学习·计算机视觉
多年小白18 小时前
【周末消息】2026年5月30日-6月1日
大数据·人工智能·深度学习·机器学习·金融
weixin_4684668518 小时前
图像连通域分析新手实战指南
图像处理·人工智能·深度学习·ai·机器视觉·连通域