上个月我们把千问7B的LoRA微调任务从单机单卡迁到优云智算平台的多机多卡集群上,原本以为只是“多租几台机器、改一下启动命令”的事,结果从资源开通、容器环境到NCCL通信,前前后后折腾了将近一周。中间最崩溃的一次是四台机器、八张卡都正常识别了,训练进程一启动就卡在NCCL初始化上,日志里报超时,换了三种排查思路才定位到是节点间端口没有完全放通。这篇文章就把整个部署过程、踩坑点、最终能稳定跑起来的配置原原本本写出来,希望能帮到打算在GPU算力平台上做多机多卡微调的人。
文章内容面向的读者很明确:已经能在单机上跑通大模型微调、想扩展到多机多卡的朋友,或者是刚接手算力平台、需要帮算法团队搭训练环境的运维同学。你会看到从需求拆解、集群规划,到安装部署、跑通训练,再到问题排查的完整链路。整篇以LLaMA-Factory作为微调工具链为例,因为它在千问、Llama等主流模型上支持LoRA、freeze、全量微调,配置简单,是目前社区里最常用的一站式方案之一。
1. 部署前必须想清楚的事:多机多卡不等于机器数量相加
很多人的第一反应是“我把机器买够了,环境照旧装,训练跑起来就行”。实际上多机多卡部署最大的坑不在安装,而在架构规划。硬件资源怎么选、节点间怎么通信、用什么方式做分布式训练、微调策略和资源是否匹配,这些问题没想清楚,后面环境搭得再漂亮也会反复返工。
1.1 微调方式先定:全量、freeze还是LoRA影响资源规划
微调的三种主流方式——全量微调(Full Fine-tuning)、Freeze微调和LoRA微调,对显存、通信、训练时长的需求差异非常大。
全量微调需要更新模型的全部参数,训练时除了模型权重,还要保存梯度、优化器状态(比如AdamW的动量项)。一份7B模型在bf16精度下权重约占14GB,但完整训练状态的显存开销通常是权重的3到5倍甚至更高。如果序列长度长、批次大,一张A100 80GB不一定放得下7B的全量微调。而且全量微调过程中每一层参数都在变化,梯度同步的数据量非常大,多机通信压力显著。
Freeze微调通常冻结大部分底层参数,只训练顶层或某些特定模块。它的显存开销比全量低,但通信压力仍然不小,因为所有需要更新的梯度仍要跨节点做AllReduce(全归约)。
LoRA微调是很多人做多机多卡的首选。它通过低秩适配器在原始模型旁边插入少量可训练参数,原始权重被冻结,训练时反向传播的梯度只涉及适配器部分。显存占用和通信量都会大幅下降。我实测7B模型用LoRA在一台双卡机器上就能跑得动,扩展到多机多卡更多是为了加快数据遍历速度、用更大总批次提升收敛稳定性。多机多卡对LoRA来说并不是“显存放不下”,更多是“单卡跑太慢,想用更多卡并行”。
这直接影响你资源规划的方向:如果只想跑LoRA,中等显存多卡机器(如A100 40GB或L20 48GB)性价比更高;如果想跑全量微调,应优先考虑高显存机器和高速互联节点。
1.2 算力集群规模估算:按模型参数、序列长度和批次反推显卡数量
我不会一上来就说“配置越高越好”,而是推荐先做一个估算。以7B模型LoRA微调为例,一个比较实用的估算方式是这样的:
训练时每张卡的主要显存占用包括:
- 模型权重 + LoRA适配器权重:bf16下约15GB(含临时推理激活)
- 梯度:只算LoRA参数时很小,但如果开了ZeRO或者全量更新,要按全参数量估算
- 优化器状态:LoRA微调可以显著压缩,但AdamW状态依然和参与训练的参数量成正比
- 激活值:取决于批次大小×序列长度×模型层数
实际操作中,LoRA加序列长度2048、per_device_train_batch_size设为1到2时,7B模型在24GB显存的卡上即可启动。需要多少张卡取决于总批次(global batch size)和目标训练时长。比如你想达到global batch size 64,如果per_device_train_batch_size=2,数据并行度为32,单机8卡需要4台机器。如果预算有限也可以用梯度累积让每张卡的实际批次更小,但通信效率和BatchNorm之外的问题也要考虑。
在优云智算这类算力平台上开工前,还需要确认平台单资源组最多关联多少节点、这些节点是否在同一个机房内网、是否支持高带宽互联。如果平台把两台机器分在不同可用区,即使你能SSH登录,训练效率也可能很差。
1.3 节点互联方式决定了你能跑多快:RoCE、IB与普通以太网的区别
多机训练中有一句话我非常认同:单卡看显存,多卡看通信。分布式训练每个step都需要跨节点同步梯度。以7B全量微调为例,一次AllReduce要传输的数据量约等于模型参数量乘梯度字节数,大概几十GB。如果节点间走的是普通千兆以太网,一个batch光同步梯度就要等很久,GPU利用率长期处于个位数。
较新的算力平台通常会提供RDMA网络,包括InfiniBand(IB)和RoCE(RDMA over Converged Ethernet)。它们让GPU可以绕过CPU、直接访问远端内存,延迟低、CPU负载小。如果你在多机环境里跑训练明显比单机慢,先不要急着优化代码,先用ibstatus、ibv_devinfo这类工具确认是否真的检测到了RDMA设备,或者登录平台控制台查看节点类型是否标注了“高带宽互联”。如果只有普通以太网,建议优先在同一台8卡机器上扩卡,而不是强行做4台2卡训练。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 优云智算平台上的集群开通与基础配置:不踩权限坑
集群规划好之后,进入实际开通和配置环节。这个阶段最大的矛盾是“算法工程师想要快速跑起来”和“运维同学要保证环境一致、权限可控”之间的矛盾。平台上的多机集群通常不是简简单单给每台机器装上环境就行,需要把账号体系、存储、镜像、网络权限一起打通。
2.1 资源组、共享存储与镜像仓库的打通流程
在优云智算平台(以及其他同类算力平台)上,我第一次部署时就发现一个很关键的点:资源隔离和网络会按照“资源组”划分。算法团队需要把多台GPU实例加入同一个资源组,才能保证节点间二层网络互通、方便挂载同一份共享存储。开通多机多卡集群的推荐顺序是:
- 在平台上创建一个专用资源组,把训练所需的GPU节点全部加入该资源组。
- 申请一块共享存储(如并行文件系统或NAS),把它挂载到所有节点的同一路径下,比如
/mnt/shared。 - 在镜像仓库准备一个训练镜像,或者选择平台预置的PyTorch镜像。
- 创建专用部署账号,把SSH公钥批量注入所有节点。
每台节点建议选择相同的操作系统镜像和GPU驱动版本。现实中很多奇怪的分布式训练问题,比如某张卡莫名其妙地OOM、显存信息显示异常,最后查出来是某个节点驱动版本和容器不完全兼容。多机环境下“环境一致”是减少随机问题的第一原则。
2.2 节点互信与SSH免密:多机训练的“地基”
多机分布式训练需要各进程能通过SSH互相访问。torchrun默认就是通过SSH登录远端节点启动worker进程。每个节点至少需要能免密访问其他所有节点。
我习惯的做法是:
- 在每台节点上创建同一个部署用户(如
train),不要直接用root,避免容器内外用户ID不同导致数据目录权限错乱。 - 在管理节点生成一对专用密钥,不设passphrase。
- 将公钥追加到所有节点的
/home/train/.ssh/authorized_keys。 - 在
~/.ssh/config里配置好每个节点的主机别名、IP和登录用户。
多机环境最怕的是“部分节点互通、部分节点不通”。建议配置完成后写一个小循环脚本,在管理节点上批量执行ssh 节点IP hostname,确认全部返回正常。这个动作做一次不过两分钟,能省掉后面排查NCCL超时的半天时间。
2.3 容器镜像里必须装齐的东西:PyTorch、CUDA、NCCL与框架版本匹配
镜像选型是决定多机训练是否顺利的另一个关键点。我不推荐在裸机上一点点装CUDA和PyTorch,太容易因为某个节点的动态库不一致而出问题。直接用官方PyTorch镜像是个省心方案,但要注意版本匹配问题。
很多人在这一步忽略的是NCCL(NVIDIA Collective Communications Library)的存在。PyTorch官方镜像通常自带NCCL,但如果你后续手动换了CUDA或编译过什么组件,很可能导致NCCL版本与驱动不匹配,最终表现为节点间通信直接hang死。如果你要编译flash-attention这类对CUDA版本敏感的自定义算子,建议基于一个固定的PyTorch镜像构建业务镜像,把依赖提前装好,不要在训练机上临时pip install大量包。
我这里给一套相对稳妥的组合(以LLaMA-Factory为例):
| 组件 | 建议版本 | 说明 |
|---|---|---|
| 驱动 | >= 535 | 需要和新版CUDA、NCCL兼容 |
| CUDA | 12.1或12.4 | 取决于所选PyTorch版本 |
| PyTorch | 2.1以上 | 原生支持torchrun和NCCL |
| LLaMA-Factory | 0.9.x或最新稳定版 | 如果从源码安装,注意它依赖的transformers版本 |
| transformers | 4.43以上 | 版本过低可能不支持Qwen2类模型 |
这些组件之间的版本关系特别容易踩坑。我记得有一次L拉取modelscope模型后反序列化失败,发现问题出在transformers版本太老,不认新模型的config字段。因此部署前最好在单机上先把“模型加载 + 单卡跑通”验证一遍,再把镜像同步到集群,而不是直接上多机。
3. 建立分布式训练运行时:NCCL、环境变量与共享内存
多台GPU节点准备就绪后,我们面临一个非常重要的问题:怎么让多个进程互相知道对方、协作训练一个模型。这里涉及的是分布式训练运行时,包括进程启动器、通信库和运行环境配置。环境变量和参数如果设置错了,会出现一些非常诡异的错误,例如有的节点进程起来了、有的起不来,或者所有进程都在等一个永不出现的master。
3.1 多机训练的进程启动模型:用torchrun而不是自己写mp.spawn
PyTorch提供的torchrun是目前启动多机多卡训练最简单可靠的方式。它把环境变量自动注入每个worker进程,自动处理节点故障的退出和重启逻辑。你需要正确设置的几项包括:
--nnodes:总节点数,比如4。--nproc_per_node:每台机器上使用的GPU数,比如8。--master_addr:master节点的IP地址(管理节点)。--master_port:master节点上监听的端口,如29500。- rank相关参数:
torchrun会自动分配RANK和LOCAL_RANK,不需要手动指定每个节点的rank。
我之前看到有人写多机训练脚本时自己在每台机器上硬编码node rank,稍不注意就会重复或漏掉,非常容易出问题。用torchrun的标准姿势是在master节点和执行节点上运行几乎一样的命令,--master_addr都指向同一个IP。
一个典型的启动命令是:
bash复制torchrun \
--nnodes=4 \
--nproc_per_node=8 \
--master_addr=192.168.1.100 \
--master_port=29500 \
--node_rank=0 \
src/train_bash.py \
...
除master节点外,其余每个节点启动时以上命令基本一致,只需把--node_rank改为当前节点的编号。可能让人困惑的是“每个节点都要启动一次”这件事。很多人在worker节点上只准备了环境,却忘了手动启动,结果master一直等不到进程。相较之下,有些平台会帮你统一拉起,但本质逻辑是一样的。
3.2 NCCL通信链路检查:先跑通一个最小的AllReduce脚本再谈训练
我强烈建议在跑正式训练前,先写一个极小的多卡通信测试脚本,验证节点间NCCL是否真的能正常通信。这个步骤如果能通过,后续训练启动出现的问题就基本集中在框架配置上;如果这个都过不了,说明通信链路有问题,再多的业务排查都是浪费时间。
简单测试脚本如下:
python复制import os
import torch
import torch.distributed as dist
dist.init_process_group(backend="nccl")
rank = dist.get_rank()
world_size = dist.get_world_size()
tensor = torch.tensor([rank]).cuda()
dist.all_reduce(tensor, op=dist.ReduceOp.SUM)
print(f"Rank {rank} after allreduce: {tensor.item()}")
dist.destroy_process_group()
然后在master节点上用下面的命令启动四节点测试:
bash复制torchrun --nnodes=4 --nproc_per_node=1 --master_addr=192.168.1.100 --master_port=29500 test_nccl.py
如果脚本能在每个节点输出正确的allreduce结果,说明SSH互信、NCCL库、GPU间通信都是通的。如果卡住不输出,大概率是网络端口未放通或通信库初始化失败。
记得有一次测试卡在NCCL INFO NET/Plugin : No plugin found,后面并没有报error,只是长时间没有输出。后来发现是NCCL在回退到TCP通信,而TCP通信要解析的节点主机名在/etc/hosts里缺失。把节点主机名和IP的映射关系补齐后,通信恢复顺畅。这类经验真的能帮你快速判断问题层面。
3.3 共享内存与Docker的shm-size:跑训练前必须改的默认值
如果你是用容器跑训练,有一个非常不起眼但影响巨大的配置:/dev/shm的大小。Docker容器默认的/dev/shm只有64MB,但PyTorch DataLoader在num_workers>0时,多个worker进程通过共享内存传输数据,一旦数据量大,直接报Bus error或No space left on device。
多机环境里还有另一个隐藏依赖:NCCL也可能使用共享内存做进程间通信。虽然NCCL对GPU Direct和共享内存的依赖在单机多卡下更明显,但保险起见,启动容器时建议加上:
bash复制docker run --gpus all \
--shm-size=32g \
--network=host \
-v /mnt/shared:/workspace \
...
--network=host也非常重要。容器的默认bridge网络会做NAT,多机节点之间通信需要额外做端口映射才能互通。使用host网络模式,容器直接使用宿主机的网络栈,NCCL通信才能拿到真实IP,避免网络隔离带来的各种连接问题。
4. 用LLaMA-Factory跑一遍多机LoRA/全量微调:从配置到启动
基础设施没问题之后,就可以把微调任务真正跑起来了。我以LLaMA-Factory作为示例,因为它在多机多卡场景下的配置方式很典型,理解了这个框架的启动方式,很多其他框架的思路也大同小异。这里不会走“界面点点点”的流程,而是用命令行和YAML配置落地,方便在集群上批量执行。
4.1 配置文件里的关键字段:模型路径、数据集路径与并行策略
LLaMA-Factory在单机和多机场景下的训练入口差不多,区别主要在底层分布式启动参数。一个典型的LoRA微调YAML配置如下:
yaml复制model_name_or_path: /mnt/shared/models/qwen/Qwen2-7B-Instruct
template: qwen
stage: sft
finetuning_type: lora
lora_rank: 8
lora_alpha: 16
dataset: /mnt/shared/data/alpaca_zh_51k.json
cutoff_len: 2048
per_device_train_batch_size: 2
gradient_accumulation_steps: 8
learning_rate: 2.0e-5
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
output_dir: /mnt/shared/output/qwen-lora
logging_steps: 10
save_steps: 500
多机环境下,我建议把model_name_or_path指向共享存储路径,而不是每台机器本地都存一份模型。原因很简单:7B模型约14GB,四台机器每台拷一份就是56GB,如果数据存储同步不及时还容易出现版本不一致。共享存储只需一份,所有节点都能访问,部署后的实际体验会好很多。
dataset路径也一样,放到共享存储上。但在训练跑起来后,各节点的DataLoader会同时读取同一份文件,如果底层存储IO能力不够,可能出现训练loss长时间不变、GPU利用率波动大的情况。后续会专门说这个问题,通常的应对是拉取到本地缓存目录。
4.2 多机启动命令的完整写法:node_rank、master_addr与端口
假设集群拓扑如下:
- master节点:
192.168.1.10 - worker-1节点:
192.168.1.11 - worker-2节点:
192.168.1.12 - worker-3节点:
192.168.1.13 - 每台节点4张GPU,共16卡
在master节点上执行:
bash复制torchrun \
--nnodes=4 \
--nproc_per_node=4 \
--master_addr=192.168.1.10 \
--master_port=29500 \
--node_rank=0 \
src/train_bash.py \
--config_file qwen_lora.yaml
在worker-1节点上执行:
bash复制torchrun \
--nnodes=4 \
--nproc_per_node=4 \
--master_addr=192.168.1.10 \
--master_port=29500 \
--node_rank=1 \
src/train_bash.py \
--config_file qwen_lora.yaml
其他worker节点同理,node_rank分别设为2和3。这种模式对所有参与节点一视同仁,唯一的“管理节点”是IP地址为192.168.1.10的那台主机。如果master节点因为某种原因挂了,训练也会中断。条件允许时可以租一台不跑GPU的轻量管理节点专门负责调度和存储,会更稳定。
有一种说法是“既然有torchrun,我是不是在worker节点也要装完整的Python和模型依赖”?答案是是的。每个节点都需要能自己加载模型、执行训练脚本。torchrun只是把启动指令分发到各个节点,但节点自身必须环境完整。这也是为什么我一直强调提前打好镜像,而不是靠每台机器即时安装。
4.3 全量微调、Freeze微调与LoRA在多机下的资源差异
跑通一个LoRA之后,很多团队的下一步是尝试全量微调或Freeze微调。此时最好提前知道三者在多机环境下的实际差异:
| 项目 | LoRA微调 | Freeze微调 | 全量微调 |
|---|---|---|---|
| 可训练参数量 | 极小(如7B模型的0.1%) | 部分层/参数 | 全部参数 |
| 单卡显存压力 | 低 | 中 | 高 |
| 梯度通信量 | 低 | 中 | 高 |
| 适用场景 | 大多数任务,快速迭代 | 目标任务较接近原域 | 数据分布差异大时 |
| 多机扩展收益 | 提速主要靠大batch | 兼顾质量和速度 | 大batch和长上下文必需 |
如果你在多机环境里做全量微调,建议配合DeepSpeed ZeRO Stage 2或Stage 3使用,在代码和配置上会有额外的ZeRO配置。LLaMA-Factory对deepspeed的支持做得不错,需要在启动命令中加入类似这样一段:
bash复制torchrun --nnodes=4 --nproc_per_node=4 --master_addr=192.168.1.10 --master_port=29500 \
src/train_bash.py \
--config_file qwen_full_finetune.yaml \
--deepspeed ds_z3_config.json
其中ds_z3_config.json里可以设置zero_optimization.stage=3,并开启offload_optimizer以进一步降低GPU显存压力。多机全量微调对共享存储的带宽和IOPS要求更高,因为各个节点需要频繁读取/写入模型分片。
5. 训练监控与稳定性:看日志、看GPU、看网络,还要小心超时
训练一旦拉起,不是盯着loss曲线往下掉就万事大吉。多机环境的监控对象比单机多出一个维度:节点间通信质量。训练跑到一半GPU利用率从90%跌到20%,或者出现间歇性hang住,这在多机环境里很常见。本节讲一些我常用的监控和稳定性保障手段。
5.1 用NCCL_DEBUG、nvidia-smi和平台监控区分瓶颈在计算还是通信
多机训练性能问题排查的第一条经验是:先确认瓶颈在哪一层,是计算、IO还是通信。可以使用nvidia-smi查看每张卡的利用率,如果所有卡利用率都持续偏低,例如低于30%,大概率是数据加载太慢或卡在通信等待。
判断通信是否正常的常用办法是设置环境变量NCCL_DEBUG=INFO并重新启动一个较小规模的训练或测试脚本。开启后,NCCL会在初始化阶段打印大量信息,例如:
text复制NCCL INFO NET/IB : Using dev mlx5_0
NCCL INFO NET/Socket : Using [0]...
NCCL INFO Call to connect returned Connection timed out
如果能看到NET/IB,说明NCCL走的是InfiniBand;如果只有NET/Socket,说明在用TCP回退。正常使用时我们当然希望走RDMA,这个日志可以帮助确认通信路径是否合理。日志中一旦出现Connection timed out或failed to connect字样,基本上可以确定某个节点连接不上master,或某个端口被封掉。
平台的监控面板也要配合使用。优云智算平台这类服务通常有节点级监控,能看到每台GPU实例的上下行带宽。如果训练中某两个节点间带宽始终跑不满,而节点内在同资源组的机器确实具备高带宽互联,那可能是平台分配机器时跨了交换机,需要联系平台客服调整资源组内的物理部署位置。
5.2 多机训练的checkpoint同步策略:共享存储、自动保存与避免覆盖
多机训练崩溃时最让人心疼的是训练了十几个小时,因为一个节点故障导致前面全部白跑。因此,checkpoint策略要在训练开始前设计好,而不是出问题时才想。
我比较推荐的方式是:
- 将
output_dir设置在共享存储中,比如/mnt/shared/output/qwen-lora。 - 调低
save_steps,例如每200到500步保存一次,宁愿多占一点存储,也不要让长时间训练无保存。 - 每次保存时写到一个带step编号的子目录,避免临时文件的覆盖导致checkpoint损坏。
- 训练被中断后,用
--resume_from_checkpoint指定最近一次checkpoint继续训练。
这里需要特别提醒:如果是全量微调或多机并行,保存的checkpoint可能包含多个分片(由不同的rank各自保存),比如在使用ZeRO Stage 3时,每个节点只保存了模型的一部分。恢复训练时,必须确保所有节点都能访问到完整的共享存储路径,否则会有某个rank读取不到对应分片的问题。这种问题最坑的是报错信息不明显,可能只是某节点等待超时。
5.3 平台配额超限、实例被释放时的应对
在优云智算这类算力平台上还会遇到一个本地机房不常见的问题:实例可能因为配额到期或账户欠费被释放。释放意味着节点上的本地盘数据全部消失。即使你有训练中的checkpoint在共享存储上,一些本来放在本地的临时文件、日志、容器内的中间产物也会一起丢失。
我的应对方式是:
- 把所有重要的代码、数据集和输出checkpoint全部放到共享存储或对象存储,而不是放在容器根目录或节点本地磁盘。
- 在训练启动命令里将日志实时写到共享存储路径,这样即使实例被释放,也能通过日志定位最后的状态。
- 关注平台的到期提醒,在长时间训练前确认资源租期覆盖训练周期,必要时提前续费。
很多分布式训练的失败都不是因为算法本身,而是因为某个外围资源失效,比如IP变了、存储掉了、密钥失效。训练越长时间,越要做好这种“外围容灾”。
6. 实际踩过的坑和性能调优结论:从失败到稳定跑通
最后这部分我整理这次在算力平台上部署多机多卡微调环境过程中真正踩过、也实际解决的坑。如果这些细节能帮你少走点弯路,那这篇文章的价值就达到了。
6.1 部署中最容易让你怀疑人生的三个问题
第一个坑是端口放通。我们第一次跑NCCL测试时,master节点上的29500端口没有在安全组策略里放通,worker节点连不上master,进程直接hang住。最迷惑的是SSH是可以连通的,因为SSH用了22端口。排查过程一度怀疑是NCCL版本问题,后来是在master节点用ss -lntp看到了监听端口,用telnet 192.168.1.10 29500从worker节点去试,才发现网络不通。部署前先把各节点之间需要互访的端口(如29500、6000等)都验证一遍,省掉的远不止半小时。
第二个坑是CUDA/NCCL版本不匹配。平台给镜像预装的驱动版本和新容器内的CUDA版本不匹配时,NCCL会在初始化时报unexpected error,或者干脆在初始化时静默回退到低速路径。排查的终点往往不是业务代码,而是容器镜像。建议固定一套经过验证的镜像组合并把它作为团队标准镜像,防止不同成员装出“每个节点都能跑,但彼此不兼容”的混乱状态。
第三个坑是共享存储IO慢导致数据加载拖垮训练。一开始我们把数据集放在共享存储路径下,单机跑没问题。可是四台节点16个进程同时读同一份JSON文件时,数据集加载变得非常慢,GPU利用率在每轮数据加载时掉到0。后来把数据在训练前同步到每个节点的本地磁盘,再用dataset_dir指向本地,情况立刻好转。这说明使用共享存储时,一定要关注IO并发能力,不能默认“网络存储一定快”。
6.2 多机多卡微调提速的实用参数
部署跑通后,大家关心的自然是怎么把训练速度提上去。有几个参数实测下来很有用:
- 开启
gradient_checkpointing。它通过重新计算前向激活值来降低显存占用,虽然增加约20%的额外计算量,但可以让单张卡放下更大的批次,从而减少梯度同步频率,整体收益通常远大于损失。 - 使用flash-attention或框架内置的注意力优化。序列长度较长时收益非常明显。
- 把
per_device_train_batch_size调大到显存允许的极限,再相应减小gradient_accumulation_steps,这样每个step的通信次数变少,多机扩展效率更高。 - 设置
TORCH_DISTRIBUTED_DETAIL=ERROR或合理的NCCL_TIMEOUT,避免因网络抖动导致的任务长时间无响应。
一个容易被忽略的点是LoRA等低秩方法本身训练速度较快,但如果在多机环境中保存checkpoint过于频繁(如每50步),会频繁写共享存储,把训练时间拉长。建议根据训练总步数平衡save_steps,既保证恢复点可靠,又不至于让保存变成瓶颈。
6.3 个人经验总结:多机环境部署的顺序感和检查清单
从这次部署的教训里,我总结出一条非常有用的“顺序感”:先单机,后多机;先通信,后训练。无论你想直接上多少卡,都建议先在一台节点上跑通单卡或多卡训练,确认代码没有问题;然后跑NCCL小脚本验证通信链路;最后再启动完整的多机训练。任何一步失败,都可以快速定位到对应层面,而不是在一堆变量中盲猜。
下面是我每次在算力平台搭多机训练环境前都会过一遍的检查清单,你也可以直接拿去用:
- [ ] 所有节点的GPU驱动版本一致,通过
nvidia-smi能正确识别所有GPU。 - [ ] 节点间SSH免密互通,从管理节点能批量执行hostname命令。
- [ ] 共享存储在每台节点以同一路径挂载,且读写权限一致。
- [ ] 容器使用host网络模式,
/dev/shm足够大。 - [ ] 训练端口(master_port等)在所有节点间可访问。
- [ ] NCCL最小AllReduce测试跑通。
- [ ] 模型路径、数据集路径在共享存储中可访问。
- [ ] checkpoint保存目录有足够剩余空间。
- [ ] 单机小批量训练和预期loss走势一致。
- [ ] 多机启动命令中master_addr、node_rank配置正确。
多机多卡微调的部署本质上是个“工程问题”,而不是算法问题。很多时间会花在等待、排查、验证上。但一旦基础设施稳定下来,后续再跑其他模型、切换数据集,都会变得丝滑。我在实际部署中的最大体会是:环境搭建别贪快,每一步验证后再往后走,比出了问题回头排查要省时间得多。遇到奇怪问题也别慌,按照通信、存储、镜像三个方向去拆,基本都能找到答案。
