带新人带得久了,手上攒下一沓答疑记录:同样的问题换个人再问一遍,就得从头再排查一次,不如把被问得最多的那些收拢成一页速查。这里挑出十八个新人卡得最久的地方,每问一答,答案直给,抄下来就能用。分组也按答疑的实际场景走:新机器盘点、把服务拉起来、输出不对劲、训练和多卡、值守,五段翻完。
背景先摆在这里:一台 8 卡海光 DCU 服务器(K100_AI),DTK 26.04,torch 2.5.1,主力推理栈是 vLLM 0.9.2。文中的数字都是这台机器上的实测值,换机器请以自己的实测为准。用法上就一句话:先照抄跑通,再拿自己机器的数字微调。
## 一、新机器到手的盘点
**问 1:单卡显存到底多大?用什么看?**
答:`rocm-smi --showmeminfo vram`,每卡 65520 MiB——这个数换算成 GiB 口径就是 63.98 GiB,两个工具里显示不一样时先别怀疑硬件,是单位口径的差别。不放心就用厂商的 hy-smi 再看一遍,两边数字对得上就踏实;看实时占用和进程归属,rocm-smi 一个工具够用。
**问 2:磁盘怎么分?东西都往哪放?**
答:`/home` 通常只分十几 G,权重、conda 环境、数据集全放 `/data1` 这块大盘;docker 的 data-root 也指到大盘,否则镜像一拉,根分区就满。新机器初始化,先拿 `df -h` 把这几处的容量确认完再开工,比事后搬目录省事得多。
**问 3:`.numpy()` 报 Numpy is not available,谁动了我的 numpy?**
答:DCU 版 torch 2.5.1 是按 numpy 1.x 的 ABI 编译的,环境里 numpy 升到 2.x 之后就会这样。两条路:把 numpy 锁在 `<2`,省事,适合能自由控制环境的情况;或者代码里改用 `.tolist()` 绕开,适合环境动不了的场合。服务器全局环境是 numpy 2.x 时最容易中招,装新环境时先看一眼版本。
**问 4:conda 环境挪了目录之后全崩了?**
答:conda 的脚本 shebang 记的是创建时的绝对路径,挪了目录就全部指向旧位置。进到环境目录里执行 `find bin -exec sed -i "s|旧路径|新路径|g" {} +` 批量改回来,替换前先 grep 一下旧路径,确认影响面再动手。能不挪就不挪,挪了就全量替换,别指望改一两个入口就完事。
## 二、把服务拉起来
**问 5:vLLM 直接 pip install 行不行?**
答:不行,官方包里的 CUDA kernel 在 DCU 上编译不过去。装 DTK 适配版 wheel——版本号后缀带 `dtk` 的那种,从 sourcefind 下载渠道按自己的 DTK 版本对号入座,torch、vLLM、flash_attn 三件套尽量保持同一套栈;torch 和 flash_attn 的适配版也在那里。顺带省一句弯路:download.hygon.cn 这个地址目前不通,别在上面耗时间。
**问 6:服务起来半天了,到底算不算就绪?**
答:看日志两行同时出现:`Uvicorn running` 和 `Application startup complete`。只看到端口监听不算数,权重的加载和 KV cache 分配都在后面,这时候放流量进去只会收到超时。健康检查脚本就 grep 这两行,两行齐了再挂上游。
**问 7:KV cache 给了多大?显存快被吃满,正常吗?**
答:正常。默认行为是预分配 0.9 倍显存给 KV cache,看到总显存快被吃满不要慌;具体给了多大不用猜,vLLM 启动日志里直接打印实测值,按 MiB 数得很清楚。要调就调 `gpu_memory_utilization`,给别的进程留余量时往下压这个值。
**问 8:第一个请求要 3.9 秒,后面只要 46ms,差在哪?**
答:首次请求里背着 JIT 编译和算子内核生成的一次性成本,这笔钱付过一次就没有了,编译产物落在本地之后,后面的请求都在 46ms 这一档。正确做法是服务就绪后主动预热:喂 3-5 条不同长度的样本,把常用 kernel 都编译出来,再挂健康检查。不预热的话,这笔钱由第一个真实用户来付。
## 三、输出不对劲的时候
**问 9:模型输出一长串感叹号 !!!!!,坏在哪?**
答:两个方向。一是 GPTQ 量化 kernel 反量化坏了,换 BF16 权重就好;二是 chat template 里特殊 token 渲染错——见过全角竖线|混进去导致采样崩坏的案例。排查顺序固定:先拿 tokenizer 验模板,再换权重验 kernel。先验模板是因为它零成本,几分钟就能排除掉一个方向,别一上来就重下权重。
**问 10:报 head size 80 not supported,是算子库的问题吗?**
答:先别动算子库。查 `config.json` 有没有被人改坏——架构字段写错就会触发这种迷惑报错,实际碰到的案例就是一份改坏的配置。这个报错的迷惑性在于字面指向算子能力,让人以为模型结构太新,实际多半是配置在说话。配置没毛病,再查 attention backend 是不是选了个不支持该 head size 的实现。顺序别反。
**问 11:显存显示 4.8/63.98 GiB,却找不到任何进程,泄漏了吗?**
答:不是泄漏,是 HIP 的延迟释放窗口——显存已经还了,只是计数没刷。等几十秒再看,数字就会归位;急着跑下一单的话直接换张卡,不用重启机器。判断要点是"无进程但有残留计数",真泄漏的现场是进程还在、显存只涨不降,两者别混为一谈。
**问 12:vLLM 版本怎么选?是不是越新越好?**
答:实测下来分三档:0.6.2 容器保底,顺手避开 GPTQ 的坑;0.9.2 的栈跑 32B 级最稳,当前主力;0.11 跑小模型没问题。32B 级别在更新的栈上会撞 gfx928 的 inductor blocker,别头铁硬升——升级前先想清楚自己要跑多大的模型,版本跟着模型走,不是跟着新闻走。
## 四、训练和多卡
**问 13:八卡训练的启动命令有什么讲究?**
答:`torchrun --nproc_per_node=8`,外面再包一层 `numactl --interleave=all`。八张卡在 NUMA 上分了 4 组,不绑的话跨组访存会拖慢训练,卡越多、张量越大,这笔开销越明显。这是标配写法,不是可选优化——把它当成启动模板的一部分固定下来,别每次手敲再漏掉。
**问 14:训练之前,怎么快速确认通信是通的?**
答:写一个三十行的小脚本:8 张卡各生成一个全 1 张量做 all_reduce 求和,结果等于 36 就是全通;结果不对就停下来查链路,别带着隐患继续烧训练时间。任何多卡训练在 step 0 之前必跑,30 秒换掉后面几个小时的排查——通信问题的表象经常伪装成 loss 不收敛,到时候查到怀疑人生也想不到是链路。
**问 15:DeepSpeed ZeRO-3 加载 32B 报 ds_numel=0?**
答:zero.Init 对 norm、bias 这类小参数有分区缺口,小参数没被正确登记进分区表,报错里的 ds_numel=0 字面上就是"分区表里登记的参数量为零"。在当前这套 torch/DeepSpeed 组合上无解,别耗,直接转 FSDP1。表象越古怪越要早点换路——这条路上有人耗过整个下午,结论没变。
**问 16:FSDP2 能用吗?activation checkpointing 怎么开?**
答:FSDP2 要 torch 2.6 及以上,torch 2.5.1 就老老实实用 `version=1`(FSDP1)。activation checkpointing 通过 `fsdp_config` 配置,不走顶层那个 `gradient_checkpointing` 开关——后者在这条栈上不生效,配了等于没配,还容易让人误以为省显存的手段已经上了,实际什么都没发生。
## 五、值守时的两件小事
**问 17:停了服务显存不放,怎么清干净?占卡的又是谁?**
答:vLLM 是一主多 worker 的进程树,只杀主进程会把 worker 留成孤儿,继续攥着显存不放。`pkill -9 -f "vllm serve"` 按特征杀全家,再用 `fuser -v /dev/kfd` 校验没有进程还攥着设备句柄——校验这步不能省,杀完看一眼显存归零再拉新服务。反过来要找"占着卡的到底是谁",也是同一条命令:`fuser -v /dev/kfd` 会列出所有握着设备句柄的 PID,配合 `ps -fp
` 看归属。N 卡上"进程列在显存表里"的直觉在这里不完全成立,fuser 才是最终答案。
**问 18:长任务挂后台,断线就丢怎么办?**
答:宿主机上用 tmux,断线不丢。要在 `docker exec` 里挂就用子 shell 三件套:`( nohup 命令 >log 2>&1 & )`——括号包住、输入重定向、日志落盘,缺一样都可能被 SIGHUP 连坐,表现就是退出终端任务跟着死。另一个相关现象:容器里 pkill 杀不掉进程,是容器内 PID namespace 看不全所致,从宿主机按同样特征 `pkill -f`,或按 cgroup 整组清掉——这是隔离的正常表现,不是 pkill 坏了。
十八个答案都不长,因为排查到位之后,结论本来就该这么短;真正花时间的是从表象走到根源的那段路,这份速查就是把那段路折叠掉。照抄跑通之后,显存余量、KV cache 大小、预热样本数、NUMA 绑定方式这几处,换成自己的卡型和负载都要重新量一遍。用的时候还有一条小原则:答案里凡是给了固定排查顺序的(先验模板再验权重、先查配置再查后端),顺序本身就是答案的一半,别跳步。