深度解读|Spark-H3:从注意力几何到稀疏内核代码

人工智能炼丹君
2026-10-24 / 0 评论 / 3 阅读 / 正在检测是否收录...

原文:Spark-H3: Adaptive Block Sparse Attention for MiniMax-H3
作者署名:SparkH3 Team。项目博客首发于 2026-09-23,技术正文更新于 2026-10-08。
阅读与代码核对日期:2026-10-24。源码固定在 502ef356,避免后续版本变化影响理解。
代码:Spark-H3 仓库。仓库标注 Apache-2.0;模型权重及依赖的许可应分别查看。
阅读提示:先建立整体直觉,再推导 Reblock 与 Reweight,最后对照源码和运行实验。文中自制实验只验证数学性质,未在本机复现 H3 视频质量或 GPU 加速比。

01 先把问题说清楚:少算哪些注意力,才能让视频保持原样

从输入到输出的计算路径

自制原理图:Reblock 改善布局,Top-K 选择精算块,Reweight 覆盖其余块,最后统一归一化并恢复 query 顺序。

Spark-H3 给 MiniMax-H3 视频生成模型替换了一段计算量很大的注意力运算。它保留模型已有权重,在推理时选择一部分 token 之间的交互精确计算,再用便宜的近似覆盖剩余交互。

视频生成会把时空内容编码成 latent token。每一层、每一个注意力头,都要让 query 判断应当从哪些 key 对应的 value 取信息。token 数变长,所有两两关系的数量按平方增长。

降低采样步数可以少运行几次模型;Spark-H3 则降低每次运行内部的注意力成本,两者可以叠加。

这里的目标包含两个层次。一个是输出视频看起来合理;另一个是尽可能接近同一 prompt、同一 seed 下的 dense 原始输出。

后者更严格:即使两段视频都很好看,人物姿态或镜头轨迹不同,逐像素保真指标也会下降。

这篇博客最有价值的地方,是把近似误差拆成了两个可以分别改进的问题。

  • 分组误差:固定把相邻 token 装进同一个块,块均值可能代表不了内部成员,导致重要块没有被选中。
  • 压缩误差:没被精算的块如果只取 K/V 均值,会错误估计它应当分到多少注意力,以及应当贡献什么内容。

Spark-Reblock 处理前者,Spark-Reweight 处理后者。把这两条线分开,后面的公式和代码就容易读了。

02 先读实验:10% 预算到底换来了什么

同一主表中的 DiT 耗时对比

据原博客 Benchmark Results 数据重绘:1344×768、240 帧、24 fps、19 次去噪。只计 DiT;Spark 与 Lite 均为 10% 视频块精算密度,非本机实测。

原博客 Benchmark Results 使用 1344×768、240 帧、24 fps、VBench prompts,以及 20 个调度点对应的 19 次去噪。

质量比较采用相同 prompt、seed 的 dense 输出作为参考。以下只摘出支持主要判断的几行。

方法 视频块精算密度 DiT 时间 相对 dense 加速 PSNR / LPIPS
Dense 100% 583.3 秒 1.00× ∞ / 0.00
Sol-H3 动态选择 355.4 秒 1.64× 20.36 / 0.20
Spark-H3 10% 337.4 秒 1.73× 23.30 / 0.14
Spark-H3 20% 371.1 秒 1.57× 25.38 / 0.09
Spark-H3 30% 404.1 秒 1.44× 27.07 / 0.07
Spark-H3-Lite 10% 330.2 秒 1.77× 23.34 / 0.14

来源:原博客 Benchmark Results。这是作者报告的数据,未在本机重跑。

博客的集成实验明确写了 RTX PRO 6000 Blackwell Server Edition 96GB 与 per-block compile;主表段落没有完整重述全部硬件和 warmup 条件,不能自行把另一组实验配置全部搬过来。

10% 是候选视频 K/V 块的精算预算。 它不表示只保留 10% 的视频 token,不表示总 FLOPs 下降 90%,也不表示整条视频生成流程提速十倍。文本、音频等 exact 内容、warmup、分组、摘要和 MLP 仍然有成本。

PSNR 越高、LPIPS 越低,表示相对 dense 参考更接近;SSIM 则主要衡量结构相似。它们回答“改动有多大”,无法单独回答“哪个视频更好”。

VBench 的一致性、平滑度和画质指标补充另一个视角,但也不能证明所有 prompt 上没有损失。

例如作者报告 Spark-H3 10% 的 VBench imaging quality 为 71.81,dense 为 72.14;aesthetic quality 为 68.22,dense 为 67.59。

几个维度接近且互有高低,适合表述为“这些已测维度整体接近”,不应扩写成全面无损。

03 从 dense attention 推到“精算加摘要”

精算分支与压缩分支共用分母

自制原理图:两条分支先合并未归一化分子与指数质量,再得到输出;不能把两个独立 softmax 输出直接相加。

这一节开始进入推导。只想了解部署的读者,可以先读第 11 节源码地图和第 13 节使用说明。

记一个 query 为 q,块 B 内的 key、value 为 k 和 v,head dimension 为 d。注意力先算缩放点积,再指数化,最后统一归一化。

$$s_j(q)=q^T k_j/\sqrt{d}$$

$$Z_B(q)=\sum_{j\in B}e^{s_j(q)}$$

$$U_B(q)=\sum_{j\in B}e^{s_j(q)}v_j$$

Z 是这个块的注意力总质量,U 是还没归一化的内容贡献。全体块的 U 相加,再除以全体块的 Z 相加,得到最终输出。这里把“分子”和“分母”分开,是理解压缩分支的关键。

对精算集合内的块,逐 token 计算 Z 和 U。对剩下的块,用一个 key、一个 value 和一个质量修正项近似整块。这样,昂贵的 token 对 token 交互只发生在少量选中块中。

朴素均值压缩会取块内平均 key 和平均 value。块内有 m 个 token 时,摘要 logit 还要加 log(m)。

原因很直接:把同一个均值重复 m 次,指数质量就乘 m;改成一个虚拟 token 后,必须补回这个数量。

$$\widehat{Z}_B(q)=m e^{q^T\bar{k}_B/\sqrt{d}}$$

因此,把一整个块压成一个 token,却不给它 log(m),会额外漏掉块大小这一项。 这个问题和 Jensen gap 是两回事,应先保证数量语义正确,再讨论怎样让近似更准。

两条分支最终共享同一套分母。不能分别算两个 softmax 输出,再直接加起来,或者各乘 0.5。正确合并时,哪一条分支带来更多指数质量,哪一条就分到更多权重。

实际内核通过 online softmax 维护行最大值、指数和、加权输出。这避免显式生成完整注意力矩阵,也让精算 token 与压缩摘要可以在同一个归一化过程中合并。

04 为什么固定时空块会把 Top-K 选错

原文 Reblock 动画关键帧

来源:SparkH3 Team 原博客的 Spark-Reblock 动画。截取末帧;16 个 token、每叶 4 个 token 及图中召回数值均为动画玩具示例,不是 H3 消融实验。手机端将原图的分组与矩阵区域纵向排列;博客保留完整帧。

块稀疏注意力需要规则块:GPU 擅长计算整齐的矩阵 tile,不擅长逐个处理四散的 token。但“地址相邻”与“应该一起被注意”不总是一回事。

同一个视频里,一个人物可能跨帧移动。两个空间相近的位置,也可能分别属于人物和背景。扩散早期噪声更强,干净画面里的局部相似性会进一步减弱。

固定时空分组仍然有工程价值,只是未必符合当前层、当前 head 的注意力偏好。

假设一个块里混有几个极重要 token 和大量无关 token。均值打分会把重要成员稀释。预算有限时,整个块可能排不到 Top-K;即使入选,也花了大部分计算在无关成员上。

Reblock 的做法是改变打包方式:把注意力偏好相近的成员放在一起。这样块均值更有代表性,选中一块时,“整块都值得算”的概率更高。

相同注意力矩阵在重排前后的形状

图 1:自制教学实验。左图为交错排列的合成 token,右图按二阶矩特征做等容量二叉分组;亮区域更集中。这里只演示分组几何,未使用作者的 landmark/fanout-16 生产算法,也不代表真实 H3 的质量收益。

单纯重排不会丢信息。对 Q 重新排序,对 K/V 使用同一套 key 排列,计算后恢复 query 顺序,dense attention 的输出在精确算术下保持一致。

真正引入近似的是后续块选择和摘要替代,而不是 permutation 本身。

这也解释一个实现要求:Q 和 K 可以独立分组;但 K 与 V 必须绑定重排,输出必须按 Q 的逆排列恢复。哪怕公式写对,只要其中一处索引错位,就会把别人的内容写到当前 token 上。

05 核心原理一:为什么用“对侧二阶矩”衡量相似

Q 和 K 为什么要看对侧二阶矩

自制原理图:Q 的分组由 K 的非中心化二阶矩诱导,K 的分组则参考 Q;对应比较的是打分模式的相似性。

直接比较两个 query 的欧氏距离,不一定能判断它们对 key 的偏好是否相近。更合理的办法,是比较它们对所有 key 打出的分数模式。

把 query 的完整打分向量写成 Kq。对两个 query,打分向量的内积可以改写为:

$$\langle Kq_i,Kq_j\rangle=q_i^T K^T Kq_j$$

定义 key 的非中心化二阶矩:

$$M_K=K^T K/N$$

于是两个打分向量的 cosine,可以不用真的构建长度为 N 的打分向量,转而在变换后的 d 维空间计算。博客把对应距离写成:

$$d_Q(i,j)=1-\cos(M_K^{1/2}q_i,M_K^{1/2}q_j)$$

这不是凭空添加的“统计技巧”:它来自对 attention logit profile 的比较。

某个方向如果在 key 分布里几乎不出现,query 在这个方向上的差异,对打分影响就很小;key 经常变化的方向,则应得到更多关注。

对 key 做分组时,同理使用 query 的二阶矩。Q 的分组看 K,K 的分组看 Q。 源码中的交叉命名容易绕晕,抓住这个关系就不会读反。

这里有三处边界要说明。

第一,M 是 E[kkᵀ],没有减均值,不能随手改成协方差 Cov(k)。后者会改变几何含义。源码还引入采样、ridge 等数值处理,因此数学等式与实际估计器要分开看。

第二,这是对原始打分模式的 cosine,不是对 softmax 后概率分布的精确距离。cosine 会忽略向量整体尺度,但尺度可能改变 softmax 的尖锐程度。

它是有依据的分组标准,不能宣称“同组 query 的注意力分布完全相同”。

第三,不需要显式求一个对称平方根。只要找到因子 L,使 LLᵀ 近似 M,对行向量使用 qᵀL 就能得到同一内积几何。

不要把“Mahalanobis”习惯性理解成必须乘逆协方差;这里采用的是对侧二阶矩诱导的度量。

06 从几何到硬件:为什么还需要等容量层次划分

等容量层次划分如何得到规则块

自制教学图:16 个 token 逐级分成容量相等的子组,最终每叶 4 个 token。真实生产路径通常使用 64-token 叶块,图中分叉仅用于解释容量约束。

知道相似度,还不足以得到 GPU 好用的稀疏块。普通 k-means 的簇大小会不相等:有的簇很多 token,有的很少。如果再硬切成固定块,边界可能切断簇,或者混入别的簇。

Spark-Reblock 通过层次划分处理容量约束。从整组 token 开始,按指定子节点容量分配成员,然后在子组内继续细分,直到叶子是目标块大小。当前生产路径通常面向 64-token 叶块。

固定版本的默认设置包括 fanout 16、32 个 midpoint landmarks、group size 1,以及 power-of-two fanout 调度。

landmarks 帮助估计节点内划分方向,再用容量约束产生规则块。它不是对每一对 token 都计算相似度,也不是全局最优聚类的保证。

博客给出的分组复杂度是 O(N log N),这个判断需要把 head dimension、landmark 数量和分叉数视为固定参数。

每一层处理当前 token,层数随序列长度对数增长,因而避免直接枚举所有 token 对。

但 Spark 整套注意力不因此变成 O(N log N)。 如果始终精算固定比例 ρ 的视频块,精算部分仍有约 ρN² 个交互。逐 query 消费 N/64 个尾部摘要,也保留二次量级,只是常数更小。Reblock 的复杂度与整个注意力的复杂度必须分开说。

源码还有一个值得注意的优化:ComfyUI 当前默认 reblock_layout=q_reuse_k,只构建 K 布局,让 Q 复用;independent 则分别构建两侧布局。

两者会带来不同的布局成本与分组结果,不能只凭博客的抽象描述推断当前节点必然独立分组。

原博客 Spark-Reblock 消融在 10% 预算下,把 attention-mass recall 从 68.66% 提升到 81.54%,增加 12.88 个百分点;PSNR 从 18.61 提升到 22.41 dB。

这个实验只替换分组,其他设置保持不变,因而支持“更好的块布局有帮助”这一判断。

attention-mass recall 统计选中交互覆盖了 dense 的多少概率质量。它不是视频语义召回率,也不表示丢掉了其余概率:压缩分支仍会近似剩余部分。

07 核心原理二:均值压缩为什么会低估注意力质量

原文中的 Jensen gap 与质量修正

来源:SparkH3 Team 原博客的 reweight_correction 图。蓝色为先平均再 exp,橙色为先 exp 再平均,绿色表示修正后的等效 logit。原图用 x₁=−1、x₂=2;手机端按相同数据重绘并配中文说明。这张图解释质量偏差,完整加权 K/V 构造见第 08 节。

注意力是先 exp,再求和。均值压缩把一组不同的 logit 替换成平均值,再 exp。由于指数是凸函数,这两个顺序通常不等价。

$$E[e^x]\ge e^{E[x]}$$

这就是博客提到的 Jensen gap。同一块内部的 logit 越分散,先平均再指数化就越容易遗漏高分成员带来的质量。

压缩块与 exact 块放在一个 softmax 中竞争时,压缩块可能因此被系统性压低。

拿一个只有两个 token 的块看得最清楚。令 d=1、q=1、key 为 −2 和 2,value 为 0 和 1。两个 logit 就是 −2 和 2。

  • 真实指数质量:exp(−2)+exp(2)=7.524391。
  • 均值 key 为 0;补了两个 token 的数量后,近似质量仍只有 2。
  • 均值 value 为 0.5;真实块内加权 value 则为 0.982014。

所以需要补的有两件事:这个块该分到多少权重,以及它拿到权重后应当输出什么内容。只修分母、不修 value,仍可能把块的主要内容算错。

Reweight 采用一个代表 query,为每个块重新计算摘要。默认代表点是当前 head 内所有目标视频 query 的均值。

只用一个代表点给所有 K 打分,新增摘要构建可保持线性复杂度;若每个 query 都重新生成专属摘要,就回到了昂贵的全量交互。

08 完整推导:加权 K、加权 V 与 log-mass bias

原文 Reweight 动画关键帧

来源:SparkH3 Team 原博客的 Spark-Reweight 动画。截取末帧;四个玩具 token 的 logit 为 −2、−1、1、2,图示依次修正压缩质量与加权 value,并与固定 exact 分支联合归一化。它展示代表 query 处的匹配,不表示任意 query 都精确。手机端将两侧面板纵向排列。

记代表 query 为 a。先在块内计算相对 a 的 softmax 权重:

$$p_j(a)=\operatorname{softmax}_j(a^T k_j/\sqrt{d})$$

再同时加权 K 和 V:

$$\widetilde{k}_B=\sum_{j\in B}p_j(a)k_j$$

$$\widetilde{v}_B=\sum_{j\in B}p_j(a)v_j$$

最后构造质量修正。为了手机阅读,把它拆成两条短式子:

$$\ell_B=\log Z_B(a)$$

$$b_B=\ell_B-a^T\widetilde{k}_B/\sqrt{d}$$

对于实际 query q,用如下一个虚拟 token 近似整块:

$$\widehat{z}_B(q)=q^T\widetilde{k}_B/\sqrt{d}+b_B$$

$$\widehat{U}_B(q)=e^{\widehat{z}_B(q)}\widetilde{v}_B$$

在 q=a 时,这个摘要能恢复整块的真实 Z 和 U。 将 q=a 代入,第一项正好被 bias 中的减法消掉,留下 log Z;再乘加权 value,就回到原始未归一化分子。多个压缩块与任意 exact 块一起合并时,这个性质仍然成立。

这是理想精确算术下的性质,真实 BF16/FP32 实现会有舍入误差。

当前源码默认还会用存储后的 BF16 摘要 key 计算 bias 中的减项,使下游实际消费的 key 与质量校正相配合;可选 pre_round 是不同的数值消融。

回到上面的两-token 例子,a=1 时,加权 key 为 1.928055,加权 value 为 0.982014,bias 为 0.090095。

虚拟 logit 为 2.018150,指数后正好是 7.524391。

这里容易出现一个反直觉的误读:bias 比 log(2) 小,不意味着补偿方向错了。 加权 key 已经提高了 logit,bias 必须扣除这部分变化。

不能保留均值 key,却直接套用加权 key 对应的 bias;也不能换了加权 key,还继续无条件加 log(m)。

事实上,在未舍入的数学定义下,这个 b 就是代表点块内权重的熵 H(p),介于 0 和 log(m) 之间。全块近似均匀时,它接近 log(m);权重集中到一个成员时,它接近 0。

补偿的含义取决于“key 和 bias 的组合”。

09 更深一层:Reweight 可以看成 log-mass 的切线

下面这一层是根据定义推导出的解释,原博客并未把它写成完整定理。

把一个块的精确 log-mass 记为 f(q)=log Z_B(q)。它对 q 的梯度就是按当前注意力加权的 key,再除以 √d。

$$\nabla f(a)=\widetilde{k}_B/\sqrt{d}$$

所以 Spark 的虚拟 logit 等价于 f 在 a 处的一阶展开:

$$\widehat{z}_B(q)=f(a)+(q-a)^T\nabla f(a)$$

这样可以看清它为什么比均值更贴近局部真实分布:它同时对齐了代表点上的函数值和梯度。也可以看清它的局限:q 走远了,一条切线无法描述整个曲面。

log-sum-exp 是凸函数,因此理想算术下,这条切线不会高于真实块 log-mass。局部二阶误差由注意力权重下 key 的协方差控制,方向上越分散,偏离代表点时误差越大。

这个性质只讨论单块质量,不意味着最终视频误差有同样简单的单调关系。

value 的限制更直接:摘要 value 对所有 q 固定,而真实块内加权 value 会随 q 改变。就算某处质量近似得不错,内容贡献也可能不准。

代表 query 附近的质量与内容误差

图 2:自制两-token 实验,key 为 −2 和 2,value 为 0 和 1,代表点 a=1。左图显示 log-mass 在代表点相切;右图显示固定加权 value 无法跟随全部 query。远离代表点时,Reweight 也可能比均值更差,应按实际分布评估。

这也解释了 Reblock 与 Reweight 为什么互补。前者让需要一起处理的成员更集中,也改善重要块的选择;后者尽量提高剩余块的摘要质量。

但不能由此推出它们误差必然相加,或者任何输入下组合都严格更优。

原博客 Reweight 单独消融保持固定分组,将绝对 log-mass 误差从 3.86 降到 2.78 nats,约下降 28%;PSNR 从 18.61 到 19.17 dB。

它的独立收益小于 Reblock 那组,但它修的是另一处误差,不能拿两组数字直接做联合归因。

10 先写一个能跑的实现,再看 GPU 优化

下面是独立编写的 NumPy 教学实现,采用稳定 softmax,输入一个块的 K/V 和代表 query。它与作者内核的数学目标对应,省略了多 head、混合布局和 GPU 调度。

import numpy as np

def softmax(x):
    z = np.exp(x - np.max(x, axis=-1, keepdims=True))
    return z / z.sum(axis=-1, keepdims=True)

def summary(anchor, keys, values):
    scale = keys.shape[-1] ** -0.5
    logits = keys @ anchor * scale
    weights = softmax(logits)
    key = weights @ keys
    value = weights @ values
    peak = logits.max()
    lse = peak + np.log(np.exp(logits - peak).sum())
    bias = lse - anchor @ key * scale
    return key, value, bias

def mixed(query, keys, values, exact_ids,
          block=4, anchor=None):
    logits, vals = [], []
    scale = keys.shape[-1] ** -0.5
    for bid, start in enumerate(range(0, len(keys), block)):
        kb = keys[start:start + block]
        vb = values[start:start + block]
        if bid in exact_ids:
            logits.extend(query @ kb.T * scale)
            vals.extend(vb)
        else:
            if anchor is None:
                ak, av = kb.mean(0), vb.mean(0)
                bias = np.log(len(kb))
            else:
                ak, av, bias = summary(anchor, kb, vb)
            logits.append(query @ ak * scale + bias)
            vals.append(av)
    return softmax(np.asarray(logits)) @ np.asarray(vals)

rng = np.random.default_rng(20261024)
k = rng.normal(size=(32, 8))
v = rng.normal(size=(32, 5))
a = rng.normal(size=8)
dense = softmax(a @ k.T / np.sqrt(8)) @ v
out = mixed(a, k, v, {1, 5}, anchor=a)
print(np.max(np.abs(out - dense)))
assert np.allclose(out, dense, atol=1e-12, rtol=0)

exact_ids 是本例手动指定的精算块集合;生产代码会由路由生成。选中块只贡献原始 token;未选中块只贡献摘要,避免重复记账。

最后只有一次 softmax,这一行承担了分子与分母的正确合并。

运行最后一段,最大绝对误差约为 1.25×10⁻¹⁶。同样随机输入与 exact 集合下,将尾部改成均值摘要,最大绝对误差约为 0.240925。

这个数字用于检验构造,不能当作 H3 指标或普适收益。

配套实验还做了三个独立检查:全部块精算时回到 dense;Q/K 重排后恢复输出保持不变;对侧二阶矩空间的 cosine 与完整打分向量 cosine 一致。三个最大误差均低于 1.1×10⁻¹⁵。

完整脚本位于本项目 tools/spark_h3_lab.py,会保存实验数字和两张图。它的等容量二叉 PCA 分组仅用于解释 Reblock 直觉,不冒充作者的分区算法。

复现生产性能需要跑真实 H3、正确的 CUDA 后端和相同评测协议。

11 源码地图:把每个公式对应到文件和调用路径

从公开入口追到摘要与内核

自制源码路线图;文件与当前解读固定的 502ef356 版本对应。图中的顺序用于阅读理解,实际后端可以融合若干步骤。

固定版本源码中,公开入口、布局、路由与内核分得比较清楚。阅读时建议沿着下面的顺序走,避免从一个叫 Spark 的辅助实验文件误入非默认路径。

第一站:公开入口。 spark.py 把 spark_reblock 直接别名到 recursive_landmark_tree_v2_blocks,把 spark_reweight 别名到 virtual_summaries。后者只构建加权 K/V 与 bias,不负责生成代表点、路由、精算或合并输出。

第二站:模型安装器。 processor.py 的 install_h3_spark_attn 构建控制器,安装 attention processors 和布局 hook。上下文退出时恢复原状态;同一个安装上下文中再次调用 pipeline 前,需要 reset,避免沿用上一次去噪计数与缓存。

第三站:二阶矩与分组。 landmark_direction.py 中的 landmark_direction_factors 处理交叉度量;landmark_tree_v2.py 构建等容量层次与 permutation。指标估计、landmark 策略和树分割是独立选择,别把它概括成一次普通 sort。

第四站:Top-K。 spark_integration.py 的 _sol_topk_policy_scores 提供了很直观的参考路径:计算 query 块均值与 key 块质心点积,再按候选视频块数确定预算。它不是先构建全 token 注意力矩阵再取 Top-K。

相邻位置的强制 exact 带,在重排默认设置下关闭。独立排列 Q/K 后,块号相邻已不表示原时空邻近。exact context 则单独加入,不挤占候选视频块预算。

spark_route.py 明确标为 experimental,不能仅凭名字把它当作默认路由。

第五站:摘要。 sol_numerator_virtual_q.py 的 _summaries 和 virtual_summaries 对应第 8 节。核对重点是三个输出:加权 key、加权 value、log-mass;它们必须来自同一套权重和尺度。

底层用 exp2/log2,是 GPU 数值实现选择。点积先乘 1/√128,再换到以 2 为底的指数单位,写回 bias 时再换回自然对数。

看到 1.442695... 与 0.693147...,不要误以为模型换了定义;它们分别是 log₂e 和 ln2。

第六站:融合计算。 spark_reweight_sm120.py 包含路由 mask、online softmax 与摘要质量合并等实现。生产路径还包含 packed route 导出,尽量避免在注意力内核里再次算路由 QK。

整体数据流可以理解为:QKV 投影与位置处理 → 确认 packed token 范围 → 重排规划 → 块路由和尾部摘要 → exact 与近似联合归一化 → 恢复 query 排列 → 输出投影。

某些后端将其中几步融合,未必存在对应的中间大张量。

12 为什么 Python 与 ComfyUI 要分开理解

Python 与 ComfyUI 的两条实现路径

根据固定版本源码整理:算法思想相通,安装方式、内核与默认值分别核对。ComfyUI 的 producer_chunk 是 QKV 生产端分块,不是 64-token 注意力块。

Diffusers/Python 与 ComfyUI 是两条集成路径。它们共享算法思想,但 hook 位置、内核、默认参数和布局实现会变化。

不能在 Python 路径复现一个结果,就认为 ComfyUI 所有配置都会逐位一致。

ComfyUI 的 comfyui_nodes.py 在原生 dit/double_block patch 结构接入;comfyui_backend.py 连接 architecture-specific comfy-kitchen CUDA 后端。

它没有在运行时调用研究路径的 Triton/CuTe attention 内核。

一个很实在的优化,是把排列索引直接交给前后处理:读入 Q/K/V 时按布局消费,输出时按逆排列 scatter,减少四次实体 gather 带来的额外显存读写。

数学上等价的流程,在长序列下可能有完全不同的内存成本。

固定版本节点的默认参数还包括:topk_ratio=0.2、dense_layers=0、min_tokens=12288、tail_granularity=query、producer_chunk=16384。

其中 producer chunk 是 QKV 生产端分块大小,不是 attention block size;后者仍通常为 64。较早文档出现的 4096 不能当成当前默认值。

tail_granularity=query 保留每一条真实 q 来消费摘要;block 则同一个 query 块共享近似结果。exact 分支仍使用真实 query。

只看“都有 Reweight”无法判断这两种配置的误差是否相同。

默认 sparse_scope=target-video,目标视频以外的参考视频、图像、文本和音频按 exact 条件处理。

Ref2VA 可以显式选择 joint-video,将目标与参考视频共同放入稀疏域;静态参考图、文本和音频仍 exact。这是功能范围变化,应独立评价参考一致性。

混合尾块也需要小心。视频边界如果不是 64 的倍数,不能把后面的文本 token 当成视频一起聚类。默认 dense-tail 路径把这一段按 exact 处理。

布局来自模型提供的元数据,比猜测 token span 可靠。

13 如何开始使用,哪些参数先别混着改

19 次真实调用中的 warmup 安排

自制调度图:19 次真实去噪、20% warmup 向上取整为 4 次 dense;随后 15 次启用 Spark。调度器另含最终 σ=0 端点。

截至核对日期,作者 v0.1.5 发布说明 提供 Linux/Windows x86_64、SM86/SM89/SM120 的 CUDA 13.0 安装包,并增加 ComfyUI 0.42.x 的 comfy-kitchen 0.2.39 支持;包内同时提供面向 0.38.x–0.40.x 的 wheel。

Python 3.12+、PyTorch CUDA 13.0+ 等要求应以当前安装包为准。

SM86、SM89、SM120 大致对应这批发布包中的 RTX 30、RTX 40、RTX 50/相关 Blackwell 设备。

不要把研究代码中的 SM90/SM100 dispatch 分支,等同于这些架构已完成生产验证。硬件支持、融合实现完成度和发布包可用性,是三项不同事实。

如果走 ComfyUI,先下载符合操作系统与 GPU 架构的 ZIP,连同 SHA256SUMS 校验;将节点目录放到 custom_nodes,用启动 ComfyUI 的同一个 Python 执行安装器,再重启。

权重和 LoRA 不包含在节点包中。

参数建议从 fidelity、20% Top-K 和默认 exact 条件范围开始。

fidelity 在前 20% 模型调用使用 dense;speed 从第一次调用起稀疏;dense 用于旁路对照。

这三个模式不是博客主表里按 10%/20%/30% 密度命名的同一组标签。 模式控制 warmup,Top-K 控制活跃阶段的精算预算,需要分别记录。

例如 19 次真实去噪调用,20% warmup 按向上取整得到 4 次。

MiniMax-H3 的调度器还包含最终 σ=0 端点,因此 Python pipeline 的 num_inference_steps=20 对应 19 次真实去噪;安装器的 num_denoise_steps 应传 19。

少步 LoRA 的调度规则则按各自官方说明处理。

Python 集成可以写成下面的最小改动。这里假定 pipe、模型权重和 inputs 已按 MiniMax-H3 官方流程准备完成;它不是一份独立模型加载脚本。

from h3_sparse_attention import install_h3_spark_attn

n_denoise = 19
with install_h3_spark_attn(
    pipe.transformer,
    num_denoise_steps=n_denoise,
    warmup_mode="warmup_steps",
    warmup_steps=4,
    dense_layers=0,
    topk_ratio=0.2,
) as attention:
    result = pipe(
        **inputs,
        num_inference_steps=n_denoise + 1,
    )
    stats = attention.summary()

调参时先固定模型、prompt、seed、scheduler、帧数与分辨率,对比 dense 和 fidelity。

然后只改变 Top-K,观察脸部细节、快速运动、跨镜头一致性与参考保持;确认误差可接受,再减少 warmup。

计时至少同时记录模型去噪时间与整条 pipeline 时间。第一次编译、模型加载、权重 offload、VAE 解码和音频处理应明确计入或排除。

RTX 4090 与 96GB Blackwell 上的显存策略不一样,不能直接平移博客中的秒数。

若配合 KJNodes 低显存节点,作者建议模型连接顺序为:加载器 → Low VRAM Attention → Chunk FeedForward → Spark → 采样器。

小 chunk 可以降低临时显存,但会增加调用开销。双阶段 LBH 工作流中,高分辨率第二阶段应按作者说明关闭 dense warmup,避免再次支付预热成本。

14 如何判断“更快”与“更好”的证据

先看 Amdahl 定律。设原始流程里可被这项优化影响的比例为 p,该部分加速 r 倍,那么整体加速由两部分共同决定:

$$S=1/((1-p)+p/r)$$

原主表 Spark-H3 10% 的 attention 加速是 2.33×,DiT 加速是 1.73×。

将两者粗略代入简化模型,可反推出约 74% 的可加速占比;这只帮助理解未加速部分的约束,不是作者提供的 profiler 分解,更不能据此精确拆出 Reblock、MLP 各用了多少时间。

Spark-H3-Lite 在博客中被描述为重排延迟减半,主表 10% 时比标准版快 7.2 秒。

不要仅凭这个描述,把源码里的任意 q_reuse_k 或相邻层复用开关直接认定为 Lite 的唯一实现;复现实验还需要相应配置与完整记录。

再看与 Video DeltaNet 的比较。

博客在 345 帧、14.4 秒设置下报告,无 warmup 的 Spark-H3 达到 BF16 2.49×、FP8 2.86× 的每步 DiT 加速;相应 VDN 为 2.28×、2.60×。

这组数字不能证明 Spark 在同质量下胜过 VDN。两者没有可直接对齐的相同 dense 权重;作者也明确把无 warmup 结果看成乐观速度上界。

采用旨在保真度的 warmup 时,VDN 仍更快。FP8 行还必须与 FP8 dense 比,不能拿 BF16 dense 做分母放大加速。

Few-step LoRA 和 Spark 可以分别减少“运行几次”与“每次算多少”,但组合收益通常不是两个宣传加速倍数直接相乘。

warmup、第一层保留 dense、CPU–GPU 传输以及 latent 分辨率变化都会改变结果。

技术定位可以这样对照:

方法 改进重点 剩余内容如何处理 使用代价与边界
固定布局 BSA 规则分块与选择精算块 取决于具体实现;博客消融带均值尾部 易接内核,分组可能不匹配当前内容
Sol-Attn 动态阈值选择与融合归一化 均值压缩分支 稀疏率随内容变化
Veda 训练更准确的块选择评分 博客讨论的方案丢弃未选块 需要相应训练或适配权重
Spark-Attn 自适应布局与加权尾部摘要 代表 query 条件下的加权 K/V 加 bias 重排成本、代表点近似与后端兼容
Video DeltaNet 精算局部规则加训练适配的 DeltaNet 通过学习的线性分支覆盖其余关系 模型适配与权重不能直接等同 dense

BSA 在不同项目里可能只表示一个宽泛的算子家族。有些实现丢弃尾部;这篇博客的消融基线保留均值尾部。讨论横向比较前,应先确认具体算子,避免同名不同义。

15 我对这项工作的判断

Spark-H3 最值得学习的地方,是它把三个常常混在一起的层次接上了:先定义注意力偏好的几何,再构造 GPU 能消费的规则块,最后为未精算部分建立同时考虑质量与内容的摘要。

Reblock 的对侧二阶矩有明确的打分向量解释;Reweight 的摘要可以推导出代表点匹配和 log-mass 切线性质;内核再把这些运算融合进真实推理流程。

读懂其中任意一层,都能回头检查另两层是否实现了同一件事。

工程上也要保留几个现实判断。

当前证据主要围绕 MiniMax-H3,不能外推到所有 DiT;单代表点会有结构性误差;保真度和主观质量不能互相替代;长序列的节省要抵消重排与摘要成本,短序列可能更适合 dense。

作者博客尚不能替代完整可复现实验报告。

如果你已经在做 H3 工作流,这是一条值得实测的推理替换路径。若做稀疏注意力研究,更值得跟进的是代表点怎样选择、块质量误差怎样界定,以及能否让路由预算随层和内容变化,同时保留高效内核。

读代码时可以一直带着三个检查:这个块为什么值得精算?这个摘要的质量和内容是否配套?这些优化最终有没有省下真实墙钟时间? 这三个问题,比单看一个稀疏率更接近方法是否可用。

来源与复现实验

原理图与数值验证为本次独立编写的 CPU 实验;原博客实验值均已注明来源和条件。未运行模型权重、未测本机 GPU 性能。解读与推导:人工智能炼丹君,2026-10-24。

0

评论 (0)

取消
粤ICP备2021042327号