使用 PyTorch 进行微调

使用 Pytorch 在本地微调模型

基本思路

本指南将指导您如何在 NVIDIA Spark 设备上设置和使用 Pytorch 来微调大型语言模型。

您将完成

您将在 NVIDIA Spark 设备上为大型语言模型(1-700 亿参数)搭建一个完整的微调环境。最终,您将拥有一个支持参数高效微调 (PEFT) 和有监督微调 (SFT) 的可用安装环境。

前置知识

  • 有在 PyTorch 中微调的经验

  • 使用 Docker

先决条件

这些配置专为 DGX SPARK 设计。请确保操作系统和驱动程序均为最新版本。

辅助文件

GitHub 仓库中的文件夹中包含了所有微调所需的文件。

时间和风险

  • 预计时间:设置和运行微调需要 60-90 分钟。微调运行时间因模型尺寸而异。

  • 风险等级:模型下载文件可能很大(几 GB),ARM64 软件包兼容性问题可能需要故障排查。
  • 最后更新时间:2025 年 1月 15 日
    • 添加两个 Spark 分布式微调示例

    • 添加在 Qwen3 4B、Qwen2.5 7B、Qwen2.5 72B 型号上运行完整 SFT、LoRA 和 qLoRA 工作流程的详细说明。

第 1 步 – 配置 Docker 权限

要轻松管理容器而无需使用 sudo,您必须处于 Docker 组中。如果您选择跳过此步骤,则需要使用 sudo 运行 Docker 命令。
打开一个新的终端并测试 Docker 访问权限。在终端中运行:

docker ps

如果您看到权限被拒绝错误(例如 permission denied while trying to connect to the Docker daemon socket),请将您的用户添加到 docker 组,这样就不再需要使用 sudo 命令。

sudo usermod -aG docker $USER
newgrp docker

第 2 步 – 拉取最新的 PyTorch 容器

docker pull nvcr.io/nvidia/pytorch:25.11-py3

第 3 步 - 启动 Docker

docker run --gpus all -it --rm --ipc=host \
-v $HOME/.cache/huggingface:/root/.cache/huggingface \
-v ${PWD}:/workspace -w /workspace \
nvcr.io/nvidia/pytorch:25.11-py3

第 4 步 - 在容器内安装依赖项

pip install transformers peft datasets trl bitsandbytes

第 5 步 - 使用 Huggingface 进行身份验证

hf auth login
#<input your huggingface token.
#<Enter n for git credential>

第 6 步 - 克隆包含微调配置的 git 仓库

git clone https://github.com/NVIDIA/dgx-spark-playbooks
cd dgx-spark-playbooks/nvidia/pytorch-fine-tune/assets

第 7 步 - 运行微调程序

可用的微调脚本

我们提供了以下微调脚本,每个脚本都针对不同的模型大小和训练方法进行了优化:

脚本
模型
微调类型
描述
Llama3_3B_full_finetuning.py
Qwen3 4B
Full SFT
完全监督式微调(所有参数均可训练)
Llama3_8B_LoRA_finetuning.py
Qwen2.5 7B
LoRA
低秩自适应(参数高效)

Llama3_70B_LoRA_finetuning.py
Qwen2.5 72B
LoRA
支持 FSDP 的低秩自适应
Llama3_70B_qLoRA_finetuning.py
Qwen2.5 72B
QLoRA
量化的 LoRA(4 位量化以提高内存效率)

基本用法

使用默认设置运行任意脚本:

# Full fine-tuning on Qwen3 4B
python Llama3_3B_full_finetuning.py --model_name Qwen/Qwen3-4B

# LoRA fine-tuning on Qwen 2.5 7B
python Llama3_8B_LoRA_finetuning.py --model_name Qwen/Qwen2.5-7B

# qLoRA fine-tuning on Qwen2.5 72B
python Llama3_70B_qLoRA_finetuning.py --model_name unsloth/Qwen2.5-72B-Instruct-bnb-4bit

常用命令行参数

所有脚本均支持以下命令行参数自定义:

模型配置

  • --model_name:模型名称或路径(默认值:因脚本而异)

  • --dtype:模型精度 - float32,float16, 或者 bfloat16 (默认: bfloat16)

训练配置

  • --batch_size:每个设备的训练批次大小(默认值:因脚本而异)

  • --seq_length:最大序列长度(默认值:2048)

  • --num_epochs:训练轮数(默认值:1)

  • --gradient_accumulation_steps:梯度累积步数(默认值:1)

  • --learning_rate:学习率(默认值:因脚本而异)

  • --gradient_checkpointing:启用梯度检查点以节省内存(标志)

LoRA 配置(仅限 LoRA 和 QLoRA 脚本)

  • --lora_rank:LoRA rank 值越高 = 可训练参数越多(默认值:8)

日志配置

  • --logging_steps:每隔 N 步记录指标(默认值:1)

  • --log_dir:TensorBoard 日志目录(默认值:logs)

模型保存

  • --output_dir:保存微调模型的目录(默认值:None - 模型未保存)

常用命令行参数

python Llama3_8B_LoRA_finetuning.py --model_name Qwen/Qwen2.5-7B \
--dataset_size 100 \
--num_epochs 1 \
--batch_size 2
错误
原因
修复
无法访问 URL 的受限存储库
部分 HuggingFace 模型的访问权限受限
重新生成 HuggingFace token 并在浏览器上请求访问门控模型
多 Spark 运行中的错误和超时
各种原因
建议设置以下变量以启用额外的日志记录和运行时一致性检查。
ACCELERATE_DEBUG_MODE=1
ACCELERATE_LOG_LEVEL=DEBUG
TORCH_CPP_LOG_LEVEL=INFO
TORCH_DISTRIBUTED_DEBUG=DETAIL
任务:非零退出代码 (255)
容器退出,错误代码为 255
使用以下命令 docker ps -a --filter "name=finetuning-multinode"获取容器 ID,然后 docker logs 查看详细错误信息
无法连接到 unix:///var/run/docker.sock 的 Docker 守护进程。Docker 守护进程是否正在运行?
Docker Swarm 尝试绑定到过期或无法访问的链路本地 IP 地址,导致 Docker 守护进程崩溃。
停止 Docker sudo systemctl stop docker
移除 Swarm 状态 sudo rm -rf /var/lib/docker/swarm
重启 Docker sudo systemctl start docker
使用处于活动状态的网络接口上的有效广播地址重新初始化 Swarm

注意:

DGX Spark 使用统一内存架构 (UMA),支持 GPU 和 CPU 之间的动态内存共享。由于许多应用程序仍在更新以利用 UMA,即使在 DGX Spark 的内存容量范围内,您也可能会遇到内存问题。如果发生这种情况,请手动刷新缓冲区缓存:

sudo sh -c 'sync; echo 3 > /proc/sys/vm/drop_caches'

第 1 步 – 配置 Docker 权限

请按照连接两个 Spark 进行网络设置以建立 DGX Spark 节点之间的连接。

这包括:

  • QSFP 物理电缆连接

  • 网络接口配置(自动或手动 IP 分配)

  • 无密码 SSH 设置

  • 网络连接性验证

第 2 步 – 配置 Docker 权限

要轻松管理容器而无需使用 sudo,您必须处于 Docker 组中。如果您选择跳过此步骤,则需要使用 sudo 运行 Docker 命令。
打开一个新的终端并测试 Docker 访问权限。在终端中运行:

docker ps

如果您看到权限被拒绝错误(例如 permission denied while trying to connect to the Docker daemon socket),请将您的用户添加到 docker 组,这样就不再需要使用 sudo 命令。

sudo usermod -aG docker $USER
newgrp docker

第 3 步 – 安装 NVIDIA Container Toolkit 并设置 Docker 环境

确保每个GPU 节点(包括 manager 和 worker)都安装了 NVIDIA 驱动和 NVIDIA Container Toolkit。此软件包使 Docker 容器能够访问主机的 GPU 硬件。请确保完成以下安装步骤,包括 Docker 配置适用于 NVIDIA Container Toolkit。

第 4 步 - 启用资源广播

首先,运行以下命令查找您的 GPU UUID:

nvidia-smi -a | grep UUID

接下来,修改 Docker 守护进程配置,使其向 Swarm 广播这块 GPU。编辑 /etc/docker/daemon.json

sudo nano /etc/docker/daemon.json

添加或修改文件以包含 NVIDIA runtime 和 GPU UUID(替换 GPU-45cbf7b3-f919-7228-7a26-b06628ebefa1 为您实际的 GPU UUID):

{
  "runtimes": {
    "nvidia": {
      "path": "nvidia-container-runtime",
      "runtimeArgs": []
    }
  },
  "default-runtime": "nvidia",
  "node-generic-resources": [
    "NVIDIA_GPU=GPU-45cbf7b3-f919-7228-7a26-b06628ebefa1"
    ]
}

将 NVIDIA Container Runtime 修改为向 Swarm 广播 GPU,方法是在 config.toml 文件中取消注释 swarm-resource 这一行。您可以使用喜欢的文本编辑器(例如 vim、nano 等)或以下命令来完成此操作:

sudo sed -i 's/^#\s*\(swarm-resource\s*=\s*".*"\)/\1/' /etc/nvidia-container-runtime/config.toml

最后,重启 Docker 守护进程以应用所有更改:

sudo systemctl restart docker

对所有节点重复这些步骤。

第 5 步 - 初始化 Docker Swarm

在任意想要用作主节点的节点上,运行以下集群初始化命令

docker swarm init --advertise-addr $(ip -o -4 addr show enp1s0f0np0 | awk '{print $4}' | cut -d/ -f1) $(ip -o -4 addr show enp1s0f1np1 | awk '{print $4}' | cut -d/ -f1)

上述命令的典型输出类似以下内容:

Swarm initialized: current node (node-id) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token <worker-token> <advertise-addr>:<port>

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

第 6 步 - 加入 worker 节点并部署

现在可以开始设置集群的 work节点。在所有worker节点上重复以下步骤。

在每个工作节点上运行 docker swarm init 命令,以加入 Docker swarm 集群。

docker swarm join --token <worker-token> <advertise-addr>:<port>

在两个节点上,下载 pytorch-ft-entrypoint.sh 将脚本放入包含微调脚本和配置文件的目录中,然后运行以下命令使其可执行:

chmod +x $PWD/pytorch-ft-entrypoint.sh

在主节点上,通过将 docker-compose.yml 文件下载到与前一步相同的目录中,确认本机 CX7 网口名称,在终端中运行:

ip a

找到你为 Spark 之间通信配置的 IP(例如 192.168.100.x 所在的网段),记下该 IP 所在的网口名(例如 enp1s0f0np0)
在运行 Stack 的目录中,编辑 docker-compose.yml:
nano docker-compose.yml
在 finetunine 服务的 environment 段,将下面三行修改为你实际的 CX7 网口名称:

UCX_NET_DEVICES=<你的网口名>
NCCL_SOCKET_IFNAME=<你的网口名>
GLOO_SOCKET_IFNAME=<你的网口名>

保存文件后运行以下命令来部署 Finetuning 多节点堆栈:

docker stack deploy -c $PWD/docker-compose.yml finetuning-multinode

注意:

请确保将两个文件下载到运行该命令的同一目录中。

您可以使用以下方法验证 worker 节点的状态

docker stack ps finetuning-multinode

如果一切正常,您应该会看到类似以下内容的输出:

nvidia@spark-1b3b:~$ docker stack ps finetuning-multinode
ID             NAME                                IMAGE                              NODE         DESIRED STATE   CURRENT STATE            ERROR     PORTS
vlun7z9cacf9   finetuning-multinode_finetunine.1   nvcr.io/nvidia/pytorch:25.10-py3  spark-1d84   Running         Starting 2 seconds ago             
tjl49zicvxoi   finetuning-multinode_finetunine.2   nvcr.io/nvidia/pytorch:25.10-py3  spark-1b3b   Running         Starting 2 seconds ago    

注意:

如果您的“当前状态”不是“正在运行”,请参阅故障排除部分以获取更多信息。

第 7 步 - 查找您的 Docker 容器 ID

您可以使用 docker ps 查找 Docker 容器 ID。您可以将容器 ID 保存到一个变量中,如下所示。在两个节点上运行此命令。

export FINETUNING_CONTAINER=$(docker ps -q -f name=finetuning-multinode)

第 8 步 - 修改配置文件

对于多节点运行,我们提供 2 个配置文件:

需要修改这些配置文件:

  • 在每个节点上设置 machine_rank,对应它的节点序号。主节点应为 rank 0,第二个节点为 rank 1。

  • 使用主节点的 IP 地址设置 main_process_ip。确保所有配置文件中的该值一致。可以在主节点上使用 ifconfig 命令来查找 CX-7 网卡的正确 IP 地址。

  • 设置一个可以在主节点上使用的端口号。

YAML 文件中需要填写的字段:

machine_rank: 0
main_process_ip: < TODO: specify IP >
main_process_port: < TODO: specify port >

所有脚本和配置文件都可以在仓库找到。

第 9 步 - 运行微调脚本

成功完成前面步骤后,您可以运行本仓库提供的任一run-multi-llama_* 脚本来执行微调。以下是使用 LoRa 和 FSDP2 微调 Qwen2.5 72B 的示例。

# Need to specify huggingface token for model download.
export HF_TOKEN=<your-huggingface-token>

docker exec \
  -e HF_TOKEN=$HF_TOKEN \
  -it $FINETUNING_CONTAINER bash -c '
  bash /workspace/install-requirements;
  accelerate launch --config_file=/workspace/configs/config_fsdp_lora.yaml /workspace/Llama3_70B_LoRA_finetuning.py --model_name Qwen/Qwen2.5-72B'

对所有节点重复这些步骤。

运行过程中,微调进度条只会显示在主节点的标准输出(stdout)上。这是符合预期的因为 accelerate 使用了基于 tqdm 的封装只在主进程显示进度,具体说明参考这里。 在worker 节点使用 nvidia-smi 可以看到 GPU 正在使用。

第 10 步 - 清理和回滚

在主节点使用以下命令停止并移除容器:

docker stack rm finetuning-multinode

删除已下载的模型以释放磁盘空间:

rm -rf $HOME/.cache/huggingface/hub/models--meta-llama* $HOME/.cache/huggingface/hub/datasets*

资源

DGX Spark 文档

DGX Spark 论坛

DGX Spark 用户性能指南