MultimodalFlow
← 返回博客

DeepSeek V4 Flash NVFP4 在 2×Jetson Thor 上的调试记录 1:SGLang 走到 DeepGEMM 前

DeepSeek-V4DeepSeek-V4-FlashNVFP4Jetson ThorSGLangvLLMQSFP28边缘推理

这篇是调试记录,不是成功战报。

目标很直接:用两台 Jetson Thor,通过 QSFP28 互联,尝试启动 nvidia/DeepSeek-V4-Flash-NVFP4。这轮先验证 SGLang 路线,后面会继续试 vLLM / DSpark 路线。

结论先写在前面:

项目当前结果
模型nvidia/DeepSeek-V4-Flash-NVFP4
运行框架SGLang nightly lmsysorg/sglang:nightly-dev-cu13-20260812-c7c03ec5
硬件2× Jetson Thor
网络QSFP28,4×10GbE;单次聚合 iperf 约 35.6 Gbit/s
并行方式TP=1 + PP=2
当前状态没有完成推理服务启动
进展已完成分布式初始化、权重加载、DSV4 memory pool、FlashInfer autotune
最终阻塞deepgemm/csrc/apis/hyperconnection.hpp:59: Unsupported architecture

一句话:Thor 的系统、网络、容器和权重加载都已经越过了;真正卡点落在 DeepSeek V4 的 DeepGEMM HyperConnection/MHC kernel 对 Thor sm110 支持不足。


机器和网络

两台机器:

名称TailscaleQSFP28 角色
thor100.98.202.31.1
thor-jd100.98.98.105.2

QSFP28 四个 mgbe 网段:

接口thorthor-jd
mgbe0_0192.168.100.1/24192.168.100.2/24
mgbe1_0192.168.101.1/24192.168.101.2/24
mgbe2_0192.168.102.1/24192.168.102.2/24
mgbe3_0192.168.103.1/24192.168.103.2/24

最终用于本轮 SGLang 分布式初始化的是 mgbe1_0

NCCL_SOCKET_IFNAME=mgbe1_0
GLOO_SOCKET_IFNAME=mgbe1_0
NCCL_IB_DISABLE=1
NCCL_NET=Socket

QSFP28 聚合测速结果:

链路iperf3 结果
mgbe0_08.87 Gbit/s
mgbe1_08.87 Gbit/s
mgbe2_08.95 Gbit/s
mgbe3_08.91 Gbit/s
合计35.61 Gbit/s

配置过程已经单独整理在 docs/thor-qsfp28-40g-setup.md


权重和镜像

模型权重先下载到一台 Ubuntu PC / 中转机 chip 的外接盘,再同步到两台 Thor:

/media/chip/f2c346e1-7a07-47bc-9af0-84c67f898fbe/models/nvidia/DeepSeek-V4-Flash-NVFP4

同步后的路径:

thor:    /home/nvidia/models/DeepSeek-V4-Flash-NVFP4
thor-jd: /home/nvidia/models/DeepSeek-V4-Flash-NVFP4

权重大小约 157GB,包含 46 个 safetensors shard。

SGLang 使用的是:

lmsysorg/sglang:nightly-dev-cu13-20260812-c7c03ec5

容器内关键版本:

torch:        2.13.0+cu130
CUDA:         13.0
transformers: 5.12.1
sglang:       0.0.0.dev1+gc7c03ec53
GPU:          NVIDIA Thor, capability (11, 0)

这版 SGLang 已经能识别 deepseek_v4,旧的 NGC sglang:26.04-py3vllm:26.04-py3 不行,主要问题是 Transformers / model registry 太旧。


Docker runtime 先踩了一坑

thor-jd 重启后,Docker 的 NVIDIA runtime 一度被 CDI 配置卡住:

failed to inject CDI devices:
unresolvable CDI devices runtime.nvidia.com/gpu=all

Jetson / L4T 环境下,nvidia-ctk cdi generate 默认走 NVML 会失败:

Unable to determine the device handle for GPU0: 0000:01:00.0: Unknown Error

最后可用的修法是让 NVIDIA container runtime 强制走 CSV:

sudo cp /etc/nvidia-container-runtime/config.toml /etc/nvidia-container-runtime/config.toml.bak
sudo sed -i 's/mode = "auto"/mode = "csv"/' /etc/nvidia-container-runtime/config.toml
sudo systemctl restart docker

验证:

docker run --rm --runtime=nvidia lmsysorg/sglang:nightly-dev-cu13-20260812-c7c03ec5 bash -lc 'python3 - <<PY
import torch
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else None)
print(torch.cuda.get_device_capability(0) if torch.cuda.is_available() else None)
PY'

恢复后的输出:

True
NVIDIA Thor
(11, 0)

为什么不用 TP=2

一开始试过跨节点 TP=2,但在 Ethernet QSFP28 上它不是一个好形态。

SGLang 日志里出现过:

CustomAllreduce is disabled because this process group spans across nodes

对于 DeepSeek V4 这种 MoE + MLA + FP4/NVFP4 路线,跨节点 tensor parallel 会放大通信压力。两台 Thor 没有 NVLink/NVSwitch,QSFP28 也不是 IB/RoCE,所以本轮改用:

TP=1 + PP=2

即两台机器做 pipeline parallel,各自持有一段层。


启动命令

worker 在 thor-jd

docker run -d --name deepseek-v4-worker \
  --runtime=nvidia \
  --net=host \
  --ipc=host \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  -v /home/nvidia/models:/models \
  -e CUDA_VISIBLE_DEVICES=0 \
  -e NCCL_SOCKET_IFNAME=mgbe1_0 \
  -e GLOO_SOCKET_IFNAME=mgbe1_0 \
  -e NCCL_IB_DISABLE=1 \
  -e NCCL_NET=Socket \
  -e SGLANG_OPT_USE_TILELANG_MHC_PRE=0 \
  -e SGLANG_OPT_USE_TILELANG_MHC_POST=0 \
  -e SGLANG_DSV4_MHC_PREWARM=0 \
  lmsysorg/sglang:nightly-dev-cu13-20260812-c7c03ec5 \
  bash -lc 'python3 -m sglang.launch_server \
    --model-path /models/DeepSeek-V4-Flash-NVFP4 \
    --host 0.0.0.0 \
    --port 30000 \
    --dist-init-addr 192.168.101.1:20000 \
    --nnodes 2 \
    --node-rank 1 \
    --tensor-parallel-size 1 \
    --pipeline-parallel-size 2 \
    --trust-remote-code \
    --kv-cache-dtype fp8_e4m3 \
    --mem-fraction-static 0.70 \
    --max-running-requests 8 \
    --chunked-prefill-size 2048 \
    --disable-cuda-graph \
    --bf16-gemm-backend torch \
    --dsa-paged-mqa-logits-backend cutedsl'

master 在 thor,只改 --node-rank 0

--node-rank 0

本轮还在容器内临时补了一个 KV scale fallback。原因是 NVIDIA 这个 NVFP4 checkpoint 在 SGLang 的 FP8 KV cache 路径里没有提供完整 scaling factors,原始代码会断言:

assert layer.k_scale > 0.0

临时补丁逻辑是:如果没有正数 scale,就默认用 1.0。日志也明确提示这可能影响精度:

Using FP8 KV cache but no scaling factors provided.
Defaulting to scaling factors of 1.0.

这不是生产补丁,只是为了推进启动链路,确认后面的阻塞点。


实测推进到了哪里

这轮成功越过了几个关键阶段。

分布式初始化:

[PP0] Init torch distributed ends. elapsed=14.17 s
[PP1] Init torch distributed ends. elapsed=28.51 s

权重加载:

[PP0] Load weight end. elapsed=110.23 s
[PP1] Load weight end. elapsed=86.11 s

模型被识别为:

DeepseekV4ForCausalLM
hybrid FP8+NVFP4 checkpoint
NVFP4 MoE group_size=16

DSV4 memory pool:

[PP0] DSV4 pool PP slice: rank=0 layers=[0,21) local=21/44
[PP1] DSV4 pool PP slice: rank=1 layers=[21,43) local=22/44

内存池初始化也完成:

[PP0] Memory pool end. avail mem=18.13 GB
[PP1] Memory pool end. avail mem=15.60 GB

然后进入 FlashInfer autotune:

Running FlashInfer autotune with cache:
/root/.cache/sglang/flashinfer/autotune/0.6.15.post1/sm110/...

到这里为止,系统层面已经相当接近“服务启动前最后一步”。


最终失败点

两边最终都在 warmup forward 阶段失败:

Scheduler hit an exception
self.warmup()
File ".../base_runner.py", line 247, in warmup
RuntimeError: Assertion error (/deepgemm/csrc/apis/hyperconnection.hpp:59):
Unsupported architecture

这说明我们关掉了 TileLang MHC pre/post 和 prewarm 后,SGLang 在实际 forward warmup 里仍然会走到 DeepGEMM HyperConnection / MHC 路径,而这条路径当前不支持 Thor 的 sm110

换句话说,瓶颈已经不是磁盘、网络、Docker、模型识别、权重读取或 distributed init,而是 DeepGEMM kernel architecture coverage。


这轮得到的判断

  1. nvidia/DeepSeek-V4-Flash-NVFP4 权重可以在两台 Thor 上完整读取。
  2. SGLang nightly 已经支持 deepseek_v4 和 hybrid FP8+NVFP4 checkpoint。
  3. QSFP28 单链路可以承担 torch distributed rendezvous,分布式初始化能过。
  4. TP=1 + PP=2 是当前比跨节点 TP=2 更合理的形态。
  5. KV cache scaling factor 需要 SGLang 侧更稳的 fallback 或 checkpoint 侧提供完整 scale。
  6. 最终启动失败的主因是 DeepGEMM HyperConnection 不支持 sm110

所以这条 SGLang 路线继续往下走,需要源码级处理:

方向代价备注
在 SGLang 里彻底禁用 DeepSeek V4 MHC runtime 路径可能牺牲性能,但最适合先跑通
为 DeepGEMM HyperConnection 增加 sm110 支持需要编译和 kernel 级验证
换 vLLM / DSpark 路线已经拉到可在 Thor 上启动的 DSpark 镜像

下一步:vLLM / DSpark

参考双 DGX Spark 路线的文章使用的是:

ghcr.io/anemll/dspark-vllm-gx10:0.1.1
vLLM 0.25.2
DeepSeek-V4-Flash-0731
TP=2
nvfp4_ds_mla KV cache

我已经把这个 DSpark 镜像拉到 thor,并做了单机探针:

Linux-6.8.12-tegra-aarch64
torch 2.11.0+cu130
CUDA 13.0
cuda available: True
GPU: NVIDIA Thor
capability: (11, 0)
vLLM: 0.25.2.dev0
transformers: 5.13.1

这并不等于它能跑 DeepSeek V4,因为该镜像明显面向 DGX Spark / GB10 / sm_121a 做过优化,而 Thor 是 sm110。但至少它能在 Thor 上启动并识别 GPU,值得作为下一篇继续测试。

参考链接:

测试时间:2026 年 8 月 13 日。本文是调试记录 1,不声称已经完成 DeepSeek V4 Flash NVFP4 在 2×Jetson Thor 上的成功推理。