STABLE DIFFUSION 1.5 → FLUX.2  ·  ARCHITECTURE / OPERATOR / TECHNIQUE EVOLUTION  ·  GROUNDED IN 15 CUDA TRACES从 SD 1.5 到 FLUX.2:结构、算子与技术的演进图谱

这份图谱不是文献综述,而是十五次真实 GPU trace 的横向合成。每一个参数量都由 module 级的输入输出维度反推重建,并与对应那次运行的 summary.json 逐位核对;每一处跨模型的差异都能被一个算式精确复现。
组织方式不是时间线,而是三条正交轴:主干(图像信息在什么结构里流动)× 条件通路(条件怎么进到主干里)× 潜空间(图像被压成什么)。任何一个模型都可以写成三个坐标。
按轴看比按时间线看更有用:能看清哪些变化互相牵连(主干换成 Transformer → 文本能与图像合成一条序列 → 空间条件也能塞进去,代价归零),哪些是独立的(潜通道 4 → 16 → 32)。

覆盖 15 次 trace5 代模型 · SD 1.5 → FLUX.2主干 0.86B → 9.08B文本塔 0.12B → 8.19B潜通道 4 → 16 → 32参数量重建差额 全部为 0

1 · 十五次 GPU trace 的地图

总览
1十五次 GPU trace 的地图:三个时代,五代模型所有参数量均由 module 级形状反推重建,与各次 summary.json 逐位一致UNet 时代卷积 U-Net + 跳连 + 交叉注意力MMDiT 时代纯 Transformer 同构堆叠 + 联合注意力FLUX.2 时代单双流混合 + 共享 ModulationSD 1.5@5120.86B主干0.12B文本塔管线 1.07B文本占 11.5%SD 2.1@7680.87B主干0.34B文本塔管线 1.29B文本占 26.4%SDXL@10242.57B主干0.82B文本塔管线 3.47B文本占 23.6%SD 3 Medium@10242.03B主干5.58B文本塔管线 7.69B文本占 72.5%SD 3.5 Large@10248.60B主干5.58B文本塔管线 14.26B文本占 39.1%FLUX.2 klein@10249.08B主干8.19B文本塔管线 17.35B文本占 47.2%管线总量涨了 16.3 倍,但主干只涨 10.6 倍主干:859,520,964 → 9,078,581,248,涨 10.6 倍。文本编码器:123,060,480 → 8,190,735,360,涨 66.6 倍。管线:1,066,235,307 → 17,353,362,723,涨 16.3 倍。差额几乎全在文本侧 —— 算力越来越多地花在「理解 prompt」而不是「画图」上。文本塔占比走出一条奇怪的曲线11.5%SD 1.526.4%SD 2.123.6%SDXL72.5%SD 3 M39.1%SD 3.5 L47.2%FLUX.2峰值在 SD 3 Medium:三塔 55.8 亿,比 20.3 亿的主干还大 2.75 倍。

2 · 三条正交轴

框架
2三条正交轴:任何一个模型 = 三个坐标按轴看比按时间线看更有用 —— 能看清哪些变化互相牵连,哪些相互独立轴一 · 主干图像信息在什么结构里流动SD 1.5 – SDXL卷积 U-Net + 跳连SD 3.x纯 Transformer 同构堆叠FLUX.28 双流 + 24 单流混合轴二 · 条件通路条件怎么进到主干里文本交叉注意力 → 联合注意力全局标量广播相加 → AdaLN → 共享 Modulation空间条件拼输入 / 旁路残差 / 推理期组织轴三 · 潜空间图像被压成什么SD 1.5 – SDXL4 潜通道 · 83,653,863SD 3.x16 潜通道 · 83,819,683FLUX.232 潜通道 · 84,046,115任何一个模型都可以写成三个坐标轴一 · 主干轴二 · 条件通路轴三 · 潜空间SD 1.5卷积 U-Net 4 级 · 12 条跳连16 处交叉注意力 + timestep 广播相加4 潜通道SDXL卷积 U-Net 3 级 · 9 条跳连70 处交叉注意力 + micro-conditioning4 潜通道SD 3.5 Large38 层同构 Transformer38 层联合注意力 + 每层 AdaLN16 潜通道FLUX.2 klein8 双流 + 24 单流32 层联合注意力 + 共享 Modulation + 零参数空间条件32 潜通道三条轴正交,但变化之间有因果主干换成 Transformer→文本可以与图像合成一条序列→空间条件也能塞进序列 → 零参数联合注意力让条件通路变重→每层各生成 AdaLN 占 33%→FLUX.2 把 Modulation 提到顶层压到 2.77%所以「潜通道翻倍」是独立的一步,而「零参数空间条件」是主干换代之后自然掉下来的。

3 · 主干:卷积 U-Net → 单双流混合

轴一
3轴一 · 主干:从卷积 U-Net 到单双流混合SD 3 之后主干里除了 patch 嵌入那一层,一个卷积都没有卷积 U-NetSD 1.5 / SD 2.x / SDXL859,520,964 → 2,567,463,684down 320128²/64²up 320down 64064²/32²up 640down 128032²/16²up 1280mid_block跳连(橙)把编码器细节直接送给解码器文本通过交叉注意力从旁边注入SD 1.5/2:12 条跳连 · SDXL:9 条ResNet 62.55% / TF 31.09% (SD 1.5)ResNet 12.77% / TF 86.05% (SDXL)SDXL 是这个时代的终点:还叫 UNet,但重量中心已是注意力。纯 TransformerSD 3 Medium / SD 3.5 Large2,028,328,000 → 8,595,081,2800JointTransformerBlock · 图文双流 + 联合注意力1JointTransformerBlock · 图文双流 + 联合注意力2JointTransformerBlock · 图文双流 + 联合注意力3JointTransformerBlock · 图文双流 + 联合注意力4JointTransformerBlock · 图文双流 + 联合注意力5JointTransformerBlock · 图文双流 + 联合注意力6JointTransformerBlock · 图文双流 + 联合注意力7JointTransformerBlock · 图文双流 + 联合注意力N-1末块 · context_pre_only(文本分支截断)没有跳连、没有分辨率金字塔文本有自己的残差流与 FFN,每层都被更新联合序列 4429 = 4096 图像 + 333 文本SD 3 M:24 层 · 1536 = 24 头 × 64SD 3.5 L:38 层 · 2432 = 38 头 × 64代价:每层各生成 AdaLN 调制,占主干 33%。单双流混合FLUX.2 klein 9B9,078,581,2480双流块 · 436,208,1281双流块 · 436,208,1282双流块 · 436,208,1283双流块 · 436,208,128…… 共 8 个双流块 ……8单流块 · 218,104,0649单流块 · 218,104,06410单流块 · 218,104,06411单流块 · 218,104,064…… 共 24 个单流块 ……单流块参数正好是双流块的一半并联投影:4096 → 36864 同时喂注意力与 MLP单流 57.66% / 双流 38.44%共享 Modulation 只占 2.77%hidden 4096 = 32 头 × 128 · 所有 Linear 无 bias。主干参数分布的反转:整条演化线里最能说明问题的一组数字SD 1.562.55%31.09%四级 U-Net · 16 注入点SD 2.162.09%31.6%四级 U-Net · 16 注入点SDXL12.77%86.05%三级 U-Net · 70 注入点SD 3.x / FLUX.2100%纯 Transformer · 每层联合注意力蓝=ResNet(卷积) 红=Transformer(注意力) 灰=上下采样等

4 · 条件通路:文本

轴二 a
4轴二 · 条件通路(一):文本从「只读的插件」到「序列里平等的一半」交叉注意力:文本是只读条件SD 1.5 / SD 2.x / SDXL图像 tokenq 来自这里1×4096×320文本嵌入k / v 来自这里1×77×768交叉注意力 · 注意力矩阵 = 图像 token × 77文本从头到尾是同一份张量,只被反复查询SD 1.5 16 处 · k/v 宽 768SD 2.1 16 处 · k/v 宽 1024 (差 6,389,760 = 2 × 256 × ΣC)SDXL 70 处 · k/v 宽 2048 (60 个集中在 32×32 一级)文本本身不被更新 —— 它是插件,图像是主体。联合注意力:文本是序列里平等的一半SD 3.x / FLUX.2图像 token自己的残差流 + FFN1×4096×hidden文本 token自己的残差流 + FFN1×333×hiddenq / k / v 沿 token 维拼接 → 一次注意力图看图 · 图看文 · 文看图 · 文看文,四种关系一次算完SD 3.x 4429 = 4096 图像 + 333 文本FLUX.2 4608 = 4096 图像 + 512 文本文本每一层都被更新 —— 这是与交叉注意力最本质的区别,也是后面「零参数空间条件」能成立的前提。文本编码器:一个 CLIP → 一个更大的 CLIP → 两个拼接 → 加一个 T5 → 换成一个通用 LLM编码器输出宽度token参数量SD 1.5CLIP-L12 层 / 76877123,060,480SD 2.xOpenCLIP-H23 层 / 102477340,387,840SDXLCLIP-L + CLIP-G拼接 → 204877817,720,320SD 3.xCLIP-L + CLIP-G + T5-XXL补零 + 拼接 → 40963335,580,620,800FLUX.2Qwen3-8B第 9/18/27 层 → 122885128,190,735,360两个同类细节:SD 2 用 OpenCLIP 的倒数第二层(23 层而非 24);FLUX.2 取第 9 / 18 / 27 层拼接 —— 最后一层对生成任务未必最好。「文本被读了多少次」SD 1.516SD 2.116SDXL70SD 3 M24SD 3.5 L38FLUX.232SDXL 是交叉注意力的顶点(70 处);SD 3 之后不再有「注入点」的概念 —— 每一层都是联合注意力,而且文本也在被更新。

5 · 条件通路:全局标量

轴二 b
5轴二 · 条件通路(二):全局标量timestep 与「prompt 的整体气质」怎么进主干 —— 这条路上有一次昂贵的绕行广播相加SD 1.5 / SD 2.x· timestep → 正弦编码 → MLP → 1280 维· 投到当前级通道宽度,逐通道加· 一次加法,没有 scale、没有 gate2,050,560 · 占 UNet 0.24%最朴素的做法,22 个 ResNet 各一份time_emb_proj。+ micro-conditioningSDXL· 再加 6 个尺寸标量 × 256 = 1536· 拼 CLIP-G pooled 1280 → 2816 → MLP → 1280· 把训练数据的缺陷当成条件告诉模型5,245,440 · 占 UNet 0.20%性价比最高的一处设计,但没有被SD 3 继承 —— 被更好的数据处理取代。每层 AdaLNSD 3 Medium / SD 3.5 Large· temb = timestep + pooled 文本· 每层生成 6 组 shift / scale / gate· LayerNorm 不带仿射,缩放交给它占主干 33.06% / 33.80%调制生成器占了主干的三分之一 ——每层两个 hidden → 6×hidden 的大矩阵。共享 ModulationFLUX.2 klein· 提到顶层,全模型只算 3 份· 双流图 / 双流文 / 单流,所有块共用· 省下的容量全变成更宽的 blocks251,658,240 · 占主干 2.77%从 33% 压到 2.77% —— 整条演化线里少见的「纯粹的效率优化」。条件通路占主干的比例:一次昂贵的绕行从 0.24% 涨到 33.8%,再压回 2.77%0.24%SD 1.50.24%SD 2.10.2%SDXL33.06%SD 3 M33.8%SD 3.5 L2.77%FLUX.2为什么会有这次绕行· UNet 时代条件很便宜:一个 1280 维向量投到各级通道宽度,一次加法就完事。· 换成 DiT 之后,调制成了主要的条件机制(LayerNorm 去掉仿射,缩放平移全交给它)—— 而每层都要自己生成一份。· FLUX.2 的观察是:这些调制参数其实不需要每层都不一样。提到顶层共享之后,能力损失很小,参数省下三成。

6 · 条件通路:空间条件

轴二 c
6轴二 · 条件通路(三):空间条件同一件事,四种做法,代价跨越五个数量级 —— 从 14,400 到 20.2 亿,再到 0拼进输入SD 1.5 / SD 2 / SDXL inpaint+14,400· conv_in 输入 4 → 9 通道· 4 噪声 + 4 masked latent + 1 mask· 模型每步都「看得见」掩码· 需要专门的 checkpoint320 × (9 − 4) × 3 × 3 = 14,400旁路残差 · UNetSDXL ControlNet Canny+1,251,014,160· 复制主干的编码器半边(下行 3 级 + mid)· 9 条跳连 + 1 个 mid 各注入一条残差· 上行半(占 51%)完整省掉· 主干的 48.7%编码器半边 1,243,367,040 + 入口 1,086,480 + 零卷积 6,560,640旁路残差 · MMDiTSD3 ControlNet Inpaint+2,023,618,560· 同构堆叠没有「一半」可以省· 复制前 23 块,逐块注入残差· 几乎等于再来一个主干· 主干的 99.8%主干 − 末块 − 输出头 + 控制入口 + 23 个投影推理期组织FLUX.2 四个变体+0· 参考图当成序列里多出来的 4096 个 token· 或者当成注意力的额外 k/v(缓存 2.00 GiB)· 掩码在模型之外逐 token 加权· 四个变体共用同一个 checkpoint17,353,362,723 —— 四次 trace 逐位相同代价对照:五个数量级柱高按 log 尺度绘制;「推理期组织」是 0,用虚线框表示+14,400拼进输入+1,251,014,160UNet 旁路+2,023,618,560MMDiT 旁路+0推理期组织

7 · 八项算子逐条对照

算子
7算子层面的演进:八项逐条对照每一格都能在对应那次 trace 的 module 或 config 里被直接验证SD 1.5SD 2.xSDXLSD 3 MediumSD 3.5 LargeFLUX.2 klein归一化GroupNorm(32)LayerNorm 有仿射GroupNorm(32)LayerNorm 有仿射=GroupNorm(32)LayerNorm 有仿射=LayerNorm 无仿射+ 每层 AdaLNLayerNorm 无仿射+ 每层 AdaLN=LayerNorm 无仿射+ 共享 ModulationQK 归一化无无无无(qk_norm=null)RMSNorm(64)RMSNorm(128)FFNGEGLUC→8C→4C→CGEGLUC→8C→4C→C=GEGLUC→8C→4C→C=GELU4× 扩张GELU4× 扩张=SwiGLU有效 3× 扩张位置编码隐式(卷积)隐式(卷积)=隐式(卷积)=正弦表 buffer192² 上限正弦表 buffer192² 上限=四轴 RoPE显式旋转 q/k注意力头8 头固定head_dim 40/80/160head_dim 64头 5/10/20/20head_dim 64头 5/10/20head_dim 6424 头head_dim 6438 头head_dim 12832 头proj_in / outConv2d 1×1LinearLinear—(无此结构)——Linear biasattn q/k/v 无其余有attn q/k/v 无其余有=attn q/k/v 无其余有=attn q/k/v 有attn q/k/v 有=全部无 biaspatchify不需要不需要不需要transformerpatch 2(Conv k2 s2)transformerpatch 2(Conv k2 s2)=VAE pixel shuffletransformer patch 1预测目标ε-predictionε-predictionε-predictionrectified flowrectified flow=rectified flow=读法:灰底「=」表示与左邻一列相同。可以一眼看出哪些算子在哪一代发生了变化。注意 FFN 一行不是单调演进:UNet 用门控(GEGLU),SD 3.x 退回普通 GELU,FLUX.2 又回到门控(SwiGLU)。

8 · 潜空间与 VAE

轴三
8轴三 · 潜空间:变化最小、性价比最高的一条五代十五次 trace 下来,VAE 参数量总共只多了 0.47%4 潜通道SD 1.5 / SD 2.x / SDXL编码器34,163,592解码器49,490,179VAE 合计83,653,863基准有 quant_conv(8→8)与 post_quant_conv(4→4)编码器输出 8 通道 = 均值 + 对数方差16 潜通道SD 3 Medium / SD 3.5 Large编码器34,274,208解码器49,545,475VAE 合计83,819,683相对左邻 +165,820移除了 quant_conv 与 post_quant_conv编码器输出 32 通道 = 均值 + 对数方差32 潜通道FLUX.2 klein编码器34,421,696解码器49,620,259VAE 合计84,046,115相对左邻 +226,432又加回 quant conv;patch_size = [2,2] 做 pixel shuffle编码器输出 64 通道 = 均值 + 对数方差几乎没变的东西五代共用同一套骨架下采样 / 上采样级数四级 · 128 / 256 / 512 / 512每级 ResNet 数量编码器 2 个,解码器 3 个(不对称)mid_blockResNet → 单头 Attention → ResNet解码器跳连无(纯前馈,不是 U 型)空间压缩8×编码器 2 个 / 解码器 3 个的不对称,正是解码器比编码器重 45% 的原因。变化只发生在首尾两层:编码器 conv_out 输出 8 → 32 → 64,解码器 conv_in 输入 4 → 16 → 32。83,653,863 → 83,819,683 → 84,046,115 总共只多 392,252(+0.47%)全管线最大的注意力矩阵在 VAE 里而且是单头的VAE mid_block @102416,384 token16384² ≈ 2.68 亿SDXL UNet 最浅注意力级4,096 token4096² ≈ 0.17 亿FLUX.2 单流块4,608 token4608² ≈ 0.21 亿SD 3.x 联合注意力4,429 token4429² ≈ 0.20 亿16384 = 128×128 —— 1024 分辨率下 latent 网格的全部位置。比 FLUX.2 主干的 4608² 大 12.6 倍,比 SD 3.x 的 4429² 大 13.7 倍。这就是 tiled VAE decode 在高分辨率下几乎是必需品的原因。

9 · 每一处差异都能被算式复现

方法
9方法学:每一处差异都能被算式复现十五次参数量重建全部差额为 0 —— 重建成功本身就是一次强交叉验证SD 1.5 → SD 2.16,389,7602 × 256 × ΣC16 个 cross-attention 的 to_k / to_v 从 768 加宽到 1024三代 Base → Inpaint14,400320 × (9 − 4) × 3 × 3conv_in 从 4 通道变 9 通道 —— SD 1.5 / SD 2 / SDXL 三次完全相同SDXL ControlNet1,251,014,1601,243,367,040 + 1,086,480 + 6,560,640主干编码器半边 + 条件嵌入金字塔 + 10 个零卷积SD3 主干 − ControlNet4,709,44059,114,560 − 54,405,120(末块 + 输出头) − (控制入口 + 23 个残差投影)重建规则随架构演化十五次重建里踩过的每一个坑,都是真实的架构差异卷积核3×3;conv_shortcut / quant conv 1×1;patch 2×2proj_in / outSD 1.5 是 Conv 1×1,SD 2.1 起是 LinearLayerNorm 仿射UNet 有(2C),DiT 无(0)Linear biasUNet attn 无 / SD3 attn 有 / FLUX 全无Embedding词表与位置表单独加,lm_head 权重绑定不重复计每个坑修正后差额都归零 —— 说明规则本身就是对架构的一份精确描述。四个典型的偏差,每一个都能被算出来post_quant_conv 按 3×3 算应为 1×1差 128ControlNet 零卷积按 3×3 算10 个注入卷积都是 1×1差 约 5,248 万FLUX.2 Linear 算了 bias正好是全部 Linear 输出宽度之和差 1,790,080Qwen3 漏了词嵌入表622,329,856 − bias 1,552,768差 620,777,088任何一条规则错了,总数就对不上 —— 这是最硬的一层校验。边界声明:什么成立、什么不成立成立形状、结构、层数、显存、参数量 —— 真实的 CUDA 证据不成立任何数值结论 —— 权重不是训练出来的口径耗时是单次带 trace 开销的观测值,不能当基准测试读SD 系用随机初始化权重;FLUX.2 用合成有限值(零投影 + 单位归一化尺度),避免 90 亿规模上的数值溢出。跨模型的显存对照还要注意分辨率口径。trace 规模:module 状态数直接反映实体化了多少东西FLUX.2 base2,711 行 / 1,143最小 · 连 VAE 编码器都不跑SD 3 Medium3,352 行 / 1,859SD3 ControlNet3,999 行 / 2,707SDXL ControlNet4,476 行 / 3,232最大 · 复制了注意力极密集的下行半FLUX.2 的 Edit(1,241)− Base(1,143)= 98,正好是 vae.encoder 的模块数。
如果只记一条:架构换代会让一部分能力从「需要新增网络」变成「免费」。同样是把空间条件(掩码、参考图、边缘图)告诉模型,四种做法的代价跨越五个数量级 —— SD 1.5 / SD 2 / SDXL 改 conv_in 要 +14,400(三代完全相同);SDXL 的旁路 ControlNet 要 +1,251,014,160(主干的 48.7%,因为 U 型结构有一半可以省);SD3 的旁路 ControlNet 要 +2,023,618,560(主干的 99.8%,同构堆叠无从省起);而 FLUX.2 的四个变体是 +0 —— 参数量逐位相同,共用同一个 checkpoint。
最后那个 0 不是靠技巧堆出来的:主干换成「一条统一序列上的注意力」之后,往序列里多塞 4096 个 token 本来就是天然支持的。UNet 时代做不到,因为文本走交叉注意力、图像走卷积,压根没有这样一条序列。
另一条值得记的:算力越来越多地花在「理解 prompt」上。五代下来管线总参数涨 16.3 倍,主干只涨 10.6 倍,而文本编码器涨了 66.6 倍(123,060,480 → 8,190,735,360)。峰值出现在 SD 3 Medium —— 三个文本塔比主干还大 2.75 倍。
也有反直觉的:条件通路曾经绕了一次远路。它占主干的比例从 UNet 时代的 0.24% 涨到 SD 3.5 Large 的 33.80%(每层各生成一份 AdaLN 调制),再被 FLUX.2 的共享 Modulation 压回 2.77%。这是整条演化线里少见的「纯粹的效率优化」:不改变能力边界,只把参数花得更值。
边界:形状、结构、层数、显存、参数量是真实的 CUDA 证据;任何数值结论都不成立(权重不是训练出来的);耗时是单次带 trace 开销的观测值,不能当基准测试读。