Hugging face 模型微调系列1—— 实战transfomers文本分类finetune

前言

随着bert ,gpt 等预训练模型的快速发展,众多企业和学术组织在 1.预训练的任务,2.模型的构造,3.数据的质量等方向进行改进,训练出数以万计以transformer为基础结构的的berts和gpts,随着bert,gpt的数量越来越多。Hugging face transformer届的github 诞生了。Hugging face允许用户上传和下载的预训练的模型。这样使得每个 NLPer 都可以直接使用必须依靠大量美金才能训练出来的预训练模型。Nlper 可以轻易的在huggingface网站上面下载预训练模型在自己的数据集上进行微调就能达到很好的效果,可谓造福大家。下方是Hugging face 中模型的搜索页面,已经有多达55592个预训练模型。

hugging face

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个分类,去除了非中文,将数据处理成下方图片中展现的样子。


data
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 包在自己的数据集上进行实体识别的微调和预测

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342