跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • 浅色
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • 深色
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(LCZ-Blue)
  • 不使用皮肤
  • LCZ-Green
  • LCZ-Blue
  • LCZ-Black
折叠
品牌标识

抡锤者

首页 版块 标签
硬件
装备秀
AI 广场 App
  1. 主页
  2. 版块
  3. LLM讨论区
  4. DGX Spark + TensorFold/SparkFold 跑 Qwen3.8-Flash-Next 完整实战:EXL3 4.05bpw 由 18 个补丁到中文 draft 词表,decode 64.7 tok/s(附全套 benchmark)

DGX Spark + TensorFold/SparkFold 跑 Qwen3.8-Flash-Next 完整实战:EXL3 4.05bpw 由 18 个补丁到中文 draft 词表,decode 64.7 tok/s(附全套 benchmark)

已定时 已固定 已锁定 已移动 LLM讨论区
dgxsparkgb10qwen
5 帖子 2 发布者 300 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • J
    J
    juntucoo
    体面乡绅
    编写于 最后由 编辑
    #1

    DGX Spark + TensorFold/SparkFold 跑 Qwen3.8-Flash-Next 完整实战:EXL3 4.05bpw 由 18 个补丁到中文 draft 词表,decode 64.7 tok/s(附全套 benchmark)

    沿着 dgx-spark-llm-serving-main 仓库 lanes/exl3-sparkfold 这条路线,我在 DGX Spark 上从零跑了一遍完整 setup(2026-10-29 部署完成,服务在跑),顺便做了全套 benchmark 和中文 draft 词表的 A/B 实测。有几个发现(尤其中文词表那 part)想还回来给社群。

    一、硬件

    • DGX Spark:GB10(sm_121a)、128 GB 统一内存、aarch64,Docker 带 NVIDIA runtime
    • 根分区 3.7 T,这条 lane 共占 173 G:
    ~/models/qwen3.8-flash-next-exl3-4.05bpw    101 G   权重
    ~/.cache/tensorfold-sparkfold               967 M   扩展缓存 + 视觉权重
    ~/tensorfold-src                             25 M   打补丁的源码树
    ~/src                                       ~70 M   上游配方 + TensorFold tarball
    /var/lib/docker                             ~70 G   镜像
    
    • 前置条件(01-healthcheck.sh 只读体检,不要跳过):可用统一内存 ≥ 121 GiB、磁盘可用 ≥ 200 GiB(权重 100 + 缓存 + spill 最多 48)、docker info 能看到 NVIDIA runtime。

    二、软件栈和安装

    • 引擎:TensorFold 0.6.5 + SparkFold 806b345 + 仓库 18 个补丁。这条 lane 的全部价值来自那 18 个补丁——仓库记录过未打补丁时英文 decode 42.6 tok/s vs 打完 62.9,不要用未经补丁的 SparkFold 跑。
    • 镜像:tensorfold-qwen38:v0.3.6.3(MiaAI-Lab 封装)再叠一层 xgrammar(response_format / 结构化输出)→ tensorfold-qwen38:v0.3.6.3-xgrammar(36.9 GB,tf.patches=c1f5d72f8d16)。
    • 部署脚本全部做成幂等,失败重跑即可;都支持 DRY_RUN=1 打印将执行的命令。
    cd ~/dgx-spark-deploy && chmod +x *.sh
    
    bash 01-healthcheck.sh        # 只读体检,先做
    bash 02-build-tree.sh         # SparkFold 806b345 + 18 补丁 → ~/tensorfold-src
    bash 03-build-image.sh        # 两层镜像(v0.3.6.3 → v0.3.6.3-xgrammar)
    bash 04-download-pack.sh      # 权重 99.94 GiB:钉 commit sha + 逐文件 size + SHA-256 校验
    bash 05-vision.sh             # 视觉权重转换(可选,VISION=0 就跳过)
    bash 05b-draft-vocab-zh.sh    # 构造中文 draft 词表(中文场景建议做,见第七节)
    bash 06-start.sh              # 启动(封装仓库的 start.sh,不重新实现启动逻辑)
    bash 07-smoke.sh              # 冒烟 + 中英文基准(RUN_BENCH=1 附带仓库的 bench_en.py)
    

    全新机器先跑 bash 00-bootstrap.sh:检查并补齐 Docker / NVIDIA Container Toolkit / hf CLI,已装的一律跳过,最后一步跑 GPU 容器冒烟,确认容器里真能看到 GB10。
    02-build-tree.sh 末尾应显示 spill.py 在位(补丁 0005)。
    MiaAI-Lab 的 prepare.sh 第 3、4 步会下载该封装自己的 MLX checkpoint,本 lane 用不到;照跑是为了与上游保持一致。

    三、两个必改的关键配置(今次分享重点之一)

    3.1 内存地板 6 GiB —— 不是随便定的

    TensorFold 0.6.5 的 stream cache 规则:只有当宿主机 MemAvailable 高于 max(4 GiB, RAM/10)(本机 = 12.2 GiB)再加 2 GiB 时才允许增长,否则直接丢掉一条空闲对话的整个状态。而 Spark 服务这个模型时空载只有约 15 GiB 可用——于是一条长对话会把另一条挤掉,每一轮都变成冷 prefill。

    仓库的对照实验(三条对话轮流,16 token 回复):

    内存地板 后面几轮从零重新 prefill 的次数
    12.2 GiB(引擎默认) 8 轮里 7 轮(丢了 409 s 的 prefill)
    6 GiB(TENSORFOLD_MEMORY_RESERVE_GIB=6) 9 轮里 0 轮

    代价:到 earlyoom SIGTERM 线(RAM 的 3% = 3.6 GiB)的余量从约 11 GiB 降到约 5 GiB。所以不要把 n-gram 表全锁住——仓库记录过 TENSORFOLD_PIN_EXTRA_GIB=12(锁 36 GiB)会让 earlyoom 直接 SIGKILL 掉服务。当前配置 PIN_EXTRA_GIB=-6.2,让锁页量维持在 20-25 GiB。

    3.2 NVMe spill —— 救 evicted 的对话,不是加速

    TF_SPILL_DIR=/cache/spill,只写 ≥ 16384 token 的状态,目录上限 48 GiB,LRU 淘汰。仓库实测:100k token 的状态约 1.5-1.8 GiB,写 0.30-0.40 s,读 0.26-0.45 s。

    它只在对话被挤掉时救命。内存够时它什么都不做,也不带来加速。仓库明确写:只在受控重放里验证过,没有在真实流量上验证过——当成便宜的保险,不要当成实测收益。

    四、模型

    turboderp/Qwen3.8-Flash-Next-exl3,分支 4.05bpw_h6_ng6,EXL3 4.05 bpw,125B 总参 / 6B 激活,99.94 GiB。

    本机校验结果:26 个文件的 size + SHA-256 与 Hub 逐个一致,实下 100.08 GiB(trunk 62.9 GiB / n-gram 表 36.36 GiB / 视觉 0.52 GiB,与仓库记录逐项吻合)。

    为什么必须逐文件校验:仓库的 vLLM lane 明确记录过——大小对但内容截断的 shard 能正常加载、报告出合理的 shape、产出量级正确的激活值,然后生成通顺但完全错误的输出。不崩溃,不报错,只是不对。有人为这个丢了一天。

    另两个硬坑(与网络无关,但必须钉住版本):

    1. 上游封装仓库(MiaAI-Lab)的 main 已换成 Zig 原生引擎,与本 lane 的 Python 引擎不兼容。必须用 commit 38da375e5f4a0be0ed4c065d1014f61088e0a9e4(2026-09-29,最后一个 Python 引擎 + TensorFold v0.3.6.3 版本)。这个 commit 是对的,有硬证据:它的补丁集 hash 是 c1f5d72f8d16,与仓库 README 记录的镜像标签 tf.patches=c1f5d72f8d16 一字不差。
    2. 04-download-pack.sh 会先把分支名解析成 commit sha 再下载,钉住版本、可复现,并逐文件比对 size + SHA-256——照做就行。

    五、生产启动配置(全套)

    06-start.sh 透传给仓库 start.sh:

    变量 默认 说明
    PROFILE spark safe = 旧解码策略(A/B 对照用);bare = 引擎默认值
    SPILL 1 NVMe spill。SPILL=0 关掉
    VISION 1 多模态。VISION=0 关掉
    PARALLEL 5 并发流数
    CONTEXT 262144 上下文长度
    KV_DTYPE int8 KV 精度
    PORT 8888 端口
    BIND 127.0.0.1 监听地址。BIND=(空)= 所有网卡
    KNOBS — 追加任意 TF_*,如 KNOBS="TF_KEEP=32"
    KNOBS="TF_DRAFT_VOCAB=draft_vocab_zh.txt" bash 06-start.sh   # 中文词表(推荐)
    PROFILE=safe bash 06-start.sh            # 对照组
    VISION=0 SPILL=0 bash 06-start.sh        # 纯文本、不落 NVMe
    BIND= bash 06-start.sh                   # 对外提供服务(服务没有 API key,不要暴露到不可信网络)
    

    启动日志里应该看到这四行:

    lone-stream graph slot: 65536 rows
    spill: N stored states adopted
    ... GiB of pages locked            <- 本机实测 "22.0 GiB of it locked"(仓库记录 20-25 GiB)
    serving qwen3.8-flash-next ... loaded in ~90s
    

    首次启动要编译 CUDA/Triton 扩展(本机 260 s),之后重启 73.8 s。脚本会等到 /health 有响应(最多 15 分钟)。服务在 127.0.0.1:8888。

    常用操作:

    bash 07-smoke.sh                              # 冒烟 + 中英文基准
    docker logs -f llm                            # 看日志
    docker exec llm env | grep TF_DRAFT_VOCAB     # 确认实际生效的词表
    

    日志目录 ~/.cache/tensorfold-sparkfold/logs/。仓库的 start.sh 会 docker rm -f 旧容器、日志随之消失,所以 06-start.sh 现在重启前会先把旧日志备份进去。

    六、Benchmark(本机 2026-10-29 vs 仓库基线 2026-10-21)

    Decode 单流: 英文 64.7 tok/s(69.12 / 68.72 / 55.50 / 65.54 四条提示均值)vs 仓库 62.9——同一套构建,吻合。中文装词表 53.4、不装 38.9(见第七节);仓库韩文基线 54.1。

    并发: 仓库 sgbench 端到端 1 / 2 / 4 流 = 66.9 / 92.1 / 131.1 tok/s;llama-benchy decode(深度 0)1 / 2 / 4 流 = 61.7 / 89.5 / 112.2 tok/s。本机只测了单流,多流并发没有测。

    Prefill(冷启动): 1.9k-49k token 真实文本 1,830-2,067 tok/s(仓库)。

    Spill 还原: 100k 对话被挤掉后,冷启 40-50 s vs 从 NVMe 还原 0.8-2.3 s(仓库)。

    工具调用: tool-eval-bench 90/100(装 xgrammar 后,仓库)。

    关键校验(本机):

    • 权重:26 个文件 size + SHA-256 逐个一致,100.08 GiB
    • 源码树:18 个补丁提交全在,draft_vocab_ko.txt 86,232 行(与仓库记录一字不差)
    • 镜像:tf.patches=c1f5d72f8d16(与仓库 README 记录一致)
    • 引擎启动:22.0 GiB locked、84 个图、spill 目录 48 GiB、视觉塔 0.84 GiB

    没测的(诚实清单): 中文质量没有基线(仓库对韩文质量和长工具上下文质量也明确没测过,速度追平 ≠ 质量追平,需要自己评估);多流并发;视觉输入(权重转换好了、引擎起来了,但没实际发过图片)。

    七、中文 draft 词表 A/B 实测(新发现)

    背景:MTP 投机解码的 drafter 只能从一张候选 token 列表里挑下一个 token。引擎自带的那张列表来自 CPython 标准库和 id < 65,536:

    覆盖 比例
    代码 / Markdown token 99.3-99.5%
    英文散文 token 93.9%
    韩文 token 47.5%

    中文比韩文更糟。 这张表基本全是 ASCII,而 Qwen 分词器里绝大多数汉字 token 的 id 都 ≥ 65,536——它们根本不在候选表里。drafter 看不见中文 token,中文的投机接受率会很低,而 decode 速率基本就是"不投机"的速度。

    上游其实已经做了中文版(MiaAI-Lab 的语言补丁带 draft_vocab_zh.txt,22,088 个纯汉字 token id),但那是替换语义——上游 README 明写 "English and code get a little slower with it"。本 lane 的 TF_DRAFT_VOCAB 是并集语义(仓库补丁 0009 的韩文表就是这么做的,补齐后英文贪心回复逐字节不变)。所以 05b-draft-vocab-zh.sh 取的是 并集:引擎默认表 ∪ 上游汉字 id = 101,679 个 id(默认 79,591 + 汉字 22,088)。中文拿到全部候选,英文和代码不受影响。

    A/B(同一套构建、同一批中文提示、同一份 server 配置,只换 TF_DRAFT_VOCAB):

    词表 ZH-HIST ZH-SCI ZH-ADV 均值
    draft_vocab_ko.txt(仓库默认,不含汉字) 34.38 42.80 39.52 38.90
    draft_vocab_zh.txt(默认表 ∪ 汉字) 50.40 55.96 53.68 53.35

    +37.1%。 仓库测韩文时是 42 → 49(+17%),中文的增幅更大——因为默认表里汉字的覆盖率比谚文还低。旁证:每 chunk 的 token 数从 1.20-1.59 升到 1.88-2.11,也就是 MTP 接受率上去了,这正是 draft 词表该起的作用。对照仓库韩文基线 54.1:中文词表装上之后,中文追平韩文。

    基准方法(tools/bench_zh.py,与仓库 bench_ko.py 同构):走 /v1/chat/completions,不覆盖采样参数(用服务端默认),thinking 打开,三条中文长句提示(历史散文 / 科学解释 / 现实建议),600 token 是测量窗口不是服务上限,流式测量、用首末 chunk 之间的时间把 decode 从 prefill 里分出来。

    复现:

    cd ~/dgx-spark-deploy
    # A:仓库默认(不含汉字)
    KNOBS="TF_DRAFT_VOCAB=draft_vocab_ko.txt" bash 06-start.sh
    BENCH_MODEL=qwen3.8-flash-next BENCH_URL=http://127.0.0.1:8888/v1/chat/completions \
      python3 tools/bench_zh.py
    # B:中文并集表
    KNOBS="TF_DRAFT_VOCAB=draft_vocab_zh.txt" bash 06-start.sh
    BENCH_MODEL=qwen3.8-flash-next BENCH_URL=http://127.0.0.1:8888/v1/chat/completions \
      python3 tools/bench_zh.py
    

    要注意的取舍:

    • 只影响速度,不影响质量。 draft 出来的 token 要经过验证才被采纳,换词表不会改变回复内容(仓库对韩文验证过"英文贪心回复逐字节相同")。
    • 一次只认一个词表。 TF_DRAFT_VOCAB 是一个文件名,韩文表和中文表不要同时用;中文表取的是并集,换过去不会丢掉英文/代码的覆盖。
    • 06-start.sh 会把仓库默认的韩文表和 KNOBS 一起传给 docker,同名变量以最后一个为准;用 docker exec llm env | grep TF_DRAFT_VOCAB 确认实际生效值。

    八、陷阱清单

    • 未打补丁的 SparkFold 千万别跑:英文 decode 42.6 vs 打完补丁 62.9,差一半。
    • 权重必须逐文件 SHA-256 校验:截断的 shard 不崩溃、不报错,只是生成"通顺但完全错误"的输出。
    • n-gram 表千万别全锁:TENSORFOLD_PIN_EXTRA_GIB=12(锁 36 GiB)→ earlyoom 直接 SIGKILL 服务。
    • set -e + pipefail 会让脚本静默死掉:grep 没匹配 → 退出 1 → 管道非 0 → 脚本被杀,什么错误信息都没有。07-smoke.sh 就这么死过一次(引擎的锁页日志是 "22.0 GiB of it locked",不是仓库旧版的 "pages locked")。凡是 grep ... | ... 形式的输出行,后面都要 || true。
    • 上游封装仓库的 main 已换成 Zig 引擎:必须钉 commit 38da375e…(补丁集 hash c1f5d72f8d16 对得上镜像标签,是硬证据)。
    • 仓库 start.sh 会 docker rm -f 旧容器,日志随之消失——06-start.sh 已改成先把日志备份到 $CACHE/logs/ 再重启。
    • 第一条回复特别慢是正常的:另一个 graph 槽位首次解码要多花 0.6-1.6 s,第二次就正常。
    • 本 lane 不主打 prefix caching:重复前缀不保证命中,与 vLLM lane 不同。
    • 服务没有 API key:BIND= 对外监听只可以在可信局域网里用。
    • 对话每轮都重新 prefill 多半是内存地板问题:看日志里 memory gate evicted ...,确认 TENSORFOLD_MEMORY_RESERVE_GIB=6。

    致谢

    dgx-spark-llm-serving 仓库(lanes/exl3-sparkfold)的前辈记录、turboderp 的 EXL3 权重、MiaAI-Lab 的封装与上游语言补丁、TensorFold / SparkFold。中文质量评估如果有人焗到更深,欢迎交流。

    1 条回复 最后回复
    2
    • terryT
      terryT
      terry
      易有太极
      编写于 最后由 编辑
      #2

      发帖配点图啊,别光大段的文章,容易被当AI Slop。

      油管:https://www.youtube.com/@抡锤者

      J 1 条回复 最后回复
      0
      • terryT terry

        发帖配点图啊,别光大段的文章,容易被当AI Slop。

        J
        J
        juntucoo
        体面乡绅
        编写于 最后由 编辑
        #3

        @terry 收到,下次注意。

        1 条回复 最后回复
        0
        • J
          J
          juntucoo
          体面乡绅
          编写于 最后由 编辑
          #4

          微信图片_2026-11-02_163349_639.png
          为了方便在内网查看设备的实时是使用情况,让DSH写了一个网页。效果还不错。

          1 条回复 最后回复
          1
          • terryT
            terryT
            terry
            易有太极
            编写于 最后由 编辑
            #5

            那你可以直接把网页放上来。

            油管:https://www.youtube.com/@抡锤者

            1 条回复 最后回复
            0

            你好!看起来您对这段对话很感兴趣,但您还没有一个账号。

            厌倦了每次访问都刷到同样的帖子?您注册账号后,您下次访问时都将自动回到上次浏览的位置,并可选择接收新回复的通知(通过电子邮件或推送通知)。您还可以收藏帖子、为帖子点赞,以此向其他社区成员表达您的感谢。

            有了你的建议,这篇帖子会更精彩哦 💗

            注册 登录
            回复
            • 在新帖中回复
            登录后回复
            • 从旧到新
            • 从新到旧
            • 最多赞同


            • 登录

            • 登录或注册以进行搜索。
            • 第一个帖子
              最后一个帖子
            0
            • 版块
            • 最新
            • 标签
            • 热门
            • 用户
            • 群组