Trainer¶
Trainer 是 Transformers 库中实现的一个完整的 PyTorch 模型训练和评估循环。你只需要传递训练所需的各个部分(模型、分词器、数据集、评估函数、训练超参数等),Trainer 类会处理其余所有事情。这使得你可以更快地开始训练,而无需手动编写自己的训练循环。同时,Trainer 也非常可定制,提供了大量的训练选项,可以根据你的具体训练需求进行调整。
除了 Trainer 类,Transformers 还提供了 Seq2SeqTrainer 类,用于翻译或摘要等序列到序列任务。此外,TRL 库中的 SFTTrainer 类包装了 Trainer 类,并针对使用自回归技术训练像 Llama-2 和 Mistral 这样的语言模型进行了优化。SFTTrainer 还支持序列打包、LoRA、量化和 DeepSpeed 等功能,以便高效地扩展到任何模型大小。
你可以查看 API 参考 了解更多关于这些 Trainer 类型类的信息,了解何时使用哪一个。一般来说,Trainer 是最通用的选项,适用于广泛的多种任务。Seq2SeqTrainer 专为序列到序列任务设计,而 SFTTrainer 则专为训练语言模型设计。
在开始之前,请确保安装了 Accelerate 库,这是一个用于在分布式环境中启用和运行 PyTorch 训练的库。
pip install accelerate
# 升级
pip install accelerate --upgrade
本指南概述了 Trainer 类。
基本用法¶
Trainer 包含了你在基本训练循环中会找到的所有代码:
- 执行训练步骤以计算损失
- 使用
backward方法计算梯度 - 根据梯度更新权重
- 重复此过程,直到达到预定的训练轮数
Trainer 类抽象了所有这些代码,因此你不必每次都手动编写训练循环,尤其是当你刚开始使用 PyTorch 进行训练时。你只需要提供训练所需的基本组件,如模型和数据集,Trainer 类会处理其余所有事情。
如果你想指定任何训练选项或超参数,可以在 TrainingArguments 类中找到它们。例如,让我们定义模型保存的位置 output_dir,并在训练后将模型推送到 Hub 上,设置 push_to_hub=True。
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="your-model",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=2,
weight_decay=0.01,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
push_to_hub=True,
)
from transformers import Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
)
trainer.train()
检查点¶
Trainer 类会将模型检查点保存到 TrainingArguments 中 output_dir 参数指定的目录中。你会在一个名为 checkpoint-000 的子文件夹中找到这些检查点,文件夹末尾的数字对应于训练步骤。保存检查点对于稍后恢复训练非常有用。
# 从最新的检查点恢复
trainer.train(resume_from_checkpoint=True)
# 从输出目录中保存的特定检查点恢复
trainer.train(resume_from_checkpoint="your-model/checkpoint-1000")
你可以通过在 TrainingArguments 中设置 push_to_hub=True 将检查点(默认不保存优化器状态)保存到 Hub 上。关于如何保存检查点的其他选项可以在 hub_strategy 参数中设置:
hub_strategy="checkpoint"将最新的检查点推送到名为 “last-checkpoint” 的子文件夹中,你可以从中恢复训练hub_strategy="all_checkpoints"将所有检查点推送到output_dir定义的目录中(你会在模型仓库中看到每个检查点一个文件夹)
当你从检查点恢复训练时,Trainer 会尝试保持 Python、NumPy 和 PyTorch 的随机数生成器状态与保存检查点时相同。但由于 PyTorch 有各种非确定性的默认设置,随机数生成器状态不能保证完全相同。如果你想启用完全确定性,可以查看 控制随机源 指南,了解你可以启用的设置,以使训练完全确定。但请注意,某些设置可能会使训练变慢。
自定义 Trainer¶
虽然 Trainer 类设计为易于使用且易访问,但它也为更有经验的用户提供了大量的可定制性。许多 Trainer 的方法可以被继承和重写,以支持你想要的功能,而无需从头重写整个训练循环。这些方法包括:
- get_train_dataloader() 创建训练 DataLoader
- get_eval_dataloader() 创建评估 DataLoader
- get_test_dataloader() 创建测试 DataLoader
- log() 记录训练过程中观察到的各种对象的信息
- create_optimizer_and_scheduler() 如果没有在
__init__中传递,则创建优化器和学习率调度器;这些也可以分别通过 create_optimizer() 和 create_scheduler() 进行自定义 - compute_loss() 计算一批训练输入的损失
- training_step() 执行训练步骤
- prediction_step() 执行预测和测试步骤
- evaluate() 评估模型并返回评估指标
- predict() 在测试集上进行预测(如果有标签,则计算指标)
例如,如果你想自定义 compute_loss() 方法以使用加权损失。
from torch import nn
from transformers import Trainer
class CustomTrainer(Trainer):
def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels")
# 前向传播
outputs = model(**inputs)
logits = outputs.get("logits")
# 计算自定义损失,为3个标签设置不同的权重
loss_fct = nn.CrossEntropyLoss(weight=torch.tensor([1.0, 2.0, 3.0], device=model.device))
loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1))
return (loss, outputs) if return_outputs else loss
回调函数¶
另一种自定义 Trainer 的方法是使用 回调函数。回调函数不会改变训练循环中的任何内容。它们会检查训练循环的状态,然后根据状态执行某些操作(如提前停止、记录结果等)。换句话说,回调函数不能用于实现自定义损失函数这样的功能,你需要继承并重写 compute_loss() 方法来实现这一点。
例如,如果你想在训练循环中添加一个在10步后停止训练的回调函数。
from transformers import TrainerCallback
class EarlyStoppingCallback(TrainerCallback):
def __init__(self, num_steps=10):
self.num_steps = num_steps
def on_step_end(self, args, state, control, **kwargs):
if state.global_step >= self.num_steps:
return {"should_training_stop": True}
else:
return {}
然后将其传递给 Trainer 的 callback 参数。
from transformers import Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
callback=[EarlyStoppingCallback()],
)
日志记录¶
查看 日志记录 API 参考了解更多关于不同日志级别的详细信息。
Trainer 默认设置为 logging.INFO,报告错误、警告和其他基本信息。在分布式环境中,Trainer 副本设置为 logging.WARNING,仅报告错误和警告。你可以通过 TrainingArguments 中的 log_level 和 log_level_replica 参数更改日志级别。
要为每个节点配置日志级别设置,可以使用 log_on_each_node 参数来确定是否在每个节点上使用日志级别,还是仅在主节点上使用。
Trainer 在 Trainer.__init__() 方法中为每个节点单独设置日志级别,因此如果你在创建 Trainer 对象之前使用了其他 Transformers 功能,你可能需要尽早设置此项。
例如,要将主代码和模块设置为根据每个节点使用相同的日志级别:
import logging
import sys
logger = logging.getLogger(__name__)
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
datefmt="%m/%d/%Y %H:%M:%S",
handlers=[logging.StreamHandler(sys.stdout)],
)
log_level = training_args.get_process_log_level()
logger.setLevel(log_level)
datasets.utils.logging.set_verbosity(log_level)
transformers.utils.logging.set_verbosity(log_level)
trainer = Trainer(...)
使用不同的 log_level 和 log_level_replica 组合来配置每个节点上记录的内容。
- 单节点
my_app.py ... --log_level warning --log_level_replica error
- 多节点
my_app.py ... --log_level warning --log_level_replica error --log_on_each_node 0
# set to only report errors
my_app.py ... --log_level error --log_level_replica error --log_on_each_node 0
NEFTune¶
NEFTune 是一种通过在训练过程中向嵌入向量添加噪声来提高性能的技术。要在 Trainer 中启用它,可以在 TrainingArguments 中设置 neftune_noise_alpha 参数来控制添加的噪声量。
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(..., neftune_noise_alpha=0.1)
trainer = Trainer(..., args=training_args)
NEFTune 在训练后会被禁用,以恢复原始的嵌入层,避免任何意外行为。
GaLore¶
梯度低秩投影(GaLore)是一种内存高效的低秩训练策略,允许全参数学习,但比常见的低秩适应方法(如 LoRA)更节省内存。
首先确保安装 GaLore 官方仓库:
pip install galore-torch
然后只需在 optim 中添加 ["galore_adamw", "galore_adafactor", "galore_adamw_8bit"] 之一,并结合 optim_target_modules,它可以是一个字符串列表、正则表达式或对应于你想要适应的目标模块名称的全路径。下面是一个端到端的示例脚本(确保 pip install trl datasets):
import torch
import datasets
import trl
from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM
train_dataset = datasets.load_dataset('imdb', split='train')
args = TrainingArguments(
output_dir="./test-galore",
max_steps=100,
per_device_train_batch_size=2,
optim="galore_adamw",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"]
)
model_id = "google/gemma-2b"
config = AutoConfig.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_config(config).to(0)
trainer = trl.SFTTrainer(
model=model,
args=args,
train_dataset=train_dataset,
dataset_text_field='text',
max_seq_length=512,
)
trainer.train()
要传递 GaLore 支持的其他参数,应正确传递 optim_args,例如:
import torch
import datasets
import trl
from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM
train_dataset = datasets.load_dataset('imdb', split='train')
args = TrainingArguments(
output_dir="./test-galore",
max_steps=100,
per_device_train_batch_size=2,
optim="galore_adamw",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
optim_args="rank=64, update_proj_gap=100, scale=0.10",
)
model_id = "google/gemma-2b"
config = AutoConfig.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_config(config).to(0)
trainer = trl.SFTTrainer(
model=model,
args=args,
train_dataset=train_dataset,
dataset_text_field='text',
max_seq_length=512,
)
trainer.train()
import torch
import datasets
import trl
from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM
train_dataset = datasets.load_dataset('imdb', split='train')
args = TrainingArguments(
output_dir="./test-galore",
max_steps=100,
per_device_train_batch_size=2,
optim="galore_adamw_layerwise",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"]
)
model_id = "google/gemma-2b"
config = AutoConfig.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_config(config).to(0)
trainer = trl.SFTTrainer(
model=model,
args=args,
train_dataset=train_dataset,
dataset_text_field='text',
max_seq_length=512,
)
trainer.train()
注意,逐层优化是实验性的,不支持 DDP(分布式数据并行),因此你只能在单个 GPU 上运行训练脚本。请参阅 此部分 了解更多详细信息。其他功能,如梯度裁剪、DeepSpeed 等可能不支持开箱即用。如果你遇到此类问题,请在 GitHub 上 提出问题。
Liger Kernel¶
Liger-Kernel 是由 Linkedin 开发的一组 Triton 内核,专为 LLM 训练设计。我们实现了 Hugging Face 兼容的 RMSNorm、RoPE、SwiGLU、CrossEntropy、FusedLinearCrossEntropy 等,并将继续增加更多功能。它可以有效提高多 GPU 训练吞吐量 20%,并减少 60% 的内存使用。该内核与 flash attention、PyTorch FSDP 和 Microsoft DeepSpeed 开箱即用。
在 LLaMA 3-8B 模型训练中,吞吐量提高 20%,内存使用减少 60%。实现更长的上下文长度和更大的批量大小。如果你想将模型扩展到多头训练或大词汇量,它也非常有用。释放多头训练(medusa)等功能。查看 Liger 中的详细信息和示例。
首先确保安装 Liger 官方仓库:
pip install liger-kernel
你应该传递 use_liger_kernel=True 来在你的模型上应用 Liger 内核,例如:
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="your-model",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=2,
weight_decay=0.01,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
push_to_hub=True,
use_liger_kernel=True
)
该内核支持 Llama、Gemma、Mistral 和 Mixtral 模型架构。最新支持的模型列表可以在 这里 找到。当 use_liger_kernel 设置为 True 时,原始模型中的相应层将被 Liger 的高效实现所替换,因此你不需要做任何额外的事情,只需设置参数值即可。
LOMO 优化器¶
LOMO 优化器在 Full Parameter Fine-Tuning for Large Language Models with Limited Resources 和 AdaLomo: Low-memory Optimization with Adaptive Learning Rate 中被引入。它们都是一种高效的全参数微调方法,将梯度计算和参数更新融合在一个步骤中,以减少内存使用。支持的 LOMO 优化器有 "lomo" 和 "adalomo"。首先可以通过 pip install lomo-optim 从 pypi 安装 LOMO,或者通过 pip install git+https://github.com/OpenLMLab/LOMO.git 从源码安装。
根据作者的建议,使用 AdaLomo 时建议不使用 grad_norm 以获得更好的性能和更高的吞吐量。
下面是一个简单的脚本,演示如何在全精度下对 google/gemma-2b 模型在 IMDB 数据集上进行微调:
import torch
import datasets
from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM
import trl
train_dataset = datasets.load_dataset('imdb', split='train')
args = TrainingArguments(
output_dir="./test-lomo",
max_steps=1000,
per_device_train_batch_size=4,
optim="adalomo",
gradient_checkpointing=True,
logging_strategy="steps",
logging_steps=1,
learning_rate=2e-6,
save_strategy="no",
run_name="lomo-imdb",
)
model_id = "google/gemma-2b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0)
trainer = trl.SFTTrainer(
model=model,
args=args,
train_dataset=train_dataset,
dataset_text_field='text',
max_seq_length=1024,
)
trainer.train()
GrokAdamW 优化器¶
GrokAdamW 优化器旨在提高训练性能和稳定性,特别是对于那些从 grokking 信号函数中受益的模型。要使用 GrokAdamW,首先通过 pip install grokadamw 安装优化器包。
GrokAdamW 对于需要高级优化技术以实现更好性能和稳定性的模型特别有用。
下面是一个简单的脚本,演示如何使用 GrokAdamW 优化器对 google/gemma-2b 模型在 IMDB 数据集上进行微调:
import torch
import datasets
from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM, Trainer
# 加载 IMDB 数据集
train_dataset = datasets.load_dataset('imdb', split='train')
# 定义训练参数
args = TrainingArguments(
output_dir="./test-grokadamw",
max_steps=1000,
per_device_train_batch_size=4,
optim="grokadamw",
logging_strategy="steps",
logging_steps=1,
learning_rate=2e-5,
save_strategy="no",
run_name="grokadamw-imdb",
)
# 加载模型和分词器
model_id = "google/gemma-2b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0)
# 初始化 Trainer
trainer = Trainer(
model=model,
args=args,
train_dataset=train_dataset,
)
# 训练模型
trainer.train()
这个脚本演示了如何使用 GrokAdamW 优化器对 google/gemma-2b 模型在 IMDB 数据集上进行微调。TrainingArguments 配置为使用 GrokAdamW,数据集传递给 Trainer 进行训练。
Schedule Free 优化器¶
Schedule Free 优化器在 The Road Less Scheduled 中被引入。Schedule-Free 学习用平均和插值的组合替换基础优化器的动量,完全消除了使用传统学习率调度器的需要。支持的 SFO 优化器有 "schedule_free_adamw" 和 "schedule_free_sgd"。首先通过 pip install schedulefree 从 pypi 安装 schedulefree。
下面是一个简单的脚本,演示如何在全精度下对 google/gemma-2b 模型在 IMDB 数据集上进行微调:
import torch
import datasets
from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM
import trl
train_dataset = datasets.load_dataset('imdb', split='train')
args = TrainingArguments(
output_dir="./test-schedulefree",
max_steps=1000,
per_device_train_batch_size=4,
optim="schedule_free_adamw",
gradient_checkpointing=True,
logging_strategy="steps",
logging_steps=1,
learning_rate=2e-6,
save_strategy="no",
run_name="sfo-imdb",
)
model_id = "google/gemma-2b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0)
trainer = trl.SFTTrainer(
model=model,
args=args,
train_dataset=train_dataset,
dataset_text_field='text',
max_seq_length=1024,
)
trainer.train()
Accelerate 和 Trainer¶
Trainer 类由 Accelerate 提供支持,这是一个用于在分布式环境中轻松训练 PyTorch 模型的库,支持集成如 FullyShardedDataParallel (FSDP) 和 DeepSpeed。
了解更多关于 FSDP 分片策略、CPU 卸载等的信息,请参阅 Fully Sharded Data Parallel 指南。
要使用 Accelerate 和 Trainer,运行 accelerate.config 命令为你的训练环境设置训练配置。此命令会创建一个 config_file.yaml,当你启动训练脚本时将使用该文件。例如,你可以设置的一些示例配置包括:
分布式数据并行
FSDP
DeepSpeed
DeepSpeed 与 Accelerate 插件
compute_environment: LOCAL_MACHINE
distributed_type: MULTI_GPU
downcast_bf16: 'no'
gpu_ids: all
machine_rank: 0 #根据节点更改 rank
main_process_ip: 192.168.20.1
main_process_port: 9898
main_training_function: main
mixed_precision: fp16
num_machines: 2
num_processes: 8
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false
accelerate_launch 命令是使用 Accelerate 和 Trainer 在分布式系统上启动训练脚本的推荐方式,参数在 config_file.yaml 中指定。此文件保存在 Accelerate 缓存文件夹中,当你运行 accelerate_launch 时会自动加载。
例如,要使用 FSDP 配置运行 run_glue.py 训练脚本:
accelerate launch \
./examples/pytorch/text-classification/run_glue.py \
--model_name_or_path google-bert/bert-base-cased \
--task_name $TASK_NAME \
--do_train \
--do_eval \
--max_seq_length 128 \
--per_device_train_batch_size 16 \
--learning_rate 5e-5 \
--num_train_epochs 3 \
--output_dir /tmp/$TASK_NAME/ \
--overwrite_output_dir
你也可以直接在命令行中指定 config_file.yaml 文件中的参数:
accelerate launch --num_processes=2 \
--use_fsdp \
--mixed_precision=bf16 \
--fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \
--fsdp_transformer_layer_cls_to_wrap="BertLayer" \
--fsdp_sharding_strategy=1 \
--fsdp_state_dict_type=FULL_STATE_DICT \
./examples/pytorch/text-classification/run_glue.py
--model_name_or_path google-bert/bert-base-cased \
--task_name $TASK_NAME \
--do_train \
--do_eval \
--max_seq_length 128 \
--per_device_train_batch_size 16 \
--learning_rate 5e-5 \
--num_train_epochs 3 \
--output_dir /tmp/$TASK_NAME/ \
--overwrite_output_dir
查看 启动你的 Accelerate 脚本 教程,了解更多关于 accelerate_launch 和自定义配置的信息。