Hugging Face实战-系列教程12:文本预训练模型构建3(模型自动导入/transformers/BERT/模型蒸馏/文本截断处理/随机mask)、项目实战、源码解读

Hugging Face 实战系列 总目录

有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Jupyter Notebook中进行
本篇文章配套的代码资源已经上传

Hugging Face实战-系列教程10:文本预训练模型构建1
Hugging Face实战-系列教程11:文本预训练模型构建2

5、完形填充训练

5.1 随机mask

接下来我们需要随机mask掉一些位置,然后来进行预测,方法huggingface已经提供好了!!!
随机mask,正常情况下我们需要写一个函数,对某一个索引位置的Token做值的替换,但是AI领域发展的太快了,python又是一个如此魔性的语言,直接有现成的方法。

from transformers import DataCollatorForLanguageModeling
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
#0.15是BERT人家说的,咱们别改了
  1. 在HuggingFace中到导入这个LanguageModeling包
  2. 在LanguageModeling可以任意指定mask词的比例,bert用的是15%,这里别改,mlm表示的是mask language model的缩写

5.2 随机mask展示

这里和torch中的dataloader非常像,实际上的功能也是一样的

samples = [lm_datasets["train"][i] for i in range(2)]
for sample in samples:
    print(sample)
for chunk in data_collator(samples)["input_ids"]:
    print(f"\n'>>> {tokenizer.decode(chunk)}'")
    print(len(chunk))
  1. 从原始训练集中取出两个数据,放到sample 这个list中
  2. 遍历
  3. 打印出来,可以看到id都是什么
  4. 遍历看刚刚的两个文本,哪些是mask:从mask训练集中取出刚刚的两个文本的input_ids
  5. 打印mask后的文本:decode(chunk)可以将id转化为mask_id,tokenizer将id转化为文本打印出来
  6. 打印文本长度,很显然都是128

打印结果:
Hugging Face实战-系列教程12:文本预训练模型构建3(模型自动导入/transformers/BERT/模型蒸馏/文本截断处理/随机mask)、项目实战、源码解读_第1张图片
没有mask的文本就是标签,有mask的文本就是训练数据。lm_datasets是我们下载的原始数据,data_collator是我们使用DataCollatorForLanguageModeling工具随机mask后的数据,分别是数据和标签。

5.3 mask数据采样

train_size = 10000
test_size = int(0.1 * train_size)
downsampled_dataset = lm_datasets["train"].train_test_split(
    train_size=train_size, test_size=test_size, seed=42
)
downsampled_dataset
  1. 原始的数据有6万多,只取了1万
  2. 取10%作为测试数据
  3. 取出训练数据,指定训练、测试数据集大小
  4. 打印数据的维度结构

打印结果:

DatasetDict({
  train: Dataset({
    features: [‘input_ids’, ‘attention_mask’, ‘word_ids’, ‘labels’],
    num_rows: 10000
  })
  test: Dataset({
    features: [‘input_ids’, ‘attention_mask’, ‘word_ids’, ‘labels’],
    num_rows: 1000
  })
})

6、训练

6.1 指定训练参数

from transformers import TrainingArguments
batch_size = 64
logging_steps = len(downsampled_dataset["train"]) // batch_size
model_name = model_checkpoint.split("/")[-1]
training_args = TrainingArguments(
    output_dir=f"{model_name}-finetuned-imdb",#自己定名字
    overwrite_output_dir=True,
    evaluation_strategy="epoch",
    learning_rate=2e-5,
    weight_decay=0.01,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    logging_steps=logging_steps,
    num_train_epochs=1,
    save_strategy='epoch',
)
  1. 从transformers 导进来训练参数
  2. 指定batch_size
  3. 指定多少个step进行打印(len(downsampled_dataset[“train”])是整个数据集的长度,除以batch_size就是batch数量,所以相当于每个epoch进行打印)
  4. 指定模型名字,因为一些模型名字前面会带有机构的名字,比如openAI/什么模型,用斜杠分开,只取最后一个
  5. TrainingArguments工具设置参数
  6. 保存训练模型的地址
  7. 是否覆盖文件
  8. 以epoch为间隔跑验证集
  9. 学习率
  10. 学习率衰减
  11. 训练集的batch
  12. 验证集的batch
  13. 多少次迭代打印一次损失
  14. 一共需要跑多少个epoch
  15. 每间隔一个epoch保存一次结果

6.2 设置Trainer

from transformers import Trainer
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=downsampled_dataset["train"],
    eval_dataset=downsampled_dataset["test"],
    data_collator=data_collator,
)
  1. 导包
  2. Trainer工具
  3. 指定模型
  4. 指定训练参数
  5. 指定训练集
  6. 指定验证集(这里验证集叫test)
  7. 指定mask

6.3 评估指标

import math
eval_results = trainer.evaluate()
print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")

这个评估指标叫做困惑度,困惑度就是交叉熵的指数形式,这东西有点难理解,用我的话就是你不得在mask那挑啥词合适吗,平均挑了多少个才能答对。

》》》Perplexity: 21.94

6.4 训练

trainer.train()

看下损失:

Hugging Face实战-系列教程12:文本预训练模型构建3(模型自动导入/transformers/BERT/模型蒸馏/文本截断处理/随机mask)、项目实战、源码解读_第2张图片

看下训练后的模型,困惑度是不是更好一点:

eval_results = trainer.evaluate()
print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
  1. 还是去执行验证集,trainer.train()是训练,trainer.evaluate()就是去评估一下
  2. 打印评估结果
    打印结果:

'>>> Perplexity: 12.85

7、模型测试

训练完模型后看看模型效果,加载我们训练的模型:

from transformers import AutoModelForMaskedLM

model_checkpoint = "distilbert-base-uncased"
model = AutoModelForMaskedLM.from_pretrained("./distilbert-base-uncased-finetuned-imdb/checkpoint-157")

训练好的模型保存在本地了,157表示迭代的次数不一样,所以每个人的名字也不一样

继续用tokenizer去加载:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)

看看新模型的结果:

import torch
inputs = tokenizer(text, return_tensors="pt")
token_logits = model(**inputs).logits
mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
mask_token_logits = token_logits[0, mask_token_index, :]
top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist()

for token in top_5_tokens:
    print(f"'>>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}'")
  1. 导包
  2. 还是用tokenizer做分词
  3. model(**inputs)是去预测,这里的模型是从本地加载进来的(我们自己训练的),.logits表示得到预测结果
  4. 后面都是同样的取预测结果,取top5,for训练打印出结果

打印结果:

‘>>> This is a great deal.’
‘>>> This is a great idea.’
‘>>> This is a great adventure.’
‘>>> This is a great film.’
‘>>> This is a great movie.’

训练结果多出来了film和movie,之前没有这些词
NLP都是微调的,你自己是玩不出来的

Hugging Face实战-系列教程10:文本预训练模型构建1
Hugging Face实战-系列教程11:文本预训练模型构建2

你可能感兴趣的:(Hugging,Face实战,bert,人工智能,深度学习,自然语言处理,transformer,pytorch)