33B Omni-Transformer 的结构:MiniMax H3 里那 13B 参数为什么推理时不用加载

2026-08-09

看模型架构文档,最容易犯的错是把参数量当成部署成本、把”结构里有”当成”发出来的版本里能用”。MiniMax H3 的 Omni-Transformer 这一段,恰好两个坑都踩得到,而且官方 README 把话说得挺清楚,只是读的人常常一扫而过。

这篇只干一件事:把截至 2026-08-09 的 MiniMax H3 官方仓库 README「Model Architecture」章节和仓库内的 transformer/config.jsonFL2VA/transformer/config.json 摊开来对着读,让你看完能自己判断——哪几个数字是可以拿去做工程决策的,哪几个数字看着像结论其实什么都不是。

先把口径说在前面:我们没有下载权重、没有部署、没有发起过任何一次推理请求。下面所有数值都来自仓库里的文件,不含任何本机测量。

一、“dense 单流”这四个字承载的信息量

官方对 H3-Omni-Transformer 的定义是:33B 参数的 dense、单流(single-stream)Transformer

dense 的意思是它不是 MoE 结构,没有专家路由,参数在前向过程中不做稀疏激活。这决定了它的参数量和”每步实际参与计算的参数量”之间不存在一个可以随手打折的比例。

single-stream(单流)则要结合另一条 README 里的描述才能读懂:注意力层与 FFN 层都不含模态特定结构。也就是说,视频 latent、音频 latent、文本表示这些不同模态的 token,被 H3-Base 组织成一条统一的 packed multimodal sequence 之后,就一起顺着同一套注意力层和同一套 FFN 层往下走,中途没有”这一层只处理音频”这种分岔。

那模态之间的差异去哪了?官方给的答案是:模态特定参数只存在于输入/输出层与 AdaLN 分支

这个分工值得记一下,因为它是后面所有判断的基础。序列进 Transformer 之前,不同模态各走各的编码路径(文本由 H3-Encoder 编码,视觉输入由 H3-Encoder 与 H3-VisualVAE 共同编码,音频仅由 H3-AudioVAE 编码);进了主干之后是”混着走”的;输出端再分开,Omni-Transformer 联合预测视频与音频的 latent,之后分别解码为视频与立体声音频。

所以当你看到 “33B” 这个数字,它指的是这一整块骨干加上挂在旁边的调制分支的总和,而不是”一条 token 流过去要过 33B 的注意力和 FFN”。

二、最反直觉的一条:约 13B 参数在 AdaLN 分支,仅推理时不需要加载

README 原意是这样的:33B 参数中,约 13B 位于 AdaLN 相关分支;因为 AdaLN 的调制输出可以预先计算并缓存,这些参数在”仅推理”的部署中不需要加载

第一次读到这句会有点转不过弯——参数就在模型里,怎么会不用加载?

理解的关键就在官方那半句解释里:AdaLN 的调制输出可以预先计算并缓存。一份输出既然能被「预先算好」,那它就不依赖生成过程中实时变化的东西——可以离线算完、存下来、运行时直接取用。而取用缓存这一步,并不需要再把当初生成这份缓存的权重装进来。

README 只说到这一层。这条分支具体接收哪些条件输入、缓存以什么形式组织、预计算发生在哪个环节,官方没有写,别去猜。

官方同时说明,他们发布的是完整模型权重,目的是支持包括微调在内的后续开发。这两件事不矛盾:训练/微调时你需要这 13B,因为要更新它;纯推理时你可以只带走缓存下来的调制输出。

这条为什么重要?因为它直接推翻了”33B 的模型,按 33B 去估资源”这个下意识动作。如果你正在评估”这东西我这边跑不跑得动”,把 33B 当作分母算出来的任何结论都是站不住的。

但请注意,它同样不支持你反过来算。官方没有给出任何显存数字、模型体积、推理速度指标,我们这边也没有做过任何本机测量。“33B 减 13B 等于 20B,所以需要多少 GB”这种换算,中间隔着精度、缓存、激活值、实现方式一堆没有公开的变量,做不得。

想知道”跑得动吗”,目前唯一有依据的参照是官方在部署说明里给出的示例配置——比如 SGLang 侧的官方示例使用 4 GPU 配置。这是官方示例使用的配置,不等于”必须四张卡”,也不等于”四张卡就够”。要谈这个话题就引用它,别自己算。

三、AdaLN 为什么值得单独设一条这么粗的分支

顺着上一节的分工再想一步,就能看懂这个设计的取舍。

如果模态差异要靠”给音频单独开一套 FFN、给视频单独开一套注意力”来表达,那模型会分叉成好几条流,参数量和训练复杂度都往上翻,推理时也没法把不同模态塞进同一条序列里一起算。H3 的做法是把模态差异压到调制层:主干保持模态无关,靠模态特定的 AdaLN 在每一层给出不同的缩放与偏移。

官方对此的说法是,模态特定的 AdaLN 能以相对较低的训练与推理成本提升生成质量。“相对较低”是官方措辞,README 没有给具体数据来支撑一个比较值,所以这句只能作为设计意图引用,不能当成性能结论。

而这个设计恰好又和第二节咬合上了:正因为调制分支的输出可预计算,把参数堆在这里的推理代价才比堆在主干里低。13B 这个体量放在别处会是实打实的推理负担,放在 AdaLN 分支上则可以在仅推理场景被缓存掉。

四、MM-RoPE:位置编码为什么必须是三维的

H3 用的是三维多模态旋转位置编码(MM-RoPE),在时间与两个空间维度 (t, h, w) 上表示位置关系。

为什么必须是三维?回到第一节的结论:所有模态的 token 被展平进同一条序列。一旦展平,“这个 token 原本在第几帧、在画面的哪一行哪一列”这个信息就丢了。如果只用一维位置索引,模型只能知道谁在谁前面,无法区分”同一帧里横向相邻”和”相邻帧里同一位置”这两种完全不同的关系。三维 RoPE 把 (t, h, w) 分别编进去,序列被压平之后空间与时间结构仍然可恢复。

README 也提到,在整条序列送入 Omni-Transformer 之前,会先用 RoPE 捕捉 token 之间必要的空间与时间关系——位置信息是在进主干之前就注入好的。

config 里与之对应的键有 rope_freq_dim: 16rope_theta: 10000.0,原始 checkpoint 格式那份里对应的是 rope_inv_freq_len: 16。这两个数值可以引用,但 config 只给了数值,没有给频率如何在 (t, h, w) 三个维度间分配的说明,别去推。

五、config.json 硬参数表怎么读

下面这张表来自仓库内 transformer/config.json(diffusers 格式,_class_name: MiniMaxH3Transformer3DModel_diffusers_version: 0.36.0.dev0),是可以直接引用的原始数值。

num_layers50
num_attention_heads56
attention_head_dim128
hidden_size5376
ffn_dim14336
num_refiner_layers2
in_channels24
audio_in_channels32
patch_size[1, 2, 2]
text_dim5120
freq_dim256
time_embed_hidden_dim5376
time_embed_dim2688
rope_freq_dim16
rope_theta10000.0
norm_eps / qk_norm_eps / final_norm_eps1e-05

仓库里还并存着另一份 FL2VA/transformer/config.json(原始 checkpoint 格式,_class_name: MiniMaxH3DiTModel_diffusers_version: 0.32.2),键名不同但数值一致,另有几个 diffusers 版里没有的键:adaln_out_features 为 96768,final_adaln_out_features 为 10752,token_refiner_num_layers 为 2,latents_dim / audio_latents_dim 为 24 / 32,ffn_hidden_size 为 14336,rope_inv_freq_len 为 16。

这张表真正的价值不在于背下来,而在于它能和 README 的文字描述互相印证。几处对得上的地方:

  • in_channels: 24 与 README 里 H3-VisualVAE 的「24 个 latent 通道」对得上;audio_in_channels: 32 是音频侧的 latent 维度。
  • patch_size [1, 2, 2] 与 README 的「patch size 在 (time, height, width) 上是 1 × 2 × 2」对得上。再往下算一步:VAE 的空间压缩因子是 16×,乘上 patch 的 2,等于 32,正好是 README 说的「进入 Transformer 的视觉 token 有效空间下采样因子为 32×」;时间方向 patch 是 1,所以时间下采样因子仍为 4×,也对得上。
  • text_dim: 5120 对应的是 H3-Encoder 那一侧的接口维度。H3-Encoder 使用 Qwen3-VL-32B 的完整预训练权重,把其第 50 层的 hidden states 交给 Omni-Transformer。
  • adaln_out_features 为 96768、final_adaln_out_features 为 10752,这两个键只出现在原始 checkpoint 格式那一份里,是 AdaLN 分支在配置层面留下的直接痕迹,和 README 里「模态特定参数只存在于输入/输出层与 AdaLN 分支」这句话属于两处可以互相呼应的官方信息。但别拿这个宽度去反推参数量——config 没有给出这条分支的层数与内部结构,凑不出那 13B。

两份 config 的 _diffusers_version 不一样(0.36.0.dev0 与 0.32.2),说明仓库里并存两套格式。如果你在写加载代码,先确认自己拿的是哪一份、键名对不对得上,别拿 diffusers 那套键名去读 FL2VA 那份文件。

六、56 × 128 = 7168,而 hidden_size 是 5376

这是这张表里最容易让人卡住的一处。

按大多数 Transformer 实现的习惯,num_attention_heads × attention_head_dim 会等于 hidden_size。这里 56 × 128 = 7168,而 hidden_size 写的是 5376,两者不相等。

这是事实,可以指出。但到此为止。

config.json 只是一份数值清单,它不告诉你注意力的 q/k/v 投影是怎么接的、有没有额外的投影层、这两个维度在实现里各自作用于哪一段。任何”所以它一定是这样实现的”的说法,都是在没有源码依据的情况下编故事。如果你需要确切答案,正确的下一步是去读官方仓库里的建模代码,而不是从 config 反推。

我把这条单独拎出来讲,是因为它是一个很好的自检点:当你看到一个不符合常规的数字,第一反应应该是”我需要去看实现”,而不是”我来解释一下为什么”。

七、稀疏注意力:能力是能力,发布状态是发布状态

最后一条,也是最容易被写错的一条。

README 说:为降低长多模态序列的计算开销,H3 原生支持稀疏注意力的训练与推理,训练的最后阶段引入了 native sparse attention。

同一段里还说:首次开源发布只提供 full attention 的推理,稀疏注意力实现将在未来更新中发布。

这两句必须一起读。“原生支持稀疏注意力”描述的是模型能力,“开源版只能跑 full attention”描述的是当前的发布状态。把前半句单独摘出来写成”H3 开源版支持稀疏注意力”,就是错的。

对你的实际影响很直接:如果你正在评估长序列场景下的开销,当前开源版的推理路径是 full attention,不要按稀疏注意力的复杂度去做规划。这个状态截至 2026-08-09 是这样,未来更新可能改变,用之前请重新确认仓库说明。

顺带一提,同样属于”能力与发布状态要分开说”的还有 H3-Regenerate-2K:它的做法是不使用传统的专用超分模块,而是让基础模型以 in-context 的方式重新生成自己的低分辨率结果,从而复用原始多模态上下文;但该模块尚未开源,官方提供 API 用于验证官方结果。

看完这篇你应该能做的判断

  • 有人拿 “33B” 直接推资源需求时,你知道该追问一句:算的是训练还是仅推理?AdaLN 那 13B 算进去了吗?
  • 有人说”H3 支持稀疏注意力所以长序列很省”时,你知道该确认的是开源版当前的推理路径。
  • 你手上有一份 config.json 却对不上代码时,你知道先确认它是 diffusers 格式还是原始 checkpoint 格式。
  • 你看到 56 × 128 ≠ 5376 时,你知道下一步是去读建模代码,而不是找一个自洽的解释。

关于许可,H3 使用的是「MiniMax H3 Community License Agreement」,条款请直接读官方仓库里的 LICENSE 原文。

延伸阅读


本文依据 MiniMax H3 官方仓库(github.com/MiniMax-AI/MiniMax-H3)的 README、 模型配置文件与官方 h3-prompt-writing skill 文档整理,核对日 2026-08-09。 本文内容为官方仓库口径,未在本机部署或调用过 H3。 模型、部署方式与许可条款以官方最新说明为准。

许可条款请以官方 LICENSE 原文为准,本文不构成法律意见。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。