Transformers documentation
优化器与调度器
优化器与调度器
优化器在训练过程中更新模型权重。调度器封装优化器,并在每个训练步骤中调整学习率。Trainer 在调用 create_optimizer_and_scheduler() 时会同时创建这两者。
┌────────────┐ ┌──────────────┐
│ Optimizer │ │ Scheduler │
│ (adamw_torch_fused)◄─│ (linear) │
│ │ │ │
│ param_groups | |
│ └ lr ◄────────┤ |
│ └ weight_decay │ │
└──────┬─────┘ └──────────────┘
│
┌──── EACH TRAINING STEP ───────────────────────────────────────────┐
│ │ │
│ model(batch) │ │
│ │ │ │
│ ▼ │ │
│ loss ──► loss.backward() ──► param.grad │
│ │ │
│ ┌─────────────┘ │
│ ▼ │
│ optimizer.step() │
│ │ │
│ ▼ │
│ param.data updated │
│ │ │
│ ▼ │
│ lr_scheduler.step() ──► recalculates lr │
│ │ writes to optimizer │
│ ▼ .param_groups['lr'] │
│ model.zero_grad() │
│ │
└───────────────────────────────────────────────────────────────────┘在 TrainingArguments 中配置优化器和调度器的行为,例如 lr_scheduler_type() 和 optim()。默认设置(adamw_torch 优化器和 linear 预热调度器)是大多数微调任务的良好起点。
from transformers import TrainingArguments
args = TrainingArguments(
...,
# Optimizer
optim="adamw_torch", # or "adamw_torch_fused", "adafactor", "sgd", etc.
learning_rate=2e-5,
weight_decay=0.01,
adam_beta1=0.9,
adam_beta2=0.999,
adam_epsilon=1e-8,
# Scheduler
lr_scheduler_type="cosine", # "linear", "cosine", "constant_with_warmup", etc.
warmup_steps=500,
lr_scheduler_kwargs={"num_cycles": 3}, # scheduler-specific extras
)基于指标的调度器
一些调度器会根据训练动态进行自适应调整,而不是遵循固定的调度方案。
GreedyLR 根据评估结果更新学习率。当指标持续改善时,它通过将学习率除以 factor 来提高学习率;当指标没有改善时,它通过将学习率乘以 factor 来降低学习率。当学习率降至 min_lr 且在 reset_start 步之后仍未改善时,GreedyLR 会重置为初始状态并开始新的周期。
GreedyLR 在训练过程中需要进行评估。请将 eval_strategy 设置为 "steps" 或 "epoch"。
args = TrainingArguments(
+ lr_scheduler_type="greedy",
+ lr_scheduler_kwargs={"patience": 10, "factor": 0.95, "min_lr": 1e-5},
+ eval_strategy="steps",
+ eval_steps=200,
... # remaining args from the TrainingArguments intro config
)默认的
mode="min"适用于损失值。如果您跟踪的是数值越高越好的指标(例如准确率),请在lr_scheduler_kwargs中传入"mode": "max"。
有关可配置参数的完整列表,请参阅 GreedyLR 类。
优化器集成
Transformers 集成了第三方优化器,以支持特定的训练场景。
| 优化器 | 安装 | optim="value" | 描述 |
|---|---|---|---|
| APOLLO | apollo-torch | apollo_adamw | 通过随机投影实现内存高效的全参数训练;秩 1 已足够 |
| GrokAdamW | grokadamw | grokadamw | 针对延迟泛化(grokking) |
| LOMO / AdaLomo | lomo-optim | lomo / adalomo | 融合梯度与更新步骤,以实现低内存的全参数微调 |
| 无调度 | schedulefree | schedule_free_adamw, schedule_free_radam, schedule_free_sgd | 消除学习率退火;请搭配使用 lr_scheduler_type="constant" |
| GaLore | galore-torch | galore_adamw, galore_adafactor, galore_adamw_8bit | 通过梯度低秩投影进行全参数学习 |
| StableAdamW | torch-optimi | stable_adamw | AdamW + AdaFactor 更新裁剪;无需梯度裁剪 |
pip install apollo-torch
用于内存高效大语言模型优化的近似梯度缩放(APOLLO)是一种在预训练和微调期间进行全参数学习时内存高效的优化器。它通过使用廉价的随机投影而非 SVD,以类似 SGD 的内存开销实现了与 AdamW 相当的性能。若需极致节省内存,请使用 APOLLO-Mini,这是一种秩为 1 的变体。
使用 optim_target_modules 参数来指定要训练的层。
args = TrainingArguments(
+ optim="apollo_adamw",
+ optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
... # remaining args from the TrainingArguments intro config
)通过 optim_args 传递额外的超参数。
将
scale设置为n/r,其中n为原始空间维度,r为低秩空间维度。保持scale为默认值并调整学习率,也能达到类似的效果。
| 参数 | 描述 | APOLLO | APOLLO-Mini |
|---|---|---|---|
| rank | 用于梯度缩放的辅助子空间的秩 | 256 | 1 |
| scale_type | 缩放因子的应用方式 | channel(按通道缩放) | tensor(按张量缩放) |
| scale | 调整梯度更新以稳定训练 | 1.0 | 128 |
| update_proj_gap | 更新投影矩阵前的步数 | 200 | 200 |
| proj | 投影类型 | random | random |
使用秩为 1 的配置启用 APOLLO-Mini。
args = TrainingArguments(
optim="apollo_adamw",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
optim_args="proj=random,rank=1,scale=128.0,scale_type=tensor,update_proj_gap=200",
... # remaining args from the TrainingArguments intro config
)pip install grokadamw
GrokAdamW 针对的是 grokking 现象,即由于梯度变化缓慢,模型表现出延迟泛化的特性。
args = TrainingArguments(
+ optim="grokadamw",
... # remaining args from the TrainingArguments intro config
)pip install lomo-optim
低内存优化(LOMO)包含两个用于低内存全参数微调的优化器:LOMO和AdaLomo。两者都将梯度计算和参数更新融合为一步。AdaLomo 增加了类似 Adam 的逐参数自适应学习率。
AdaLomo 在不使用
grad_norm时效果最佳,能够提升性能和吞吐量。
args = TrainingArguments(
+ optim="adalomo",
learning_rate=2e-6,
... # remaining args from the TrainingArguments intro config
)pip install schedulefree
Schedule Free 优化器(SFO) 使用平均和插值的组合来替代动量,从而完全消除了对学习率退火的需求。
SFO 支持 RAdam(schedule_free_radam)、AdamW(schedule_free_adamw)和 SGD(schedule_free_sgd)优化器。RAdam 调度器不需要 warmup_steps。
将 SFO 与 lr_scheduler_type="constant" 搭配使用。其他调度器类型虽然也能运行,但会影响 SFO 的预期行为。
args = TrainingArguments(
+ optim="schedule_free_radam",
+ lr_scheduler_type="constant",
learning_rate=2e-6,
... # remaining args from the TrainingArguments intro config
)pip install torch-optimi
StableAdamW 将 AdaFactor 的更新裁剪机制移植到 AdamW 中,从而无需再进行梯度裁剪。除此之外,它可以作为 AdamW 的直接替代品使用。
如果您正在使用大批量大小进行训练,或者仍然观察到损失尖峰,请尝试将
beta_2设置在 0.95 到 0.99 之间。
args = TrainingArguments(
+ optim="stable_adamw",
learning_rate=2e-6,
... # remaining args from the TrainingArguments intro config
)pip install galore-torch trl
梯度低秩投影(GaLore)可降低训练大语言模型的内存占用。与 LoRA 等低秩适配方法不同,GaLore 保留了全参数学习。
将 trl.SFTConfig 中的 optim 设置为 GaLore 优化器("galore_adamw"、"galore_adafactor" 或 "galore_adamw_8bit")。通过 optim_args 指定目标模块 optim_target_modules 以及 GaLore 特定参数(rank、update_proj_gap、scale)。
from trl import SFTConfig
args = SFTConfig(
output_dir="./galore",
max_steps=100,
optim="galore_adamw",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
optim_args="rank=64, update_proj_gap=100, scale=0.10",
)在优化器名称后添加 _layerwise 以启用逐层优化("galore_adamw_layerwise")。只有被 GaLore 选中的线性层会使用低秩分解,其余所有层均按常规方式优化。
from trl import SFTConfig, SFTTrainer
args = SFTConfig(
output_dir="./galore",
max_steps=100,
optim="galore_adamw_layerwise",
optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
optim_args="rank=64, update_proj_gap=100, scale=0.10",
)Layerwise 模式目前处于实验阶段。它仅在单个 GPU上运行,不支持 DistributedDataParallel (DDP),且梯度裁剪和 DeepSpeed 可能无法正常工作。
自定义优化器和调度器
创建自定义优化器和调度器,以使用尚未集成的优化器、调整逐层学习率或应用自定义逻辑。
传入一个类和 kwargs
~Trainer.optimizer_cls_and_kwargs 接受自定义的优化器类,同时将参数分组和设备放置委托给 Trainer。
Trainer 会将优化器的构建推迟到 create_optimizer() 执行时,因此此时模型已经位于正确的设备上。
import torch
trainer = Trainer(
...
optimizer_cls_and_kwargs=(
torch.optim.SGD,
{"momentum": 0.9, "nesterov": True}
),
)传入预构建的实例
将预定义的优化器和调度器传递给 ~Trainer.optimizers。当提供预构建的实例时,Trainer 会跳过 create_optimizer() 和 create_scheduler()。如果未传递调度器,Trainer 会自动创建一个。
在将模型放置到正确的设备之后再构建优化器。参数在构造时即被解析,早于
Trainer移动模型。在分布式训练中,设备不匹配可能会悄无声息地导致错误行为。
import torch
from transformers import Trainer, get_cosine_schedule_with_warmup
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5)
scheduler = get_cosine_schedule_with_warmup(
optimizer, num_warmup_steps=500, num_training_steps=10_000
)
trainer = Trainer(
...
optimizers=(optimizer, scheduler),
)预构建实例会绕过 create_optimizer() 和 create_scheduler(),因此您需要自行指定参数组。
重写优化器和调度器方法
子类化 create_optimizer() 和 create_scheduler() 以获得完全的控制权。这两个方法都会在 train() 期间 运行。
重写 create_scheduler(),以使用 SchedulerType 中不可用的调度器,例如 OneCycleLR。
对于每种方法,请确保将其赋值给 self 并返回它。
import torch
from transformers import Trainer
class MyTrainer(Trainer):
def create_scheduler(self, num_training_steps, optimizer=None):
optimizer = optimizer or self.optimizer
self.lr_scheduler = torch.optim.lr_scheduler.OneCycleLR(
optimizer,
max_lr=0.1,
total_steps=num_training_steps,
)
return self.lr_scheduler如果默认优化器可用,则无需重写 create_optimizer()。使用 super() 扩展方法比完全替换它更简单。例如,在保持其他所有内容不变的情况下,添加一个额外的参数组。
class MyTrainer(Trainer):
def create_optimizer(self, model=None):
super().create_optimizer(model) # builds the default two param groups
# add extra param group
self.optimizer.add_param_group({
"params": self.model.classifier.parameters(),
"lr": self.args.learning_rate * 10,
})
return self.optimizer