大语言模型微调就像调教一只聪明但调皮的猫,手法不对就容易翻车。经过上百次的踩坑实践,我总结了一套Transformers框架的调优技巧,能帮你在保证效果的前提下大幅提升训练效率。这套方法在我们团队的线上项目中测试过,性能提升非常明显。
PEFT轻量级微调
传统的全量微调太费显存,用PEFT能事半功倍:
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
def setup_peft_model():
model = AutoModelForCausalLM.from_pretrained("llama2-7b")
config = LoraConfig(
r=8, # LoRA秩
lora_alpha=32, # 缩放因子
target_modules=["q_proj", "v_proj"],
lora_dropout=0.1,
)
peft_model = get_peft_model(model, config)
return peft_model
温馨提示:别傻傻地全部层都用LoRA,只对关键层做微调就够了,不但省显存还省时间。
数据加载优化
数据加载慢是个老大难问题,来看看这个加速技巧:
from datasets import Dataset
from torch.utils.data import DataLoader
class FastDataLoader:
def __init__(self, dataset_path):
self.dataset = Dataset.from_file(dataset_path)
def prepare(self):
# 预处理数据
self.dataset = self.dataset.map(
self.tokenize_function,
batched=True,
num_proc=4 # 多进程处理
)
# 打乱数据
self.dataset = self.dataset.shuffle(seed=42)
# 启用内存映射
self.dataset.set_format(
type='torch',
columns=['input_ids', 'attention_mask', 'labels'],
device='cuda'
)
我前两天还遇到个坑,数据集太大内存装不下,改用内存映射后直接起飞。
训练策略优化
光有好数据不行,还得有好的训练策略:
from transformers import Trainer, TrainingArguments
def get_training_args():
return TrainingArguments(
gradient_accumulation_steps=16, # 梯度累积
warmup_ratio=0.1, # 预热比例
lr_scheduler_type="cosine", # 余弦退火
fp16=True, # 混合精度
optim="adamw_8bit", # 8bit优化器
max_grad_norm=0.3, # 梯度裁剪
)
class CustomTrainer(Trainer):
def compute_loss(self, model, inputs):
# 自定义损失函数
outputs = model(**inputs)
loss = outputs.loss
# 添加正则化
if self.args.weight_decay > 0:
loss += self.regularization_loss()
return loss
有个小技巧,训练开始时先用小学习率预热一会,模型不容易跑飞。
推理加速妙招
训练完了还得优化推理速度:
import torch
def optimize_for_inference(model):
# 量化模型
model = model.half() # FP16量化
# 优化注意力计算
model.config.use_flash_attention = True
# 批处理请求
@torch.inference_mode()
def batch_inference(texts, batch_size=32):
results = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
outputs = model.generate(
batch,
max_length=128,
use_cache=True
)
results.extend(outputs)
return results
温馨提示:推理时把batch_size设大点,能充分利用显卡性能。不过也别太大,容易OOM。
说到推理,我还发现个好玩的,用BetterTransformer包装一下模型,啥都不用改就能提速30%:
from optimum.bettertransformer import BetterTransformer
model = BetterTransformer.transform(model)
还有个经常被忽视的细节,tokenizer的padding策略特别重要。右padding比左padding快好多,毕竟注意力不用算那么多。
前阵子我优化一个项目,就光改padding位置就提升了15%的速度。不过话说回来,模型优化真是个体力活,得不停地尝试各种组合才能找到最佳方案。
跑大模型的时候记得监控显存,我见过好多人被显存泄漏坑惨了。推荐用nvidia-smi设置显存上限,这样出问题能及时发现。