环境准备与基础配置

在 AMD GPU 上进行大模型微调,首要任务是构建一个纯净且隔离的开发环境。很多初学者容易直接在系统全局安装 PyTorch,这往往会导致 CUDA 版本的动态库与 ROCm 驱动发生冲突,引发难以排查的 Segmentation Fault。最稳妥的方案是使用 Conda 创建独立环境,并严格指定 ROCm 版本的 PyTorch。

conda create -n rocm-llama python=3.10 -y
conda activate rocm-llama
# 务必从 pytorch.org 获取带有 rocm 后缀的安装命令,切勿混用 cuda 版本
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.0

环境激活后,安装 LLaMA-Factory 及其依赖。这里建议直接从源码安装,以便后续根据需要修改底层配置:

git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]"

安装完成后,不要急着开始训练。先运行一个简单的验证脚本,确认 HIP_VISIBLE_DEVICES 环境变量能正确识别到你的 AMD 显卡(如 MI250 或 RX 7900 系列)。如果这一步报错,说明驱动层或容器映射有问题,后续所有训练都会失败。

配置文件关键调整

LLaMA-Factory 的核心优势在于其模块化的 YAML 配置体系。针对 Qwen 系列模型在 ROCm 后端的微调,我们需要重点关注 ds_z3_config.json(DeepSpeed 配置)和主训练配置文件 train_qwen_rocm.yaml

在默认配置中,许多优化策略是基于 NVIDIA 架构预设的。对于 AMD 环境,尤其是使用 RCCL 进行多卡通信时,需要显式关闭一些尚未完全适配的 Flash Attention 变体,或者强制指定使用 PyTorch Native 的实现。打开你的训练配置文件,确保以下参数设置正确:

model_name_or_path: Qwen/Qwen2-7B-Instruct
adapter_name_or_path: null
template: qwen
finetuning_type: lora
lora_target: all
output_dir: saves/qwen2-7b/lora/rocm-fp32
overwrite_cache: true
preprocessing_num_workers: 16
cutoff_len: 2048
learning_rate: 1.0e-4
num_train_epochs: 3.0
per_device_train_batch_size: 2
gradient_accumulation_steps: 8
lr_scheduler_type: cosine
warmup_ratio: 0.1
fp16: false  # 关键点:ROCm 下混合精度有时不稳定
bf16: false  # 视具体显卡架构而定,老款 AMD 卡不支持 bf16
plot_loss: true
include_effective_batch_size: true

特别注意 fp16bf16 的设置。虽然现代深度学习推崇半精度训练以节省显存,但在某些 ROCm 版本与特定模型结构的组合下,自动混合精度(AMP)可能会引发数值溢出。如果你使用的是较旧的 GCN 架构或遇到训练不收敛的情况,暂时关闭这些选项,回归纯 FP32 往往是解决问题的第一步。

攻克混合精度梯度爆炸难题

在实际操作中,我最常遇到的“拦路虎”就是梯度爆炸。现象非常典型:训练刚开始几步,Loss 值还是正常的,突然在某一步飙升到 NaNInf,随后整个训练进程崩溃。查看日志,通常会发现是 AMP scaler 在反向传播时未能正确缩放梯度,导致权重更新步长过大。

这个问题在 NVIDIA 平台上可能通过调整 loss_scale 解决,但在 AMD 环境下,由于底层算子实现的差异,更彻底的方案是直接禁用混合精度,启用纯 FP32 模式。

修改配置文件是最直接的方法。将上述 YAML 中的 fp16bf16 均设为 false。但这还不够,还需要检查 DeepSpeed 的 ZeRO 配置。编辑 examples/deepspeed/ds_z3_config.json,确保 gradient_clipping 被设置为一个合理的值(例如 1.0),这能在硬件层面强行截断过大的梯度:

{
  "gradient_clipping": 1.0,
  "zero_optimization": {
    "stage": 3,
    "offload_optimizer": {
      "device": "cpu",
      "pin_memory": true
    },
    "allgather_partitions": true,
    "allgather_bucket_size": 5e8,
    "overlap_comm": true,
    "reduce_scatter": true,
    "reduce_bucket_size": 5e8,
    "contiguous_gradients": true
  },
  "fp16": {
    "enabled": false,
    "auto_cast": false
  },
  "bf16": {
    "enabled": false
  }
}

有些同学会担心纯 FP32 会爆显存。其实对于 Qwen-7B 这种量级的模型,配合 LoRA 微调,即使在全精度下,单张 24GB 显存的消费级显卡也能跑得动。如果显存确实紧张,可以适当减小 per_device_train_batch_size,并通过增加 gradient_accumulation_steps 来保持等效的全局 Batch Size,这样既保证了数值稳定性,又控制了内存峰值。

训练监控与效果验证

配置修改完毕后,启动训练命令:

llamafactory-cli train examples/train_lora/qwen2_lora_sft_rocm.yaml

训练开始后,LLaMA-Factory 会自动在输出目录下生成 trainer_log.jsonl 和绘图数据。由于我们开启了 plot_loss: true,训练结束后可以直接查看损失曲线。

在纯 FP32 模式下,你会观察到一条平滑下降的 Loss 曲线,不再出现之前那种断崖式的 NaN 跳变。特别是在处理长文本序列时,FP32 的数值精度优势非常明显,模型能够更稳定地学习长距离依赖关系。虽然训练速度相比半精度模式可能会有 20%-30% 的下降,但换来的是训练过程的“坚挺”和最终模型权重的可靠性。

对于研究人员来说,时间成本固然重要,但复现性和结果的准确性更是底线。在 AMD 生态尚在快速迭代的当下,牺牲一点算力换取稳定的实验结果,无疑是性价比最高的选择。当看到验证集 Loss 稳步收敛,且生成的回复逻辑清晰、无乱码时,你就知道这套“退一步海阔天空”的 FP32 策略奏效了。

200小时GPU算力已就位,快来领取:https://marketing.csdn.net/questions/Q2604140858304426315?utm_source=AIpaper
在这里插入图片描述

更多推荐