这个标题描述的是一个关于分布式监督微调(SFT)的技术实践项目,主要使用了trl(Transformer Reinforcement Learning)和DeepSpeed这两个工具库。从"Part 1: Starting Locally"可以看出,这是一个系列教程的第一部分,重点在于本地环境的搭建和初步实现。
作为从业者,我理解这个项目的核心价值在于:
trl是Hugging Face推出的一个专注于Transformer模型强化学习的库。它主要提供三大功能:
在本次项目中,我们主要使用其SFT功能。与原生Hugging Face Trainer相比,trl的SFTTrainer提供了更丰富的功能:
DeepSpeed是微软开发的深度学习优化库,其核心优势包括:
特别值得注意的是ZeRO的三个阶段:
虽然最终目标是分布式训练,但本地环境搭建是第一步。建议配置:
注意:实际需求会根据模型大小而变化。7B参数的模型在fp16精度下需要约14GB显存进行推理。
创建conda环境并安装核心依赖:
bash复制conda create -n sft python=3.10
conda activate sft
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install transformers datasets trl accelerate deepspeed
验证安装:
python复制import torch
print(torch.cuda.is_available()) # 应返回True
print(torch.cuda.device_count()) # 显示可用GPU数量
使用Hugging Face datasets加载示例数据集:
python复制from datasets import load_dataset
dataset = load_dataset("imdb", split="train")
dataset = dataset.map(lambda x: {"text": f"Review: {x['text']}\nSentiment: {x['label']}"})
以GPT-2为例的模型加载:
python复制from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
# 关键:设置pad_token
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
使用SFTTrainer的基本配置:
python复制from trl import SFTTrainer
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
dataset_text_field="text",
max_seq_length=512,
args={
"per_device_train_batch_size": 4,
"gradient_accumulation_steps": 2,
"num_train_epochs": 3,
"learning_rate": 2e-5,
"output_dir": "./results",
"report_to": "none"
}
)
创建ds_config.json文件:
json复制{
"train_micro_batch_size_per_gpu": 4,
"gradient_accumulation_steps": 2,
"optimizer": {
"type": "AdamW",
"params": {
"lr": 2e-5
}
},
"fp16": {
"enabled": true
},
"zero_optimization": {
"stage": 2,
"offload_optimizer": {
"device": "cpu"
}
}
}
修改训练命令:
bash复制deepspeed --num_gpus=1 train.py \
--deepspeed ds_config.json
在代码中需要添加:
python复制from transformers import TrainingArguments
training_args = TrainingArguments(
per_device_train_batch_size=4,
gradient_accumulation_steps=2,
num_train_epochs=3,
learning_rate=2e-5,
output_dir="./results",
report_to="none",
deepspeed="ds_config.json" # 关键添加
)
安装并使用nvitop监控:
bash复制pip install nvitop
nvitop -m full
关键指标关注:
使用自动批处理大小发现:
python复制from accelerate.utils import AutocastKwargs
kwargs = AutocastKwargs()
kwargs.enabled = True
kwargs.cache_enabled = True
trainer = SFTTrainer(
...,
args=TrainingArguments(
...,
auto_find_batch_size=True,
kwargs=kwargs
)
)
典型错误:
code复制CUDA out of memory.
解决方案:
python复制model.gradient_checkpointing_enable()
可能原因:
诊断命令:
bash复制watch -n 1 nvidia-smi
优化方案:
python复制dataset = dataset.with_format("torch")
bash复制deepspeed --num_gpus=4 train.py
修改启动命令:
bash复制deepspeed --num_gpus=2 train.py \
--deepspeed ds_config.json
需要调整的关键配置:
json复制{
"train_micro_batch_size_per_gpu": 2,
"gradient_accumulation_steps": 4,
"zero_optimization": {
"stage": 3
}
}
添加模型保存策略:
python复制training_args = TrainingArguments(
...,
save_steps=1000,
save_total_limit=2,
logging_steps=100
)
恢复训练:
bash复制deepspeed --num_gpus=2 train.py \
--resume_from_checkpoint ./results/checkpoint-1000
在实际操作中,我发现从本地单卡开始验证pipeline的正确性非常重要。很多分布式环境的问题其实在本地就能发现端倪。特别是在使用DeepSpeed时,建议先使用stage 1或2进行验证,再逐步过渡到stage 3。