... views
在大语言模型微调领域,效率和性能的平衡一直是开发者关注的焦点。Unsloth作为一个高效的微调框架,通过优化内存使用和训练速度,让我们能够在有限的硬件资源上实现高质量的模型微调。本文将详细介绍如何使用Unsloth对Gemma-3模型进行微调,并提供完整的代码实现和最佳实践。
我们的微调项目包含以下核心组件:
gemma3/
├── unsloth-finetune-gemma3.py # 主要微调脚本
├── run-unsloth-finetune.sh # 运行脚本
├── start_tensorboard.sh # TensorBoard监控脚本
├── requirements.txt # 依赖配置
├── training_logs/ # 训练日志目录
└── training_outputs/ # 模型输出目录
项目使用了以下关键依赖:
# 设置Hugging Face镜像加速下载
export HF_ENDPOINT=https://hf-mirror.com
# 指定GPU设备
export CUDA_VISIBLE_DEVICES=1
from unsloth import FastModel
model, tokenizer = FastModel.from_pretrained(
model_name="/media/do/llmhub/modelhub/gemma-3-4b-it",
dtype=None,
max_seq_length=1024,
load_in_4bit=True, # 4-bit量化,显著减少内存使用
load_in_8bit=False,
full_finetuning=False # 使用PEFT而非全量微调
)
使用低秩适应(LoRA)技术进行参数高效微调:
model = FastModel.get_peft_model(
model,
finetune_vision_layers=False,
finetune_language_layers=True,
finetune_attention_modules=True, # 注意力模块对GRPO训练有益
finetune_mlp_modules=True,
r=8, # 秩参数:越大精度越高,但可能过拟合
lora_alpha=8, # 推荐 alpha == r
lora_dropout=0,
bias="none",
random_state=3407,
)
from unsloth.chat_templates import get_chat_template
tokenizer = get_chat_template(
tokenizer,
chat_template="gemma-3", # 使用Gemma-3专用模板
)
def formatting_prompts_func(examples):
convos = examples["conversations"]
texts = [
tokenizer.apply_chat_template(
convo,
tokenize=False,
add_generation_prompt=False
).removeprefix('<bos>')
for convo in convos
]
return {"text": texts}
# 加载并格式化数据集
dataset = load_dataset("mlabonne/FineTome-100k", split="train")
dataset = standardize_data_formats(dataset)
dataset = dataset.map(formatting_prompts_func, batched=True)
from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
eval_dataset=None,
args=SFTConfig(
dataset_text_field="text",
output_dir="./training_outputs",
logging_dir="./training_logs",
# 批次配置
per_device_train_batch_size=2,
gradient_accumulation_steps=4, # 梯度累积模拟更大批次
# 训练步数
max_steps=30, # 快速验证设置
warmup_steps=5,
# 优化器配置
learning_rate=2e-4, # 短训练用2e-4,长训练建议2e-5
optim="adamw_8bit", # 8-bit优化器节省内存
weight_decay=0.01,
lr_scheduler_type="linear",
# 日志和保存
logging_steps=1,
save_steps=10,
save_strategy="steps",
# 监控配置
report_to="tensorboard",
run_name="gemma3-finetune",
# 性能优化
dataloader_num_workers=2,
seed=3407,
),
)
from unsloth.chat_templates import train_on_responses_only
trainer = train_on_responses_only(
trainer,
instruction_part="<start_of_turn>user\n",
response_part="<start_of_turn>model\n",
)
import torch
# 解决dynamo重编译限制问题
torch._dynamo.config.cache_size_limit = 64
torch._dynamo.config.accumulated_cache_size_limit = 256
# 备选方案:完全禁用torch编译
# torch._dynamo.config.disable = True
量化策略
梯度累积
项目提供了自动化的TensorBoard启动脚本:
#!/bin/bash
# 检查并安装TensorBoard
if ! command -v tensorboard &> /dev/null; then
echo "安装TensorBoard..."
pip install tensorboard
fi
# 创建必要目录
mkdir -p ./training_logs
mkdir -p ./training_outputs
# 启动TensorBoard
tensorboard --logdir=./training_logs --port=6006 --host=0.0.0.0
通过访问 http://localhost:6006
可以实时监控:
# 安装依赖
pip install -r requirements.txt
# 启动TensorBoard监控
./start_tensorboard.sh
# 运行微调脚本
./run-unsloth-finetune.sh
warmup_ratio
的含义warmup_ratio
表示在整个训练过程中,有多少比例的步数用于学习率预热(warmup)。
在你的代码中:
num_train_epochs = 2.0
- 训练2个epochwarmup_ratio = 0.03
- 总训练步数的3%用于warmuplr_scheduler_type = "linear"
- 使用线性学习率调度器总训练步数计算:
总步数 = (数据集大小 / batch_size) × epoch数量
Warmup步数计算:
warmup步数 = 总步数 × warmup_ratio
warmup步数 = 总步数 × 0.03
学习率变化过程:
2e-4
)假设你的数据集有95,000个样本(FineTome-100k的95%):
每个epoch的步数 = 95,000 / (4 × 4) = 5,938步 # batch_size=4, gradient_accumulation_steps=4
总步数 = 5,938 × 2 = 11,876步
warmup步数 = 11,876 × 0.03 ≈ 356步
所以:
如果你改变epoch数量,warmup的绝对步数也会相应调整,但始终保持总训练步数的3%。