前言
随着bert ,gpt 等预训练模型的快速发展,众多企业和学术组织在 1.预训练的任务,2.模型的构造,3.数据的质量等方向进行改进,训练出数以万计以transformer为基础结构的的berts和gpts,随着bert,gpt的数量越来越多。Hugging face transformer届的github 诞生了。Hugging face允许用户上传和下载的预训练的模型。这样使得每个 NLPer 都可以直接使用必须依靠大量美金才能训练出来的预训练模型。Nlper 可以轻易的在huggingface网站上面下载预训练模型在自己的数据集上进行微调就能达到很好的效果,可谓造福大家。下方是Hugging face 中模型的搜索页面,已经有多达55592个预训练模型。
hugging face 又开发了transformers 这个python 包,供大家一行代码使用这些模型,十分便捷。比如可以直接 一行代码 从 hugging face下载预训练模型到本地并加载到内存,但是此法经常碰到网络练接中断的问题。
model = BertForSequenceClassification.from_pretrained(pretrain_Model_path)
今天笔者就记录一下如何从https://huggingface.co 这个网站手动下载模型,利用 transformers这个python 包采用本地加载模型的方式完成一次文本分类的微调任务。
finetune前期准备
1.使用下方命令安装transformers的python包
pip install transformers
2.下载合适的预训练模型
这里笔者拿roberta为例,在huggingface网站搜索roberta,我这里找到哈工大的中文roberta,进入详情页点files and verisons。就会看到如下方图所示的模型文件和配置文件。
这里如果是pytorch 用户只需要下载config.json,pytorch_model.bin和vocab.txt 即可,然后把它们放到同一个文件夹。
1.config.json 模型的结构文件,如下方所示,定义了 dropout,hidden_size之类的参数。
{
"architectures": [
"BertForMaskedLM"
],
"attention_probs_dropout_prob": 0.1,
"bos_token_id": 0,
"directionality": "bidi",
"eos_token_id": 2,
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"layer_norm_eps": 1e-12,
"max_position_embeddings": 512,
"model_type": "bert",
"num_attention_heads": 12,
"num_hidden_layers": 12,
"output_past": true,
"pad_token_id": 0,
"pooler_fc_size": 768,
"pooler_num_attention_heads": 12,
"pooler_num_fc_layers": 3,
"pooler_size_per_head": 128,
"pooler_type": "first_token_transform",
"type_vocab_size": 2,
"vocab_size": 21128
}
2.pytorch_model.bin模型的权重
3.vocab.txt 模型所用的词表,如下方所示。
[PAD]
[unused1]
[unused2]
[unused3]
[unused4]
[unused5]
[unused6]
[unused7]
[unused8]
...
体
佔
何
佗
佘
余
佚
...
finetune实战部分
在模型已经下载完成,transformers 包安装完成后。我们就开始在自己的数据集上进行微调。
数据预处理
这里笔者选取来8000条新闻数据,共13个分类,去除了非中文,将数据处理成下方图片中展现的样子。
import re
from sklearn.utils import shuffle
import pandas as pd
label_dic = {
'__label__affairs':0,
'__label__constellation':1,
'__label__economic':2,
'__label__edu':3,
'__label__ent':4,
'__label__fashion':5,
'__label__game':6,
'__label__home':7,
'__label__house':8,
'__label__lottery':9,
'__label__science':10,
'__label__sports':11,
'__label__stock':12}
def get_train_data(file,label_dic):
content = []
label = []
with open(file, "r", encoding="utf-8") as f:
for i in f.readlines():
c,l = i.split("\t")
content.append(re.sub('[^\u4e00-\u9fa5]',"",c))
label.append(label_dic.get(l.strip()))
return content,label
content,label = get_train_data("./news_fasttext_train.txt",label_dic)
data = pd.DataFrame({"content":content,"label":label})
data = shuffle(data)
train_data = tokenizer(data.content.to_list()[:8000], padding = "max_length", max_length = 100, truncation=True ,return_tensors = "pt")
train_label = data.label.to_list()[:8000]
预训练模型的载入
这里通过两行代码就可以初始化bert的编码器和预训练模型的加载,AutoModelForSequenceClassification是专门为文本分类定制的函数。
from transformers import AutoModelForSequenceClassification
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("./Robert")
model = AutoModelForSequenceClassification.from_pretrained("./robert", num_labels=13)
其中“./robert” 即是上方笔者从hugging face 网站上下载的模型和配置文件保存在了./robert 文件夹下。
定义优化器和学习率
在AutoModelForSequenceClassification.from_pretrained("./robert", num_labels=13) 这个函数中,transformer 已经帮你定义了损失函数,既13个分类的交叉熵损失,所以下方我们只需要自己定义优化器和学习率即可。
import torch
from torch.utils.data import TensorDataset, DataLoader, RandomSampler, SequentialSampler
batch_size = 16
train = TensorDataset(train_data["input_ids"], train_data["attention_mask"], torch.tensor(train_label))
train_sampler = RandomSampler(train)
train_dataloader = DataLoader(train, sampler=train_sampler, batch_size=batch_size)
// 定义优化器
from torch.optim import AdamW
optimizer = AdamW(model.parameters(), lr=1e-4)
//定义学习率和训练轮数
num_epochs = 1
from transformers import get_scheduler
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
)
模型训练
这一步就是模型的微调训练过程,每10步输出一下loss。
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device)
for epoch in range(num_epochs):
total_loss = 0
model.train()
for step, batch in enumerate(train_dataloader):
if step % 10 == 0 and not step == 0:
print("step: ",step, " loss:",total_loss/(step*batch_size))
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
model.zero_grad()
outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
loss = outputs.loss
total_loss += loss.item()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
lr_scheduler.step()
avg_train_loss = total_loss / len(train_dataloader)
print("avg_loss:",avg_train_loss)
#输出大致如下
#step: 10 loss: 0.1410729356110096
# step: 20 loss: 0.11348817646503448
# step: 30 loss: 0.09371910033126672
# step: 40 loss: 0.07884938775096088
# step: 50 loss: 0.06864133032038808
# step: 60 loss: 0.06410953995461265
# step: 70 loss: 0.05953138789960316
# step: 80 loss: 0.05694254372501746
# step: 90 loss: 0.05430558831948373
# step: 100 loss: 0.05061182997655123
# step: 110 loss: 0.04901935522105883
模型预测
这里已经完成了模型的微调,接下来我们用微调后的模型进行预测。输入“过考研大纲谈农学复习之化学部分年农学将第二次实行全国统一考试这使农学考生的复习备考十分迷茫”,模型确实预测出来是属于教育类的新闻。
import numpy as np
test = tokenizer("通过考研大纲谈农学复习之化学部分年农学将第二次实行全国统一考试这使农学考生的复习备考十分迷茫",return_tensors="pt",padding="max_length",max_length=100)
model.eval()
with torch.no_grad():
outputs = model(test["input_ids"],
token_type_ids=None,
attention_mask=test["attention_mask"])
pred_flat = np.argmax(outputs["logits"],axis=1).numpy().squeeze()
print(pred_flat.tolist())
# label_dic = {
# '__label__affairs':0,
# '__label__constellation':1,
# '__label__economic':2,
# '__label__edu':3,
# '__label__ent':4,
# '__label__fashion':5,
# '__label__game':6,
# '__label__home':7,
# '__label__house':8,
# '__label__lottery':9,
# '__label__science':10,
# '__label__sports':11,
# '__label__stock':12}
尾声
至此,我们就已经学会了如何从haggface 网站上下载预训练的模型,并利用transformers 包在自己的数据集上进行文本分类微调和预测,接下来的一篇系列文章,笔者将会介绍如何并利用transformers 包在自己的数据集上进行实体识别的微调和预测。