对象 :我们的 RWKVMLATransformer(rwkv4_mla_s6uw256) vs. Kimi K3(mini 缩放版) vs. DeepSeek V4(mini 缩放版)
协议:T=8192、B=1、600 步、lr=2e-4、AdamW、char 级词表 V=530、单 seed、同数据同顺序切分
日期:2026-10-31
1. 摘要
在严格对齐"参数量 ≈ 30.2M + 同训练协议"的前提下,我们把 Kimi K3 与 DeepSeek V4 的官方建模代码按其家族核心机制缩放到 30M,与我们的 RWKVMLATransformer 做了三臂对比。
| 臂 | 参数量 | 测试集 CE(600 步) | 峰值显存 | 单步耗时 |
|---|---|---|---|---|
| Ours(RWKV + 检查点 MLA) | 30.20M | 2.3360 | 4155 MB | 114 ms |
| Kimi K3 mini(KDA + gated MLA) | 30.25M | 2.2851 | 4621 MB | 1635 ms |
| DeepSeek V4 mini(CSA/HCA + mHC) | 30.27M | 2.3258 | 6959 MB | 526 ms |
三点结论:
- 质量 :K3 领先我们 0.0509 CE(相对 2.2%),V4 领先 0.0102 CE(0.4%)。考虑到单 seed 的跑动波动可达 ±0.04(见 §7.1),只有 K3 的差距接近可辨识阈值,需要用多 seed 复核。
- 代价:K3 的单步耗时是我们的 14.3 倍(KDA 的 chunk 化扫描仍比 RWKV 的 cumsum 形式重得多);V4 是 4.6 倍、显存是 1.67 倍。
- 我们的定位:在"每步算力 / 显存"这一维度上我们明显最优;差距主要出现在训练中前期(step 100--400),末期收敛斜率已接近。
另有内部归因 结论(§5.4--5.5):RWKV 之后的"检查点 MLA + 解压"通路在同参同深 对照下贡献 0.058 CE(3 seed,13σ) ,且不是参数效应(纯 RWKV 参数翻倍只值 0.002);解压环节不可省(换成旁路写回比没有深层更差)。机制上,稠密探针定位到了收益来源:单点多条键值关联两臂都能饱和(K 到 256 无差异),但"按顺序精确复现 4 个 token"时完整版 CE 0.094、全 RWKV 1.70(下界 2.30),差 1.61 ------ 收益来自"有序片段的精确取回",而不是查表容量。把 K3/V4 放进同一探针(§5.5.5)后排序变得完整:样本效率 K3 ≈ V4 ≫ Ours ≫ 全 RWKV (达标步数 ≈300 / ≈430 / ≈1900 / 未达标),但墙钟效率 Ours ≈ V4 ≫ K3(≈3.6 / 3.7 / 7.7 分钟)------我们靠"每步便宜"补回了样本效率上的劣势。

2. 实验设置
2.1 数据与训练协议
| 项目 | 取值 |
|---|---|
| 语料 | c_code_train.txt(前 1500 万字符) |
| 词表 | 字符级,从语料统计得到 V=530(不走任何预训练 tokenizer) |
| 序列长度 | T=8192(训练/测试同长) |
| batch | B=1(每步 8192 token) |
| 步数 | 600(三臂相同,等 batch 协议) |
| 优化器 | AdamW,lr=2e-4,betas 默认 |
| 权重衰减 | norm/bias/A_log/dt_bias/ape 等为 0,其余 0.01 |
| 精度 | CUDA autocast fp16 + GradScaler(KDA 内部扫描强制 fp32) |
| 梯度裁剪 | 无 |
| 评估 | 每 100 步在留出测试集上前 10 个 batch 上算 CE |
| 随机性 | 单 seed(0) |
说明:600 步 × 8192 token ≈ 4.9M token,属于架构筛选级预算,不是收敛级预算。所有结论都是"同预算下的相对趋势"。
2.2 参数对齐
以我们这一臂在本词表下的真实总参 30,197,458 为目标,用二分搜索调整两个对照臂的 MoE 专家宽度(其余结构固定):
| 臂 | 对齐旋钮 | 总参数 | 相对偏差 |
|---|---|---|---|
| Ours | ---(基准) | 30,197,458 | --- |
| K3 mini | moe_inter = 1056 |
30,250,832 | +0.18% |
| V4 mini | moe_inter = 992 |
30,273,525 | +0.25% |
三臂的参数构成高度一致:90% 以上都在 FFN/MoE,注意力部分只有百万量级。因此"同参数量"实质上是"同 FFN 容量",差异来自注意力的组织方式。
3. 我们的模型架构
RWKVMLATransformer 的核心主张是:把"记历史"和"精确检索"拆给两种互补的算子------线性 RNN(RWKV)负责把全部历史压进每位置的状态,稀疏检查点注意力负责在压缩后的长程上下文上做精确检索,最后再把深层结果解压回每一个位置。

3.1 逐段说明
(1) 嵌入 :Embedding(530→128) + RMSNorm。
(2) 浅层 ×4:RWKV-5 时间混合 + SwiGLU
每层是两个残差支路:
h = h + RWKV5( RMSNorm(h) )
h = h + down( SiLU(gate(RMSNorm(h))) ⊙ up(RMSNorm(h)) )
RWKV 时间混合(因果、可流式、O(T))先做 token-shift 混合当前与上一时刻:
x_r = x_t·μ_r + x_{t−1}·(1−μ_r) (k / v / g 同理,各自一套 μ)
r = σ(W_r x_r), k = W_k x_k, v = W_v x_v, g = SiLU(W_g x_g)
再按通道做指数加权的键值累积(WKV):
wkv_t = ( Σ_{i≤t} e^{k_i + w·(t−i)} v_i + e^{u + w·t} v_t )
/ ( Σ_{i≤t} e^{k_i + w·(t−i)} + e^{u + w·t} )
o_t = GroupNorm( r_t ⊙ wkv_t / 8 ) ⊙ g_t
其中 w = −exp(time_decay) ∈ (−1,0) 是每头每通道的衰减率,u = time_first 是当前 token 的额外权重。实现上用 cumsum 的并行形式(数值上等价于递推):
growth = exp(−w·pos), decay = exp(w·pos)
sum_k = cumsum(e^{k}·growth) · decay
sum_kv = cumsum(e^{k}·v·growth) · decay
这给了每个位置一个"全历史压缩状态",成本 O(T·d),与 T 线性。
(3) 检查点压缩(stride=6)
浅层输出上按位置抽样,只保留:
keep_t = (t mod 6 == 5) or (t ≥ T − 16)
即"远处每 6 个 token 取 1 个 + 最近 16 个 token 全保留"。T=8192 时 M ≈ 8192/6 + 16 ≈ 1381。近端全保留是刚需:预测下一个 token 只依赖最近位置,近期位置不能是稀疏表示。
(4) 深层 ×4:检查点上的 MLA
只在这 M 个位置上跑标准 Transformer 块,注意力用 MLA(低秩 KV + 解耦 RoPE):
kv_lora = 64:KV 先降到 64 维潜空间,再上投影出 K/V(含rope_dim = 8的 RoPE 分支)- 8 头,每头 16 维,因果注意力
- 注意力复杂度从 O(T²) 降到 O(M²) = O((T/6)²) ≈ T²/36
- FFN 仍是 SwiGLU,宽度 9600
(5) 主干解压 _CheckpointUp(窗口 256)
这一步是我们与"旁路写回"式压缩模型的关键区别。不是把深层的增量散回被选中的少数位置,而是让全序列每一个位置都对检查点做因果 cross-attention:
h_t ← h_t + o_proj( Attn( q=Norm(h_t), kv=Norm(h_checkpoints), mask: pos_k ≤ t ) )
并加窗口约束:位置 t 只读 [t−256, t] 内的检查点,复杂度 O(T·2W/stride) ≈ O(T·85),避免退化成 O(T·M) 的二次项。
效果是深度覆盖率 100%:每个位置的 logits 都能用到 4 层深层 MLA 的结果,而不是只有 1/6 的位置受益。
(6) 输出 :Final RMSNorm → 与 embedding 权重绑定的 LM Head(含 head_bias)→ 交叉熵。
3.2 复杂度与参数
| 组件 | 复杂度 | 参数量(本配置) |
|---|---|---|
| 浅层 RWKV ×4 | O(T·d) | ≈ 15.0M(FFN 占 14.7M) |
| 深层 MLA ×4 | O((T/6)²) | ≈ 15.0M(FFN 占 14.8M) |
| 解压 cross-attn | O(T·2W/6) | ≈ 0.06M |
| Embedding(绑定) | --- | 0.07M |
可见参数几乎全部落在 FFN 上,注意力侧的参数极少------这是它能以 128 维模型装下 30M 参数的原因。
4. 两个对照模型
对照臂不是"换个普通 Transformer",而是把两家官方代码的家族核心机制保留下来再缩放。

4.1 Kimi K3 mini
保留机制:
-
Kimi Delta Attention(KDA) :通道级衰减门 + delta 规则的线性注意力。状态矩阵
S ∈ R^{H×16×16}逐 token 更新S_t = Diag(α_t)·S_{t−1} − β_t·k_t(k_tᵀ Diag(α_t) S_{t−1}) + β_t·k_t v_tᵀ α_t = exp(−exp(A_log)·softplus(g_t + dt_bias)),下界 exp(−5)与 RWKV 的标量累积不同,delta 规则在写入前会先"擦掉旧键方向",因此同一键重复出现时是覆盖而不是叠加。
-
gated MLA ×2 :低秩 Q/KV + 输出门(门乘在
o_proj之前,这是 K3 的实现细节)。 -
Attention Residuals :每 4 层维护一个"块残差池",层输入由
softmax(RMSNorm(v)·w)对各历史块状态加权得到,输出端再做一次。 -
Stable Latent MoE :专家在 128 维潜空间工作,8 专家 top-2 + 1 个恒激活共享专家;路由用 sigmoid 打分 +
e_score_correction_bias(bias 只影响选择,不影响权重)。 -
SiTU-GLU :
β·tanh(x/β)·σ(x)软截断,抑制极端激活。
缩放映射:93 层 → 8 层(6 KDA + 2 MLA,保持 69:24 比例)、896 专家 → 8、top16 → top2、专家宽 3072 → 1056。
4.2 DeepSeek V4 mini
保留机制:
- 压缩 KV(Compressor) :每
ratio个 token 用学习到的门控softmax(wgate(x)+ape)做加权池化,再 RMSNorm + 部分 RoPE(位置取组起点g·ratio)。 - CSA / HCA 混合 :
ratio=4的层用 Indexer 为每个查询挑 top-64 个压缩位(score = Σ_h ReLU(q·k_g)·w_h,只允许看已完整结束的组);ratio=128的层直接看全部 64 个压缩位;ratio=0的层只有滑窗 128。 - mHC 超连接 :维护 4 条残差流,
hc_pre用 Sinkhorn 归一化后的权重把 4 流压成 1 流送进子层,hc_post按comb矩阵写回并做流间混合------把残差交换约束在双随机矩阵附近。 - MoE :
sqrt(softplus)打分、bias 只进选择、top-2 后 renormalize 再乘route_scale=1.5;前 3 层用 token→专家哈希表路由;专家是带swiglu_limit=10软截断的 SwiGLU;另有共享专家。 - 分组 O 投影 + per-head attn_sink。
缩放映射:43 层 → 8 层、256 专家 → 8、top6 → top2、head_dim 512 → 64、index_topk 512 → 64、o_lora 1024 → 128。
4.3 明确省略的项
为在单卡 30M 下保持可比,以下项未实现(它们对 30M / fp32 / 单卡训练无意义或有实现风险):
FP8/FP4 量化、Hadamard 旋转、MTP 多头预测、yarn 长度外推、分布式专家并行、K3 的 12 层大块 AttnRes(改为 4 层一块)、V4 的 compressor overlap(coff=2 简化为不重叠)、V4 的语料统计哈希表(用固定随机表代替)。
5. 实验结果
5.1 收敛曲线

| step | 100 | 200 | 300 | 400 | 500 | 600 |
|---|---|---|---|---|---|---|
| Ours | 3.1935 | 2.7562 | 2.5611 | 2.4399 | 2.3675 | 2.3360 |
| K3 mini | 3.2229 | 2.6875 | 2.4782 | 2.3812 | 2.3263 | 2.2851 |
| V4 mini | 3.2861 | 2.6961 | 2.5260 | 2.4294 | 2.3749 | 2.3258 |
三个阶段值得注意:
- step 100:三臂几乎重合(3.19 / 3.22 / 3.29),我们的起手最快。
- step 200--400:K3 反超并拉开,V4 也小幅领先,我们在这一段落后最多(step 300 差 0.083)。
- step 500--600:差距收窄(step 600 差 0.051),我们的曲线仍未明显趋于平台。

训练 loss 的平滑曲线显示三臂都稳定下降,没有出现 MoE 常见的路由坍塌或 loss 尖峰;K3 在中段下降更陡,与测试集一致。
5.2 显存与吞吐

| 指标 | Ours | K3 mini | V4 mini |
|---|---|---|---|
| 峰值显存 | 4155 MB | 4621 MB | 6959 MB |
| 单步耗时 | 114 ms | 1635 ms | 526 ms |
| 吞吐(token/s) | ≈ 71.9k | ≈ 5.0k | ≈ 15.6k |
| 相对我们 | 1.00× | 14.3× | 4.6× |
显存来源各不相同:
- Ours:KV 只在 1381 个检查点上(约 T/6),解压用窗口 256 分块,注意力侧显存很小;峰值由 4 层 FFN(宽 9600)的激活主导。
- K3:KDA 即便做了 chunk 并行(见 §6.1),仍需保存每 chunk 的状态与重计算;加上 8 层 MoE(top-2,专家宽 1056),峰值略高于我们。
- V4:4 条 mHC 残差流(4×T×d)+ 压缩注意力 + 8 层 MoE,显存最高;这也是我们实现时把查询分块到 256、滑窗按块取上下文的原因(否则 T=8192 会到 15.7GB)。
5.3 显存随上下文长度的变化
只测一次 T=8192 无法区分"常数开销大"与"随 T 增长快"。因此对每个臂在 T ∈ {512, 1024, 2048, 4096, 8192} 上各跑 2 步(B=1,含 Adam 状态),记录峰值显存:

| T | 512 | 1024 | 2048 | 4096 | 8192 | 线性斜率 |
|---|---|---|---|---|---|---|
| Ours | 647 MB | 857 MB | 1302 MB | 2217 MB | 4153 MB | 0.46 MB/token |
| K3 mini | 707 MB | 940 MB | 1473 MB | 2526 MB | 4584 MB | 0.51 MB/token |
| V4 mini | 787 MB | 1175 MB | 1953 MB | 3565 MB | 6948 MB | 0.80 MB/token |
四点观察:
- 三条曲线在我们的测量范围内都近似线性(斜率分别 0.46 / 0.51 / 0.80 MB/token)。这说明当前瓶颈都是"每 token 的激活显存"(FFN/MoE 中间层 + 残差流),而不是注意力矩阵本身。
- V4 的斜率是我们的 1.75 倍,主因是 mHC 维护 4 条残差流(把残差部分的激活放大 4 倍),以及 8 层 MoE 的 top-2 专家激活。
- K3 的斜率只比我们高 10% ,说明它的 KDA 状态与 chunk 重计算开销是 O(T) 的;它真正的成本在时间(单步 1.6 s),不在显存------因为 2 层全注意力虽然算力是 O(T²),但 SDPA 走的是不物化矩阵的核,显存仍是线性。
- 按此斜率 + 截距外推,8GB 边界上:我们约可到 T≈17k,K3 约 15k,V4 约 9.7k(实际还要扣掉显存碎片,会更低)。
5.4 消融:稀疏注意力这条通路到底贡献了什么
上面的三臂对比只说明"我们的架构整体表现如何",没有回答内部归因:RWKV 后面那 4 层检查点 MLA(以及解压)到底有没有用?为此做了一组消融。

5.4.1 第一版对照的问题
最初的做法是直接把深层通路删掉(deep_layers=0),得到 15.08M 的纯 RWKV 模型,测出 CE 2.3965(完整版 2.3360)。但这个对比有严重混淆:删掉注意力的同时把 4 个块(一半参数、一半深度)也删了,所以 +0.06 的差距可能只是"参数/深度变少",与稀疏注意力无关。
5.4.2 同参同深对照(关键实验)
把 4 个深层 MLA 块换成 4 个浅层 RWKV 块:总块数仍是 8、FFN 宽度仍是 9600、参数量 30.09M vs 30.20M(差 0.4%)。两者唯一的差别就是"后面 4 层是 RWKV 还是检查点 MLA + 解压"。3 个 seed:
| 臂 | 参数量 | seed0 | seed1 | seed2 | 均值 |
|---|---|---|---|---|---|
| RWKV×4 + 检查点 MLA×4 + 解压 | 30.20M | 2.3360 | 2.3315 | 2.3312 | 2.3329 ± 0.0027 |
| 全 RWKV×8(同参同深) | 30.09M | 2.3946 | 2.3955 | 2.3826 | 2.3909 ± 0.0072 |
差值 0.0580 ± 0.0044(SE)≈ 13σ ,而且全 RWKV 那臂的单步算力还更多(159 ms vs 115 ms),所以差距不是参数、不是深度、也不是算力。
5.4.3 排除"参数解释"
| 对照(同 seed 0,纯 RWKV) | 参数量 | Test CE |
|---|---|---|
| 4 层 | 15.08M | 2.3965 |
| 8 层 | 30.09M | 2.3946 |
把纯 RWKV 的参数翻倍只换来 0.0019(噪声级);而同样约 15M 的参数放到"检查点 MLA + 解压"通路上换来 0.058。这条内部对照基本排除了"主要是参数量在起作用"。
5.4.4 解压模块不可省
保留深层 MLA,但把"主干解压"换成"旁路写回"(深层输出只回写到被选中的 1/6 个位置):
| 臂 | 参数量 | Test CE |
|---|---|---|
| 完整(解压:每个位置都读回) | 30.20M | 2.3360 |
| 旁路写回(只有被选中位置拿到深层结果) | 30.12M | 2.4035 |
| 全 RWKV×8(无深层) | 30.09M | 2.3946 |
旁路版比"完全没有深层"还差 0.009。也就是说:深层算得再好,只要不把结果读回每个位置,收益就基本被浪费------这支持我们此前"深度覆盖 100%"的设计主张。
5.4.5 消融小结
- 稀疏注意力通路贡献 0.058 CE(同参同深、3 seed、13σ),且不是参数或算力带来的;
- 贡献的解压环节是必需的,缺了它整条通路会变成负收益;
- 上面只证明"有用","为什么有用"需要单独探针,见 §5.5。
5.5 关联回忆探针
本节替换上一版,旧结论作废。 上一版用的是仓库里
SyntheticDataset的aligned/copy任务,但事后检查发现两臂都没有学会:CE 停在"内容字母表的熵"上(3.39 ≈ ln29、1.61 ≈ ln5),也就是模型只是学到了边际分布、完全没用上 cue。基于未学会的任务谈"窗口内有效/窗口外失效"是无效结论,已删除。
5.5.1 为什么这次能学动
旧任务的症结是监督太稀:8192 个 token 里只有 4--16 个计分位,2500 步累计约 3 万个监督 token,不足以学会一个跨块取回任务。
新探针 DenseRecallDataset(MQAR 式)把监督密度提高 1--2 个数量级:
每个 episode: [k1][v1] [k2][v2] ... [kK][vK] ...gap 个 FILL... [MARK_Q][k_j] → 目标 = v_j
- 键值对顺序随机,位置不能作为捷径;每个样本含 14--95 个计分位;
K控制"同时要记多少条关联"(考容量/干扰),gap控制"定义到查询的距离"(考距离);- 判据:CE 必须显著低于"完全不看上文"的熵下界 ln K,否则判为"没学会"(训练脚本会直接打印"学动? 是/否",避免再次拿未学会的结果说事)。
5.5.2 难度阶梯(全部设置都学会了)
| 设置 | 熵下界 ln K | 完整版 | 全 RWKV×8 | 学会? |
|---|---|---|---|---|
| K=1,距离 64,T=8192 | 1.386 | 0.00068 | 0.00046 | 都学会 |
| K=32,距离 32,T=8192 | 3.466 | 0.00051 | 0.00055 | 都学会 |
| K=128,距离 32,T=8192 | 4.852 | 0.00086 | 0.00092 | 都学会 |
| K=256,距离 32,T=8192 | 5.545 | 0.00084 | 0.00076 | 都学会 |
| K=1,距离 512,T=2048 | 1.386 | 0.00026 | 0.00019 | 都学会 |
| 整段拷贝 4 token,距离 64 | 2.303 | 0.0944 | 1.7011 | 仅完整版 |

5.5.3 结论
- 唯一拉开差距的是"整段有序取回" :把"记一个 value"换成"按顺序复现 4 个 token",完整版 CE 0.094,全 RWKV×8 停在 1.70(下界 2.30,基本没学会),差距 1.61 CE 。单点多条关联两臂都能饱和,但一旦要求顺序与精确性,线性状态的叠加就失效------这是"稀疏注意力在做精确检索"的直接证据,也解释了代码语料上它为什么有用(标识符/括号/缩进都要求有序复原)。
- 撤回"窗口外失败" 。
gap=512超过up_window=256,两臂仍把 CE 压到 2e-4:查询只能直接读最近 256 token 的检查点,但这些检查点本身是在全部 1381 个检查点上算出来的,已把窗口外信息蒸馏进来(压缩摘要通道)。 - 单点查表不是收益来源。K 从 1 加到 256、距离到 512,两臂都饱和在 1e-3 以下、无法区分;收益集中在第 1 条那种"有序片段精确取回"上。
5.5.4 局限
- 关联回忆族的 5 个设置都饱和在 1e-3,属"探针不敏感";能力差异只在"整段有序拷贝"这种形态上显现,因此不能推广成"所有检索任务都强 1.6 CE"。
- 整段拷贝的目标区使用 teacher forcing(前 3 个目标 token 是真实值),与自回归推理略有差异。
- 单 seed;T=2048 的那一组与 T=8192 的几组不可直接比较。
- 只覆盖"键值关联 + 整段拷贝",未测全局聚合、排序、长程一致性。
5.5.5 四臂对比(整段拷贝,T=8192,距离 64)
把 K3 与 V4 也放进同一个探针(其余设定不变),得到:

| 臂 | CE@250 | CE@500 | CE@1000 | CE@2000 | 达标(CE<0.3)步数 | 单步耗时 | 达标墙钟 |
|---|---|---|---|---|---|---|---|
| Kimi K3 mini | 0.346 | 0.079 | ---(停表) | --- | ≈300 | 1547 ms | ≈7.7 min |
| DeepSeek V4 mini | 0.687 | 0.045 | 0.013 | ---(停表) | ≈430 | 514 ms | ≈3.7 min |
| Ours(RWKV+稀疏 MLA) | 2.309 | 2.309 | 2.263 | 0.157 | ≈1900 | 115 ms | ≈3.6 min |
| 全 RWKV×8(同参同深) | 2.308 | 2.305 | 2.304 | 1.874 | 未达标(2500 步仍 1.70) | 163 ms | ∞ |
两点结论,必须一起看:
- 样本效率:K3 ≈ V4 ≫ Ours ≫ 全 RWKV 。K3/V4 在 300--430 步就学会,我们要约 1900 步(4--6 倍),纯 RWKV 2500 步都没学会。也就是说"精确有序取回"这条能力上,我们只是明显好于纯 RWKV,但弱于两个真正的注意力模型。
- 墙钟效率:Ours ≈ V4 ≫ K3。K3 的步骤少但单步 1.5 s(T=8192 下的 KDA + 全注意力),达标要 7.7 分钟;我们用 1900 步 × 115 ms ≈ 3.6 分钟,和 V4 的 3.7 分钟基本持平。我们仍然靠"每步便宜"把样本效率的劣势补回来。
注:K3 / V4 的曲线是在 500 / 1000 步提前停表(单步太慢),但两者此时已收敛到 1e-2 量级,不影响"达标步数"的读取;Ours 与全 RWKV 为完整 2500 步。
6. 工程实现要点(可复现性)
6.1 纯 PyTorch 的 KDA
本机没有 fla / triton,官方 KDA 的 Triton 核无法使用。我们按同一数学定义实现了两版扫描:
-
串行参考版 (
_scan):逐 token 递推,语义精确但 8192 步 × 6 层 = 4.9 万次 Python 迭代,实测 43 秒/步。 -
chunk 并行版 (
_scan_chunked):把 delta 规则的乘积写成 WY(UT)表示。令G_t = Σ_{s≤t} log α_s,a_t = e^{−G_t}⊙k_t、b_t = e^{G_t}⊙k_t,则递推变为S_t = (I − β_t a_t b_tᵀ) S_{t−1} + β_t a_t v_tᵀ一个 chunk(C=128)内可闭式求出:
T = (I + tril(diag(β)·B Aᵀ, −1))^{−1} diag(β) # 下三角求解,O(C²) U = T V, W = T B o = Q̃ S₀ + Mq U − (Mq W) S₀ (Mq = causal(Q̃ Aᵀ)) S ← diag(e^{G_C}) S₀ + Āᵀ (U − W S₀)关键数值技巧:所有衰减只以
e^{G_i − G_j} (i ≥ j) ∈ (0,1]的形式出现,不会上溢;不需要显式构造a_t(它会指数爆炸)。
正确性校验 :在 B=1、T=300、H=2、Dh=8 的随机输入上,对 4 种衰减情形(无衰减、温和 −0.5、极端 −5、随机 −5,0)× 3 种 chunk 大小(8/32/128)逐一比对,最大相对误差 1.2e--6 ~ 4.5e--6,与串行版数学等价。速度从 43 s/步降到 1.6 s/步(含每 chunk 重计算的额外开销)。
6.2 防 OOM 措施
| 措施 | 位置 | 效果 |
|---|---|---|
| KDA 每 chunk 重计算 | _scan_chunked |
K3 峰值 15.0GB → 4.6GB |
| DSV4 查询分块 256 | DSV4Attention |
注意力矩阵 c×H×L 常数级 |
| 滑窗按块取上下文(而非逐查询 gather) | DSV4Attention |
15.7GB → 6.9GB |
| 压缩段与滑窗段分别乘 value | DSV4Attention |
再降 9.2GB → 6.9GB |
| Indexer 分 1024 查询一块 | Indexer |
打分矩阵 H×T×Tc 从 1GB 降到 33MB |
最终三臂在 T=8192 下峰值 4155 / 4621 / 6959 MB,全程无 OOM(8GB 安全线)。
6.3 复现命令
bash
cd d:\xiaothink\tnl_obj\tnl_torch
python k3_dsv4_compare.py params # 打印三臂参数量(用于对齐)
python k3_dsv4_compare.py smoke --T 8192 --steps 2 # 冒烟:查显存/OOM
python k3_dsv4_compare.py memscan # 显存随上下文长度扫描(512→8192)
python k3_dsv4_compare.py train # 全量三臂训练(结果写入 compare_results_k3dsv4/)
python k3_dsv4_compare.py train --arms ours,ours_rwkv8 --seed 1 # 消融 + 多 seed
python k3_dsv4_compare.py probe --task dense --pairs 256 --dist 32 --probe-vocab 516 \
--steps 2500 --arms ours,ours_rwkv8 # 稠密关联回忆探针
逐 step 的 loss、测试 CE、峰值显存、单步耗时都保存在 compare_results_k3dsv4/{ours,k3,dsv4}.json。
7. 分析与讨论
7.1 这个差距意味着什么
统计上 :我们此前在相同协议、3 个 seed 下测得本模型的测试 CE 为 2.3749 ± 0.0089(seed 间标准差)。本次单 seed 得到 2.3360,比历史均值低 0.039 ------ 也就是说换 seed 带来的跑动差异可达 ±0.04 量级(数据顺序与初始化都变)。据此:
- K3 的 −0.0509 约为观察到的跑动波动的 1.3 倍,方向可信、幅度存疑,需要用 3 seed 复核;
- V4 的 −0.0102 远小于跑动波动,应视为与打平。
这一点很关键:600 步是架构筛选预算,不是收敛预算,单 seed 的排序不足以支撑"某个架构更好 2%"的强结论。
机制上:K3 的优势出现在训练中段(step 200--400),这与其两种"精确回忆"能力吻合:KDA 的 delta 规则能覆盖旧键(而 RWKV 的标量累积只会叠加),gated MLA 层又提供了 2 层全序列精确注意力。在字符级代码语料上,"精确记住前文的标识符/括号配对"正是关键能力,这与我们此前"线性状态擅长压缩、不擅长精确检索"的判断一致。
我们为什么没被拉开更多:检查点 MLA + 解压事实上给了我们"每 6 个 token 一个精确检索槽 + 全位置可读",代价是 O(T²/36) 而不是 O(T²);而 K3 的 2 层全注意力是 O(T²)(8 层中 2 层),它的质量优势有一部分被算力成本抵消------单步 14.3 倍的差距主要来自这里。
7.2 关于"同参数量"的公平性
需要强调:三臂参数相同,但单步算力并不相同。T=8192 时:
- Ours:注意力侧 O(T·2W/6 + (T/6)²);
- K3:6 层 O(T) 线性 + 2 层 O(T²) 全注意力;
- V4:8 层 O(T·(128 + 64)) 的窗口 + 压缩注意力。
所以更准确的说法是:在相同参数预算下,K3 用更多算力换到了更好的质量;我们在相同参数下把每一步压到了 1/14 的成本。若改用等算力协议(让 K3 少跑步数、我们多跑),排序有可能变化------这需要单独一轮实验。
7.3 下一步可以做的
- 等算力复测 :用 wall-clock 预算对齐(
equal_compute),检验"我们多跑的步数能否补上 0.05 CE"。 - K3/V4 也补 3 seed:目前只有我们自己这一臂做了 3 seed,跨臂结论仍受单 seed 波动(±0.04)限制。
- 把探针压到容量边界:现有 MQAR 探针在 K=256 就饱和了,需要 K≥512 并保持监督密度(T 固定时密度 ≈ T/2K,K=512 只剩 ~8 个计分位/步,得配更大 batch 或更多步数),才能找到线性状态的容量拐点。
- 窗口消融 :
up_window取 256 / 1024 / 4096,检验"窗口大小 ↔ 可取回距离 ↔ 代码 CE"这条链。注意本报告 §5.5 已表明窗口外(512)仍可借深层摘要取回,所以窗口更可能影响的是"多层复合任务的成本",而不是单条关联的可达性。 - 长序列外推:T=16384/32768 下看三种压缩策略的显存与质量曲线,我们对 KDA 的 chunk 化实现已支持任意 T。
8. 结论
- 在 30.2M 参数、T=8192、600 步的同协议下:K3 mini 2.2851 < V4 mini 2.3258 ≈ Ours 2.3360。
- K3 的质量领先 0.051(2.2%)接近可辨识阈值但仍需多 seed 复核;其代价是单步 14.3×、显存 1.11×。V4 与我们统计上打平,单步成本 4.6×、显存 1.67×。
- 内部归因 (§5.4):RWKV 后面的"检查点 MLA + 解压"通路在同参同深 、3 seed 下贡献 0.058 CE(13σ);把纯 RWKV 参数翻倍只值 0.002,所以这不是参数效应;把解压换成旁路写回反而比没有深层更差(2.4035 vs 2.3946),说明"深度覆盖 100%"是这条通路生效的前提。
- 机制证据 (§5.5):稠密探针的 6 个设置全部确认学会。单点多条关联 (K=1...256、距离 64...512)两臂都饱和在 1e-3、无差异;但整段有序拷贝 (4 个 token、距离 64)完整版 0.094 vs 全 RWKV 1.70(下界 2.30),差 1.61 CE 。四臂同探针(§5.5.5):样本效率 K3 ≈ V4 ≫ Ours ≫ 全 RWKV ,墙钟效率 Ours ≈ V4 ≫ K3。因此我们的定位是"比纯线性状态强得多的检索能力 + 最低的单步成本",而不是"检索质量最好"。副产品:距离 512 超过 256 的解压窗口时两臂仍满分,说明深层检查点在充当"压缩摘要",这推翻了旧版"窗口外失效"的说法。
- 我们的架构在"参数-显存-吞吐"三角上是最省的一档,质量差距集中在训练中前期,且可通过增加步数或引入一层精确检索来收敛。
- 两个对照臂均以官方建模代码为蓝本做机制保真缩放,实现与校验过程(尤其纯 PyTorch 的 chunk 化 KDA,与串行定义误差 ~1e-6)可作为后续复用的基础设施。