Papers

minivLLM 旧引擎审计与复用决策

快速定位 → 结论 与 diffusion_engine 的关系 14 模块盘点 A/B/C 决策 KV Cache 对比

结论

最终决策:C - 完全不适合复用,新建 diffusion_engine/

minivLLM 是一个约 900 行的 Qwen3 自回归推理引擎。对 14 个模块的审计显示,GQA、causal mask、RoPE、KV cache 和自回归采样都不能直接用于 DiT/MMDiT 的全注意力并行去噪。可直接复用的代码只有 activation.py 中 11 行的 SiluAndMul

次选方案 B 被限定为"仅复用 SiluAndMul + 代码风格参考",不构成对 C 的实质替代。新引擎将在 diffusion_engine/ 目录下从零构建,与 minivLLM/ 保持物理隔离、依赖隔离和概念隔离。

和我的 diffusion_engine 的关系

旧引擎对新引擎的价值

minivLLM 不参与 diffusion_engine 的运行时依赖。新引擎不从旧引擎 import 任何模块,不在旧引擎目录中创建或修改文件。旧引擎的代码仅供以下几类参考:

新引擎必须从零写的模块:DiT attention(full attention,无 causal mask,无 GQA)、AdaLN-Zero、timestep embedding、noise scheduler、denoising loop、VAE 集成。这些模块在旧引擎中完全不存在。

14 个模块盘点

# 模块 旧引擎状态 扩散需要吗 复用判断
1 Tensor Abstraction No 部分 不可复用。直接使用 torch.Tensor,无抽象层
2 Model Loader Partial 不可复用。依赖 HF AutoModel,需重写扩散专用 loader
3 Transformer Block Yes 仅参考 Pre-Norm+residual 结构。需改为 AdaLN+full attention
4 Attention Yes 是(full attention) 不可复用。GQA+causal mask+RoPE 服务自回归,DiT 需重写
5 MLP / FFN Partial 部分可复用。SiluAndMul 可直接复用(11 行),FFN 需重写(有 Bug)
6 Norm Yes 是(AdaLN) 仅参考 residual 融合模式。需重写为 AdaLN-Zero
7 RoPE Yes 不需要 不可复用。扩散用 2D sinusoidal position embedding
8 Timestep Embedding No 无实现。必须从零实现
9 Scheduler No 无实现。noise scheduler 与 LLM 请求调度完全无关
10 Sampling Loop Partial 不可复用。自回归 greedy vs 迭代去噪,完全不同的循环结构
11 Memory Manager No 部分 不可复用。无内存管理代码。扩散需要 activation checkpointing
12 KV Cache Yes 不需要 不可复用。扩散 denoising 每步 latent 全刷新,无跨步 KV 复用场景
13 Paged Attention No 不需要 占位字段,无实现。扩散不需要 KV 分块管理
14 Config / Context Partial 是(diffusion 专用) 仅参考 dataclass 写法。字段需完全重写
统计:5 个 Yes  |  3 个 Partial  |  6 个 No  ·  唯一可直接复用:SiluAndMul(11 行)  ·  可参考(仅风格):7 个  ·  明确不可复用:6 个  ·  旧引擎总代码量:约 900 行 Python

A / B / C 决策论证

A - 大幅复用(否决)

B - 部分复用(次选,严格限定)

C - 完全不适合,新建 diffusion_engine/(主方案)

minivLLM 围绕自回归解码、KV cache、causal mask、RoPE 和 RMSNorm 组织,扩散引擎需要的是并行去噪路径。逐项改造旧代码比单独实现新引擎更费事,还会把 LLM 专用逻辑带进新的模块边界。

建议:在 diffusion_engine/ 下新建所有模块,仅从 minivLLM/ 复制 SiluAndMul(11 行)并参考 7 个模块的工程风格。

LLM KV Cache 与 Diffusion 推理循环差异

这是旧引擎审计中最容易产生误判的点,也是复用决策中需要最清晰阐述的部分。以下是两个推理范式的逐项对比。

推理循环结构对比

LLM 自回归推理(有 KV cache)

Step 0 输入 [token_0] → 计算 K₀, V₀ → 写入 cache → 输出 token_1
Step 1 输入 [token_1] → 读 cache(K₀,V₀) + 计算 K₁,V₁ → 写入 cache → 输出 token_2
Step N 输入 [token_N] → 读 cache(K₀~K_{N-1},V₀~V_{N-1}) + 仅计算 K_N,V_N → 输出 token_{N+1}

扩散迭代去噪(无 KV cache)

Step T 输入 x_T(纯噪声,全 latent)→ 计算 K_T, V_T(全 patches)→ 输出 v_T(矢量场)→ 去噪得 x_{T-1}
Step T-1 输入 x_{T-1}(全 latent,内容不同于 x_T)→ 计算全新的 K_{T-1}, V_{T-1} → 输出 v_{T-1} → 去噪得 x_{T-2}
Step 0 输入 x₀ → 计算 K₀, V₀ → 输出 v₀ → 得到干净 latent → VAE decode

复用差异表

维度 LLM 自回归推理 扩散去噪推理
序列长度变化 逐步增长(1 → 2 → ... → L) 固定(latent patch 数不变)
历史信息 已生成的 token 的 K/V 不变,可缓存 每步 latent 全刷新,上一步的 K/V 无意义
attention 类型 Causal(只能看过去) Full(所有 patches 互相 attend)
attention 复杂度 O(L²) 无 cache,O(L) 有 cache O(P²),P 为 patch 数(固定)
位置编码 RoPE(旋转,支持任意长) 2D sinusoidal(固定网格)
归一化 RMSNorm(静态 scale) AdaLN(动态 scale/shift 由 timestep 注入)
缓存策略 KV cache 是主要优化手段 KV cache 无用。优化焦点是 activation checkpointing + CFG batched forward
迭代终止 生成 EOS token 或达到 max_len 完成 T → 0 的所有时间步

简短总结

LLM 的 KV cache 依赖于"过去 token 的中间表示不变"这一前提:序列增长,已有 K/V 可复用。
Diffusion 的 denoising 不满足这一前提:每步输入 latents 完全刷新,K/V 不能跨步复用。
因此 KV cache 对 diffusion 推理是纯粹的冗余代码。minivLLM 的 KVCache 类不可复用到扩散引擎。扩散优化的正确方向是 activation checkpointing、CFG 双 forward 合并、VAE 解码缓存,而不是 KV cache。

可参考模块 与 明确不复用模块

可参考模块(仅风格/范式)

明确不复用模块

旧引擎的已知问题

问题 文件 影响
Qwen3FFN.act_fn = None minivllm/model/qwen3.py:87 FFN forward 会抛 TypeError。SiluAndMul 已定义但从未连接。说明旧引擎的 FFN 从未被完整端到端测试。
Paged attention 占位 minivllm/utils/context.py block_tablesslot_mapping 字段从 vLLM 拷贝但无任何 kernel 使用。无 paged attention 实际实现。
仅 greedy argmax 采样 validate_model.py:185-232 无 temperature/top-k/top-p,不能用于实际文本生成(仅 HF 对比验证用)。

对后续任务的具体建议

任务 建议
T11(DiT 实现) attention 从零写(full attention,无 causal mask,无 GQA)。不要从 Qwen3Attn 改造。
T12(CFG 采样) 采样循环从零写(for t in reversed(timesteps) → CFG 融合 → scheduler step)。不要参考 LLM greedy decoding。
T16(系统优化) 主优化方向:activation checkpointing + CFG batched forward + torch.compile。KV cache 不是目标。