Transformers 微调

基于 Transformers 实现模型微调训练的主要流程

  1. 数据集下载

  2. 数据预处理

  3. 训练超参数配置

  4. 训练评估指标设置

  5. 训练器基本介绍

  6. 实战训练

  7. 模型保存

一个典型的数据点包括文本和相应的标签。来自YelpReviewFull测试集的示例如下:

{
    'label': 0,
    'text': 'I got \'new\' tires from them and within two weeks got a flat. I took my car to a local mechanic to see if i could get the hole patched, but they said the reason I had a flat was because the previous patch had blown - WAIT, WHAT? I just got the tire and never needed to have it patched? This was supposed to be a new tire. \\nI took the tire over to Flynn\'s and they told me that someone punctured my tire, then tried to patch it. So there are resentful tire slashers? I find that very unlikely. After arguing with the guy and telling him that his logic was far fetched he said he\'d give me a new tire \\"this time\\". \\nI will never go back to Flynn\'s b/c of the way this guy treated me and the simple fact that they gave me a used tire!'
}

数据字段

‘text’: 评论文本使用双引号(“)转义,任何内部双引号都通过2个双引号(”")转义。换行符使用反斜杠后跟一个 “n” 字符转义,即 “\n”。

‘label’: 对应于评论的分数(介于1和5之间)。

数据拆分(分成训练跟测试)

Yelp评论完整星级数据集是通过随机选取每个1到5星评论的130,000个训练样本和10,000个测试样本构建的。总共有650,000个训练样本和50,000个测试样本。

下载数据集

import os

# 代理的地址,格式为 http://ip:port
http_proxy="http://proxy.sensetime.com:3128/"
https_proxy="http://proxy.sensetime.com:3128/"
# 设置代理
os.environ["HTTP_PROXY"] = http_proxy
os.environ["HTTPS_PROXY"] = https_proxy
from datasets import load_dataset
dataset = load_dataset("yelp_review_full")
#得到的dataset 其实就是一个字典(key:value格式)train 跟test就是这个下载下来的数据集的key。而dataset["train"] 通过这个可以拿到Dataset格式的训练数据集(集合)
print(dataset["train"][0])

数据集抽样

import random
import pandas as pd
import datasets
from IPython.display import display, HTML
#用于从给定的数据集 (dataset) 中随机选择一些示例并显示
def show_random_elements(dataset, num_examples=10):
    assert num_examples <= len(dataset), "Can't pick more elements than there are in the dataset."
    picks = []
    for _ in range(num_examples):
        pick = random.randint(0, len(dataset)-1)
        print(pick)
        while pick in picks:
            pick = random.randint(0, len(dataset)-1)
        picks.append(pick)
    #将从数据集中随机选择的示例创建为 Pandas DataFrame
    df = pd.DataFrame(dataset[picks])
    for column, typ in dataset.features.items():#遍历数据集的所有特征
        if isinstance(typ, datasets.ClassLabel):#检查特征是否是分类标签
            #如果是分类标签,将使用 lambda 函数将标签的索引映射到实际的类别名称
            df[column] = df[column].transform(lambda i: typ.names[i])
    display(HTML(df.to_html()))
#可以print(show_random_elements(dataset["train"]) 查看效果

预处理数据

下载数据集到本地后,使用 Tokenizer 来处理文本,对于长度不等的输入数据,可以使用填充(padding)和截断(truncation)策略来处理。

Datasets 的 map 方法,支持一次性在整个数据集上应用预处理函数。

下面使用填充到最大长度的策略,处理整个数据集:

from transformers import AutoTokenizer
#用于加载预训练的文本处理模型(Tokenizer),以便将文本数据转换为模型可以接受的输入格式
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)

tokenized_datasets = dataset.map(tokenize_function, batched=True)#刚刚生成的dataset 通过map的方法,把里面的每个样本都进行tokenize_function操作,生成处理过的数据集tokenized_datasets

#可以show_random_elements(tokenized_datasets["train"], num_examples=1)查看效果

数据抽样

使用 1000 个数据样本,在 BERT 上演示小规模训练(基于 Pytorch Trainer)

shuffle()函数会随机重新排列列的值。如果您希望对用于洗牌数据集的算法有更多控制,可以在此函数中指定generator参数来使用不同的numpy.random.Generator。


small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

微调训练配置

加载 BERT 模型

警告通知我们正在丢弃一些权重(vocab_transform和vocab_layer_norm 层),并随机初始化其他一些权重(pre_classifier和classifier 层)。在微调模型情况下是绝对正常的,因为我们正在删除用于预训练模型的掩码语言建模任务的头部,并用一个新的头部替换它,对于这个新头部,我们没有预训练的权重,所以库会警告我们在用它进行推理之前应该对这个模型进行微调,而这正是我们要做的事情。

from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)

训练超参数(TrainingArguments)

完整配置参数与默认值:https://huggingface.co/docs/transformers/v4.36.1/en/main_classes/trainer#transformers.TrainingArguments

源代码定义:https://github.com/huggingface/transformers/blob/v4.36.1/src/transformers/training_args.py#L161

模型权重保存路径(output_dir)

from transformers import TrainingArguments
model_dir = "models/bert-base-cased"

# logging_steps 默认值为500,根据我们的训练数据和步长,将其设置为100, num_train_epochs 默认为3
training_args = TrainingArguments(output_dir=f"{model_dir}/test_trainer",
                                  logging_dir=f"{model_dir}/test_trainer/runs",
                                  logging_steps=100)
# 完整的超参数配置
print(training_args)

训练过程中的指标评估(Evaluate)
Hugging Face Evaluate 库 支持使用一行代码,获得数十种不同领域(自然语言处理、计算机视觉、强化学习等)的评估方法。 当前支持 完整评估指标:https://huggingface.co/evaluate-metric

训练器(Trainer)在训练过程中不会自动评估模型性能。因此,我们需要向训练器传递一个函数来计算和报告指标。

Evaluate库提供了一个简单的准确率函数,您可以使用evaluate.load函数加载

import numpy as np
import evaluate

metric = evaluate.load("accuracy")

接着,调用 compute 函数来计算预测的准确率。

在将预测传递给 compute 函数之前,我们需要将 logits 转换为预测值(所有Transformers 模型都返回 logits)。


def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

训练过程指标监控
通常,为了监控训练过程中的评估指标变化,我们可以在TrainingArguments指定evaluation_strategy参数,以便在 epoch 结束时报告评估指标。

from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(output_dir=f"{model_dir}/test_trainer", evaluation_strategy="epoch",logging_dir=f"{model_dir}/test_trainer/runs",
                                  logging_steps=100)

开始训练

实例化训练器(Trainer):可用nvidia-smi 查看使用率

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset,
    compute_metrics=compute_metrics,
)
trainer.train()

small_test_dataset = tokenized_datasets["test"].shuffle(seed=64).select(range(100))
trainer.evaluate(small_test_dataset)

保存模型和训练状态

使用 trainer.save_model 方法保存模型,后续可以通过 from_pretrained() 方法重新加载

使用 trainer.save_state 方法保存训练状态

trainer.save_model(f"{model_dir}/finetuned-trainer")
trainer.save_state()

微调代码示例

import os
# 代理的地址,格式为 http://ip:port
http_proxy="http://proxy.sensetime.com:3128/"
https_proxy="http://proxy.sensetime.com:3128/"
# 设置代理
os.environ["HTTP_PROXY"] = http_proxy
os.environ["HTTPS_PROXY"] = https_proxy

## 下载数据集
from datasets import load_dataset
dataset = load_dataset("yelp_review_full")
#得到的dataset 其实就是一个字典(key:value格式)train 跟test就是这个下载下来的数据集的key。而dataset["train"] 通过这个可以拿到Dataset格式的训练数据集(集合)
#print(dataset["train"][0])可以查看数据集的大概的结构


import random
import pandas as pd
import datasets
from IPython.display import display, HTML
#用于从给定的数据集 (dataset) 中随机选择一些示例并显示
def show_random_elements(dataset, num_examples=10):
    assert num_examples <= len(dataset), "Can't pick more elements than there are in the dataset."
    picks = []
    for _ in range(num_examples):
        pick = random.randint(0, len(dataset)-1)
        print(pick)
        while pick in picks:
            pick = random.randint(0, len(dataset)-1)
        picks.append(pick)
    #将从数据集中随机选择的示例创建为 Pandas DataFrame
    df = pd.DataFrame(dataset[picks])
    for column, typ in dataset.features.items():#遍历数据集的所有特征
        if isinstance(typ, datasets.ClassLabel):#检查特征是否是分类标签
            #如果是分类标签,将使用 lambda 函数将标签的索引映射到实际的类别名称
            df[column] = df[column].transform(lambda i: typ.names[i])
    display(HTML(df.to_html()))

#


from transformers import AutoTokenizer

#用于从Hugging Face加载预训练的文本处理模型(Tokenizer),以便将文本数据转换为模型可以接受的输入格式
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)

tokenized_datasets = dataset.map(tokenize_function, batched=True)
show_random_elements(tokenized_datasets["train"], num_examples=1)

# 使用 1000 个数据样本,在 BERT 上演示小规模训练(基于 Pytorch Trainer)
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))


# 微调训练配置
# 从Hugging Face加载BERT 模型
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)

from transformers import TrainingArguments
model_dir = "models/bert-base-cased"
# logging_steps 默认值为500,根据我们的训练数据和步长,将其设置为100, num_train_epochs 默认为3
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(output_dir=f"{model_dir}/test_trainer", evaluation_strategy="epoch",logging_dir=f"{model_dir}/test_trainer/runs",
                                  logging_steps=100)



 
# Evaluate库提供了一个简单的准确率函数,使用`evaluate.load`函数加载
import numpy as np
import evaluate
metric = evaluate.load("accuracy")

# `compute` 函数来计算预测的准确率。
def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

### 实例化训练器(Trainer)
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset,
    compute_metrics=compute_metrics)

trainer.train()
small_test_dataset = tokenized_datasets["test"].shuffle(seed=64).select(range(100))
trainer.evaluate(small_test_dataset)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值