很多人跑来问我“训练速度上不去怎么办”我第一句话基本都是反问你在腾讯云GPU实例上跑还是自建GPU集群这不是寒暄是因为后续所有调优动作都会因为答案不同而完全不一样。AI训练的性能调优表面看是调整一堆参数实际上是在“算、通、存、调”四个瓶颈之间找平衡。云上实例把很多底层细节藏了起来自建集群又把所有细节都摊在你面前这决定了你只能从不同入口开始排查。这篇文章我准备把两边各自的调优思路、关键操作和经验教训放在一起拆开讲希望读了之后能少走点弯路。1. 认知起点先搞明白“算、通、存、调”边界在哪里1.1 性能调优不是调参数而是平衡四个瓶颈AI训练就是反复执行前向传播、反向传播、权重更新。性能调优的目标很简单让GPU尽可能多的时间在跑矩阵乘和卷积而不是等数据、等梯度、等锁。我习惯把瓶颈拆成四个字母算、通、存、调。算GPU算力是否吃满算子是否高效显存是否够用。通多卡甚至多机通信梯度同步消耗了多少时间。存数据加载、checkpoint读写是不是拖后腿。调任务调度、GPU分配、排队和弹性伸缩是否合理。一开始就要想清楚自己手上对这四个维度的“控制权限”到了哪一层。腾讯云GPU实例上实例规格、镜像、安全组、VPC、云盘这些东西由你和云平台共同决定但宿主机内核、物理网络拓扑、驱动细节你都碰不到。自建集群里从网卡固件、交换机流控到OS内核、NVLink拓扑只要你想都可以自己改。这个差异很重要因为调优本质上就是“在你能动的范围内用最小代价消除最大瓶颈”。如果你连自己能动哪些东西都搞不清楚很容易陷入上来就调NCCL参数结果发现瓶颈在数据加载这种尴尬境地。提示先用nvidia-smi看GPU利用率再用iostat看存储最后才查NCCL网络顺序别反。很多调优失败案例都是把“算”的瓶颈误判成“通”或“存”。1.2 可调边界对照云上是配额和镜像自建是硬件和系统我把两边的可调边界整理成一张对照表看完就明白为什么同一个调优方法不能直接搬维度腾讯云GPU实例自建GPU集群实例规格云平台提供套餐选定后是黑盒自己采购配置可选型号GPU驱动/CUDA公共镜像或自定义镜像版本受平台支持限制完全可控可随时切换但兼容性要自己负责网络VPC/HCC带宽和协议由平台决定可调NCCL变量网卡、交换机、协议、流控全可控存储云盘/COS/CFS单实例带宽有上限本地NVMe/并行文件系统条带化自主决定故障恢复快照/重装/新开实例可自动伸缩节点替换/HA调度器控制云上实例的调优多数发生在“买什么样的实例、配多少存储、跑之前写好环境变量”这个阶段而自建集群的调优更多发生在“把物理环境弄到最好再让训练任务把基础设施真正用起来”的阶段。两者目标一样但入口完全不同。2. 网络与多卡通信云上先认通道自建先查链路2.1 通信为什么是第一个要看的点多机训练时每轮迭代都要做梯度同步。模型越大通信占比越高。我见过一些大模型训练梯度同步能占到30%-40%的时间。这时候你哪怕把GPU利用率榨到99%整体效率还是上不去。NCCL是当前主流的集合通信库PyTorch、TensorFlow都会用到。它会自动探测网络环境但“自动”不等于“最优”。尤其在虚拟化环境里NCCL经常认错网卡接口或者误判是否支持RDMA。所以第一步永远是看清楚你的通信通道到底是什么。云上和自建的明显区别云上网络是虚拟化出来的通道类型和拓扑由平台决定你通常只能通过环境变量去适配自建网络是物理链路你可以从网卡驱动、交换机配置到NCCL参数一层一层调。2.2 腾讯云GPU实例网络调优实操在腾讯云上如果你用的是普通VPC里的GPU实例节点之间大概率走TCP如果你用了高性能计算集群HCC节点之间才有RDMA通道。这个前提不搞清楚后面所有参数都是瞎调。判断方法是先开NCCL调试模式跑一个小规模任务看日志里出现的是IB还是Socket。然后按通道类型设置环境变量# 有RDMA的场景通常出现在HCC高性能集群 export NCCL_DEBUGINFO export NCCL_IB_DISABLE0 export NCCL_SOCKET_IFNAMEeth0 export NCCL_IB_HCArdma0 # 没有RDMA普通VPC实例 export NCCL_IB_DISABLE1 export NCCL_SOCKET_IFNAMEeth0 export NCCL_NET_GDR_LEVEL0设置完之后用 nccl-tests 跑一遍 allreduce看实际带宽是否达到云平台标称值mpirun -np 8 -H node1:4,node2:4 \ ./build/all_reduce_perf -b 1M -e 4G -f 2如果带宽远低于标称值第一步查实例所在的可用区跨可用区通信延迟会高一大截尽量让参与训练的所有实例都在同一个可用区、同一个VPC。第二步查安全组和网络ACL有些看似是性能问题其实是流量被规则挡住了。注意云上多机分布式训练节点数量不宜频繁变化。每次扩容或缩容NCCL的通信拓扑都会变可能导致训练中断或性能下降。我通常只在任务暂停时改实例数量。2.3 自建集群网络调优实操自建集群最常见的网络是InfiniBand或RoCE。InfiniBand需要subnet manageropensm运行正常RoCE则需要正确的GID索引和流控设置。调优时我从下往上一步步查用ibstat和ibstatus确认端口速率和状态。用ib_write_bw测两台节点之间的点对点带宽。用ibnetdiscover导出网络拓扑检查是否存在跨Leaf通信。根据情况设置NCCL变量。export NCCL_IB_HCAmlx5_0,mlx5_1 export NCCL_IB_DISABLE0 export NCCL_SOCKET_IFNAMEeth0 export NCCL_IB_GID_INDEX3 export NCCL_IB_TIMEOUT22 export NCCL_IB_RETRY_CNT7这里我特别想说一个坑自建集群的“网络问题”很多时候不是协议参数而是固件版本。有一次我遇到NCCL频繁报unexpected disconnection花了两天查网线、查配置、查驱动最后发现是交换机firmware版本太旧升级后问题直接消失。这类问题在云上很少遇到因为平台会统一维护。另外自建集群如果有多台机器尽量让通信频繁的节点落在同一台leaf交换机下面。fat-tree拓扑虽然都能到但跨leaf的跳数增加延迟和拥塞概率都会上升。对训练任务来说节点间的物理距离越近越好。3. 数据加载与存储云上拉回本地自建做缓存分层3.1 数据加载如何拖垮GPU利用率GPU算力很快但你的数据链路可能完全跟不上。一个非常典型的现象训练时GPU利用率呈“锯齿状”冲高又掉下来。用iostat一看磁盘等待时间超高或者网络接收流量饱和说明GPU在等数据。这类问题在云上和自建都会遇到但原因和解决路径不一样。云上可能是你选错了存储类型或者反复从对象存储远程拉数据自建可能是并行文件系统配置不对或者小文件太多导致元数据服务器不堪重负。定位方法也很简单在训练代码里给dataloader加计时统计每个step中“取数据耗时/总耗时占比”。如果这个占比超过20%就应该把存储调优优先级提到NCCL前面。3.2 腾讯云GPU实例的存储选型与调优在腾讯云GPU实例上存储性能的大致排序是本地NVMe 高性能云硬盘 文件存储CFS 对象存储COS。这个排序不是绝对的但可以作为默认参考。对小数据集最省心的办法是直接把数据打包传到实例本地NVMe或高性能云盘训练时从本地读。对大数据集我会把数据放在CFS或COS上但在训练开始前先做一轮“预热”把需要用到的样本下载到本地缓存目录。不要让训练循环每次都远程读文件。如果训练任务本身还要访问腾讯云向量数据库vectordb做检索增强一定要注意IO争抢。向量检索的延迟峰值和训练数据读取混在一起会造成不确定的卡顿。我的做法是把向量召回放在独立进程里或者把向量库结果显式缓存到内存避免每次训练step都去实时查询。用fio可以快速摸清存储底细fio --filename/data/test --rwread --bs1M --size2G --direct1 --group_reporting --namebandwidth没有对比就没有伤害我自己实测过同样一份数据放在COS远程读和放在本地NVMe读训练吞吐可以差接近一倍。先别急着调NCCL花半天把数据挪到离GPU近的地方收益反而最大。3.3 自建集群的分布式存储与缓存调优自建集群存储选择更自由但自由意味着你要自己维护。小型集群可以先用本地NVMe rsync分发数据节点多了再上Lustre、BeeGFS或GPFS。并行文件系统最常见的调优点有三个条带化、元数据中心、客户端缓存。条带化适合大文件把一个大文件切成多个块分布到不同存储节点上提升并发带宽。如果数据是小文件比如几万张图片元数据服务器很容易成为瓶颈。我的建议是训练前把数据打包成TFRecord或类似的大文件格式减少元数据请求数。自建还有一个云上很难实现的优势计算节点本地NVMe可以做自动缓存。第一次训练时数据从并行文件系统读入本地SSD第二次再跑同一个epoch甚至同一个数据集的其他实验时直接命中本地缓存。我做过一个对比实验加上这层缓存后训练时间缩短了大概20%。4. 资源调度与GPU利用率弹性伸缩和确定性调度是两条路线4.1 腾讯云GPU实例规格选择、竞价实例与任务级弹性云上调优很大一部分发生在“买机器”这个阶段。实例规格不是越大越好多机训练时单卡太强但网络太弱整体效率反而会被通信拖垮。选实例前可以先拿一个小的代表性任务在同等的总预算下对比“4卡实例”和“8卡实例”的吞吐再决定是多数量的便宜实例还是少数量的贵实例。腾讯云提供竞价实例价格低很多但会被回收。使用竞价实例跑训练必须做好checkpoint并且训练脚本要支持停机恢复。我习惯的做法是每次保存checkpoint到云盘或CFS实例被回收后用同一份镜像快速新开实例拉取最近checkpoint继续跑。自动伸缩组适合无状态服务不太适合长期多机的分布式训练。因为节点IP变化会直接打断NCCL通信。云上更推荐“任务级弹性”保存checkpoint → 关闭旧实例 → 开启新实例 → 恢复训练。这比自动伸缩更可控。4.2 自建集群Slurm/K8s 调度与GPU隔离自建集群的调度器HPC场景我用Slurm微服务化场景用K8s。Slurm更直接配置也简单。几个关键点分区设计把同型号GPU的节点放在同一个分区不要混用不同代际否则一个慢节点会拖慢整个并行任务。GPU分配用Gres或cgroup隔离显存和算力防止两个任务抢显卡导致双双变慢。节点状态管理故障节点一定要主动exclude调度器不会自动识别“半坏”节点。公平调度多租户团队共用集群时按GPU实际利用率排队而不是按节点数量否则有人占着资源不训练谁都没办法。自建的另一个优势是可以在调度层面做资源预留。把管理节点、存储节点和计算节点的CPU/内存边界划清楚避免调度器自己高负载导致任务启动变慢。4.3 NUMA绑定两侧都能做但收益不同GPU访问内存和网卡要走PCIe总线CPU核心绑在哪个NUMA节点上会影响通信延迟。在自建集群里我会用lscpu看CPU和GPU的拓扑然后用numactl --cpunodebind0 --membind0 python train.py绑核。在腾讯云GPU实例上部分虚拟化环境也允许numactl但CPU和GPU之间的拓扑信息可能不完整。如果发现绑定之后没有明显提升就别花太多时间在这上面。云上更值得做的是把存储和网络先调好。注意在虚拟化环境里lspci能看到GPU并不代表你能精确控制NUMA距离。这种场景下绑核收益很小甚至可能因为错误绑定导致性能下降谨慎使用。5. 分布式训练策略与算子优化通信带宽决定你能多激进5.1 梯度同步策略云上压缩通信自建直接全量同样的模型和数据集在云上和自建环境下我选择的分布式策略会不一样。如果是腾讯云普通VPC实例跨节点带宽可能不如自建的InfiniBand那么我会更倾向于使用梯度累积减少梯度同步频率。梯度压缩例如TopK稀疏化或低精度梯度传输。ZeRO Stage 3 offload把优化器状态和梯度移到CPU减少卡间通信。如果自建集群有完整的InfiniBand网络带宽充足全量梯度同步反而是最高效、最稳定的方式不需要为了压缩通信而牺牲精度或增加复杂性。混合精度AMP在两边都是标配但打开AMP之后要重点观察loss是否稳定尤其在使用梯度压缩时fp16的精度损失可能被放大。5.2 算子、驱动和框架版本底层控制权的差别用Profiler定位算子瓶颈两边都一样PyTorch Profiler、nsys、ncu都可以用。区别在于发现问题之后你能改什么。自建集群可以换驱动版本、换CUDA版本、给PyTorch打补丁甚至重编译算子。云上实例最好依托腾讯云提供的公共镜像或基于它们构建自定义镜像不要在生产环境里手动乱换cuDNN/cuBLAS。手动改系统库在云上容易把系统搞坏恢复成本虽然不高但浪费时间。如果云上遇到算子性能差优先做计算图优化例如用TorchScript或ONNX导出替换低效实现。自建可以更深入直接写自定义kernel。这背后不是谁更厉害的问题而是“谁能动底层”的权限边界问题。6. 监控、故障恢复与成本控制两边都要做但做法不同6.1 监控体系云上开箱即用自建自己搭腾讯云GPU实例自带云监控能看到GPU利用率、显存、温度等指标配置告警也很快。自建集群我推荐用DCGM exporter Prometheus Grafana把nvidia-smi dmon的数据接进来。无论哪边至少要监控这些指标指标作用GPU利用率/显存判断算力和内存是否吃紧温度/功耗判断散热和供电是否影响频率网络收发速率判断通信是否成为瓶颈存储IOPS/吞吐判断数据加载是否拖后腿dataloader耗时占比从训练代码内部看数据链路健康度我还会在训练代码里埋一个简单的计时器每个step记录“取数据时间 / 训练时间”这个指标比任何外部监控都更能说明问题。6.2 故障恢复云上重开实例自建替换节点云上实例故障后最快的方式是用快照或镜像重开一台然后挂载同一块数据盘继续跑。所以checkpoint一定不要只写在本地临时盘要写到云盘、CFS或COS上。用竞价实例更要有“随时被回收”的觉悟。自建集群故障恢复靠的是调度器机制和硬件冗余。磁盘要多块盘做RAID网络要有冗余链路管理节点最好能双活。同时配合Slurm的自动重启策略任务失败后排队重跑。我现在的通用做法是训练脚本必须支持断点续训启动时可以指定--resume_from_checkpoint。不管是云上实例被回收还是自建节点宕机都不用手动改代码。6.3 统一基准用“单位时间的有效样本数”衡量一切性能调优做得多了你会发现“看起来调好了”和“真的调好了”是两回事。我习惯为每个项目固定一套基准同一个模型、同一份数据、同一个batch size每次改动只动一个变量记录每step耗时和GPU利用率。最终衡量标准不要用“GPU利用率”单一指标更合适的是“单位时间处理的样本数”。云上按小时计费吞吐越高训练成本越低自建集群虽然不按小时计费但吞吐越高硬件折旧和电费摊到每次实验上的成本就越低。我个人在实际操作中的体会是不管你在腾讯云GPU实例还是自建GPU集群性能调优最值钱的动作不是某个玄学参数而是建立基准和记录变更历史。我每调优一次就把配置、环境变量、数据存储位置和测试结果写进训练日志的README里。过两个月再遇到“训练变慢”直接拉历史记录对比比从头查要快得多。这个习惯帮我省下的时间远比调那一两个NCCL参数多得多。