File size: 17,901 Bytes
2acbf5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# Traj-MC vs SVD-LLM — 主实验 (trajmc_main)

本目录自包含。从零实现 Traj-MC (ours) vs SVD-LLM (baseline) 主实验,
不复用本仓库其它代码/结果(仅作实现参考)。所有产物写入 `results/` 下对应子目录。

---

## 0. 冲突裁决原则(后续所有设置分歧按此处理)

当 **SVD-LLM (ICLR 2025)** 与 **LLaDA 官方 / Sink-Aware** 的实验设置不一致时,
**一律按 LLaDA 官方那条线走。**

理由:我们压缩和评测的对象是 LLaDA,用的是 LLaDA 生态的评测栈
(`eval_llada.py` / lm-eval dLLM 适配),对照表是 Sink-Aware(模型 GSAI-ML/LLaDA-8B-Base)。
SVD-LLM 是 AR 模型(LLaMA/OPT/Mistral)上的工作,其评测惯例不适用于 dLLM 评测栈。

**SVD-LLM 只在【压缩算法本身】上作为权威**:白化数学、rank 公式、full SVD、
Cholesky 及其 except 分支、校准数据的角色。**评测协议一律以 LLaDA 官方为准。**

**目标模型 = LLaDA-8B-Base**(推翻早先的 Instruct 倾向)。依据官方 `EVAL.md`:
Base 有 ppl(条件似然)评测协议,Instruct 只有 gen(条件生成)、且需逐任务不同的
gen 参数——ARC-C 在 Base(ppl)是 47.9、在 Instruct(gen)是 88.5,是两种不同问法,
不可比。用 Base 才能与 Sink-Aware 同模型同协议、REF 行直接对表。
通用性证据留给 **Dream-7B / LLaDA-1.5**(跨架构家族),不用 Instruct,本轮暂不发。

**评测引擎 = 官方 lm-eval harness**(`eval/llada_harness.py`,vendored 自官方
`eval_llada.py` + 兼容我们 A/B 权重的注入),跑真·lm-eval,逐任务 fewshot/cfg/mc_num、
acc/acc_norm、fewshot 采样、gsm8k 提取全部由权威 harness 处理,零重实现风险。

---

## 0b. 三个对象(全程只有这三个,命名固定,不得混用)

| 名称 | 定义 | 作用 |
|---|---|---|
| **Dense** | 未压缩的原始 LLaDA。不做任何压缩。 | 上界参照线(压缩前分数)。与 SVD 无关。 |
| **BASE** | SVD-LLM 照官方代码原样应用于 LLaDA:t=0 干净文本校准,一次前向收激活,whitening + 截断。已发表方法直接套用,是我们的对手。称 **"SVD-LLM (t=0)"**。 | baseline。 |
| **OURS** | Traj-MC:t~U[0,1] 加噪校准,一次前向收激活,其余与 BASE **完全相同**。称 **"Traj-MC (ours)"**。 | 我们的方法。 |

主表三行:**Dense | BASE | OURS**。
BASE 与 OURS 是【单变量对比】:唯一差异 = 校准输入是否加噪。
⛔ 不存在第四个对象。不引入"稠密轨迹收集/每步收集/dense 压缩臂"——不在本实验范围内。

---

## 1. 命题与双 claim(一字不改)

**【Gap】** SVD-LLM 的 truncation-aware whitening 隐含假设"校准分布 = 推理
分布"。对自回归模型天然成立(推理永远是干净文本,一次前向)。对 LLaDA
不成立:推理是 T 步去噪,输入含大量 MASK,激活分布随步漂移。照官方代码
原样套用(BASE),校准落在一个模型推理时从不经历的干净分布上。

**【方法立论】** t~U[0,1] 的全序列均匀打码,正是 LLaDA 的前向扩散过程,
因此单次采样的校准分布即覆盖模型去噪轨迹上的输入分布,且 X^T X 是轨迹
协方差的无偏估计。Traj-MC 只改校准输入的加噪方式,不改 objective、
白化数学、截断与管线。
⛔ 不写"prompt 可见 / prefix 保护"——本实验用连续 2048 窗口,
没有 prompt/answer 之分,那套表述与窗口构造矛盾。

**【Claim 1 · performance】** 完全相同管线下单变量对比,OURS 下游表现优于 BASE。

**【Claim 2 · efficiency】** OURS 与 BASE 校准成本相同(均 O(N) 一次前向、
内存 O(d²)/层),但 OURS 的校准分布覆盖去噪轨迹而 BASE 不覆盖——
即"零额外成本换取轨迹覆盖"。
要覆盖轨迹的朴素替代做法是每个去噪步都收集激活(O(T·N) 前向),
本实验用它作为【论证性对照】说明成本差距,不实现为实验臂。
⛔ 措辞红线:不得笼统写"比 SVD-LLM 快"——BASE 与 OURS 同为 O(N)。
正确表述:与 BASE 同等成本、额外获得轨迹覆盖;朴素的每步收集才是
O(T·N) 的那个,我们相对它是 O(1)。

---

## 8. 统计与判读(预注册,出数后一字不改)

- **BASE vs OURS 用 McNemar 配对检验**(b=BASE错OURS对,c=BASE对OURS错,
  χ²=(b−c)²/(b+c)),报 raw acc +(b,c)+ 配对 p。⛔ 禁止非配对 z。
  实现对 scipy 校验。
- **7 个 benchmark 同时检验用 Holm-Bonferroni 校正**,报校正前后 p
  (m=7 时族系错误率约 30%,故需校正)。
- **判读**(每个 benchmark 一视同仁,不预测方向):
  - 显著 = Holm 校正后 p<0.05;
  - 多数 benchmark 同向且 ≥2 个校正后显著 → **claim 1 成立**;
  - 方向分裂或仅 1 个显著 → 报混合结果,不夸大;
  - OURS 在某些 benchmark 上显著更差 → 如实报 limitation。
- ⛔ **地板规则**:任一臂在某 benchmark 低于 REF 的 15% → 该格作废不解读。
- **"显著但差距很小"** → BASE/OURS 同加 2 个校准 seed 复核,不得事后改判据。

输出到 `results/stats/`。

---

## Related work / limitation:SVD-LLM 的"校准数据不敏感"消融

⚠️ **这是 claim 1 最可能被攻击的点,必须正面回应。**

SVD-LLM 原文做过校准数据消融:改变校准**数量**、**随机 seed**、**来源数据集**
(WikiText-2 / C4 / PTB 等),下游性能变化 **<3%**,据此得出"whitening 对校准数据
不敏感"的结论。若不加区分,这条消融会被直接用来反驳我们:"既然校准数据不敏感,
你换个加噪方式凭什么会有差别?"

**我们的论证:mask 维度与"换文本数据集"是性质不同的分布变化。**

1. **他们变的是同一族内的采样。** 数量/seed/来源数据集三者都是从**同一个分布族**
   —— 干净自然文本 —— 里重新采样。无论 WikiText-2 还是 C4,输入永远是
   **完全可观测的干净 token 序列**,MASK 占比恒为 0。换语料只是重新加权了
   主题与文体,X^T X 的**精细结构**变了,**支撑集与谱型没变**。<3% 正是
   "在干净文本族内部不敏感"的正确读数。

2. **我们变的是前向扩散的坐标 t,不是另一份干净文本。** 在噪声水平 t 下,
   有 t 比例的位置被替换成**同一个** id(MASK_ID=126336)。这是范畴上不同的干预:
   - **token 边缘分布出现质点**:权重为 t 的点质量压在单一 token 上。任何
     换语料都造不出这种分布。
   - **二阶矩变成 t-混合**:X^T X(t) ≈ (1−t)·Σ_clean + t·Σ_mask + 交叉项。
     t→1 时输入趋近常量嵌入序列,协方差朝 MASK 嵌入方向**秩塌缩**。
     干净语料之间的互换永远进不了这个区域。
   - **白化矩阵就是这个二阶矩**。所以截断子空间是沿一条**以 t 为参数的单参数族**
     移动,而不是在同族样本云里抖动。

3. **他们的消融回答的是"哪份干净语料",不是"校准分布是否等于推理分布"。**
   对 AR 模型这两件事重合(推理永远是干净文本、一次前向),所以"换语料不敏感"
   ⇒"校准问题已解决"。对扩散语言模型两者**分离**:推理沿 t 从 1 走到 0,
   而干净文本校准(t=0)是模型在推理轨迹上**几乎不停留**的一个端点。

4. **可证伪 + 建议加做的对照。** 如果 mask 维度真的只是又一个良性扰动,
   那 BASE vs OURS 也应当 <3% 且统计不显著 —— claim 1 正是对此的直接检验。
   **建议补一个廉价对照**:比较
   ① 干净族内部(BASE seed1 vs BASE seed2)的截断子空间主夹角
   ② 跨 mask 轴(BASE vs OURS)的主夹角(`analysis/subspace_angle.py`)。
   若 ② ≫ ①,则从**几何上**直接证明他们的消融没有覆盖我们这条轴。
   (需额外一份 BASE 换 seed 的压缩产物,成本 = 1 个压缩 job。)

5. **诚实的 limitation。** 若实测 BASE vs OURS 差距同样 <3% 且 Holm 校正后不显著,
   则说明 SVD-LLM 的不敏感结论**外推到了 mask 轴**,claim 1 不成立 ——
   按第 8 节如实报告,不做事后改判据。

**附带好处**:因为他们自证"校准语料/数量不敏感(<3%)",我们用 C4-256 而非官方
WikiText2-256 这一偏离(**样本数已与官方一致,仅换语料**),**对 BASE 不构成削弱** ——
按他们自己的结论,这个差异是无关紧要的,故 BASE 仍是忠实、非稻草人的 baseline
(见 `docs/svdllm_port_diff.md`)。

---

## 评测集合(全部 benchmark 平权,不设主副,不预测方向)

⛔ 不得出现"主判据/副判据/预期持平/预期更好"。

**评测协议 = 官方 LLaDA-8B-Base lm-eval 设置**(逐字节核验自
`scripts/eval_llada_lm_eval.sh`,与 Sink-Aware `eval_llada.sh` 完全相同)。
**逐任务不同参数**(不是一刀切)。single source of truth = `common.LMEVAL_TASKS`:

| benchmark | lm-eval task | num_fewshot | cfg | mc_num | 打分方式 | **主指标(预注册)** | 官方 EVAL.md Dense |
|---|---|---|---|---|---|---|---|
| ARC-C | arc_challenge | 0 | 0.5 | 128 | 条件似然 | **acc** | 47.9 |
| ARC-E | arc_easy | 0 | 0.5 | 128 | 条件似然 | **acc** | — |
| PIQA | piqa | 0 | 0.5 | 128 | 条件似然 | **acc_norm** | 74.4 |
| HellaSwag | hellaswag | 0 | 0.5 | 128 | 条件似然 | **acc_norm** | 72.5 |
| WinoGrande | winogrande | **5** | **0.0** | 128 | 条件似然 | **acc** | 74.8 |
| MMLU | mmlu | **5** | **0.0** | **1** | 条件似然 | **acc** | 65.9 (w/o CFG) |
| GSM8K | gsm8k | 5 | — | — | 生成 gen=256/steps=256/**block=256**(全扩散) | **exact_match** | 70.0 |

固定:`is_check_greedy=False`。⛔ GSM8K 是 **block_length=gen_length 全扩散**,
**不是** Instruct 的 block=8 半自回归 block diffusion。

### 主指标预注册(三臂统一,出数后一字不改)

已核实:SVD-LLM 全用 acc、且只用 ARC-E 不用 ARC-C,但按第 0 节裁决**跟 LLaDA**。
LLaDA 官方 EVAL.md 逐任务用 acc 或 acc_norm(见上表),与我们体检实测吻合
(ARC-C acc 46.2≈47.9;HellaSwag acc_norm 70.0≈72.5;PIQA acc_norm 74.2≈74.4)。

⚠️ acc 与 acc_norm 判对的是**不同的题**,McNemar 是逐题配对检验 ——
**主指标压缩前钉死,不得事后择优**。acc/acc_norm 两列都逐项落盘供附录,
但**配对检验只跑上表的主指标列**(`analysis/lmeval_to_items.py` 按 `common.primary_metric` 提取)。
⛔ **不再使用**"MMLU 单 token mc_num=1 精确"论证与 assert(改用官方 mmlu 5-shot/cfg=0/mc_num=1)。

### 全量评测(取消一切子采样)

**主表 = 7 个 benchmark**(HellaSwag 于 2026-07-24 并入主表)。全部跑全量:
GSM8K 1319 / ARC-C 1172 / ARC-E 2376 / PIQA 1838 / WinoGrande 1267 /
MMLU **14042** / HellaSwag ~10042(不再 2000 子集)。理由:主表是自比
(BASE vs OURS 同流水线),外部对表只是 sanity;全量把抽样误差压到最低,
且避免"子集选择"成为新自由度。GSM8K 用 harness 内置 accelerate 数据并行
(单 job/单 seed/单 git-hash,gather 原子一致)。

### 生成域普适性任务(预注册 2026-07-29,出数后不改)

**动机**:主表 6/7 显示 OURS 的优势集中在**生成任务 GSM8K**(+9.0, p=2.8e-14),
判别式任务中性偏负。为检验"GSM8K 的胜利是**高-mask 生成任务的共性**、而非单数据集
偶然",追加 4 个生成域任务:**SVAMP / MATH-500 / HumanEval / MBPP**。

**预注册规则(先写死,出数后一字不改)**:
- 全部 **三臂 REF/BASE/OURS**、全部 **per-item + McNemar 配对**;Holm 的族大小 **m 相应增大**
  到含全部纳入的新任务。
- ⛔ **无论输赢,纳入的任务全部进最终表,不允许只报赢的**。
- **地板规则照旧**:任一臂 < 0.15×REF → 该格标注**作废**(理由=地板,与结果方向无关)。
- **打分器**:新任务一律接入主流水线(`common.LMEVAL_TASKS` + `eval/llada_harness.py`),
  与主表同一套;**不用旧 `eval_benchmarks.py`**。生成配置三臂一致、对齐 GSM8K 的
  Base 全扩散(block_length=gen_length)。

**执行顺序(按坑大小,不并发)**:
1. **SVAMP**(`eval/lm_tasks/svamp.yaml`,自定义 lm-eval task):与 GSM8K 同类,复用其
   数字抽取(flexible-extract)。协议 `fs=5, gen_length=256/steps=256/block_length=256,
   exact_match`。冒烟已过(ref 4/4)。→ 直接三臂全量(test 300)。
2. **MATH-500**(`eval/lm_tasks/math500.yaml`,复用 minerva_math 的 boxed 抽取 + `is_equiv`):
   协议 `fs=4, gen_length=512/steps=512/block_length=512, exact_match`。
   ⚠️ **先只跑 REF(dense)一个数**:若 **REF < ~20 分 → 整个任务不纳入**(Base 竞赛数学
   固有局限,此决定在看到 BASE/OURS 前做出,非选择性排除)。REF 够高才跑三臂。
3. **HumanEval / MBPP**(代码生成,lm-eval 现成 `humaneval.yaml`/`mbpp.yaml`,**pass@1
   实测执行** = 生成代码跑测试 assert;需 `HF_ALLOW_CODE_EVAL=1` + `--confirm_run_unsafe_code`)。
   ⛔ **不做代码指令微调**:前提是 LLaDA-8B-Base 未微调,一旦微调整个主表+对照全部作废;
   且比的是 OURS−BASE 相对差,模型绝对代码水平不影响 claim。
   ⚠️ **同 MATH-500 的 REF 前置门槛**(决定在看 BASE/OURS 前做,理由=REF 水平非结果方向):
   先只跑 **REF 全量(HumanEval 164 / MBPP 500)**;**REF pass@1 ≥ 20% → 发三臂**;
   **< 20%(接近地板)→ 标注"REF 过低不纳入"**(压后 BASE/OURS 大概率双双触地板、无解读空间)。
   20–25% 灰区按 REF 数当场判,仍在看 BASE/OURS 前。冒烟已过(8 题验证判分正确,但方差太大不作数)。

### Dense sanity check(压缩评测的前置闸门)

REF 用官方 harness 全量跑,与**官方 EVAL.md**(内部自洽)对表(见上表末列)。
⚠️ **不再用 Sink-Aware Dense 行**:其 MMLU 65.97(需 5-shot)与 WinoGrande
69.30(只能 0-shot)在单一协议下互不自洽;按第 0 节裁决以 LLaDA 官方为准。

### MMLU 5pp 归因记录(不改协议)

体检 0-shot/cfg=0.5/mc_num=128 得 MMLU 61.0,官方 5-shot/cfg=0/mc_num=1 是 65.9。
Δ 是**问法不同**,非 pipeline bug:官方 MMLU/WinoGrande 都是 **5-shot**;0-shot 低于
5-shot 属预期(WinoGrande 官方 5-shot 74.8 vs 我们 0-shot 69.0 同此规律)。
→ **不为追平修改协议**,改用官方 per-task 设置后 REF 应自然接近 65.9。

**REF 对不上官方 → 先查 pipeline,不往下跑任何压缩评测。**

---

## 工作点与对象

- **唯一主工作点 = all-linear r=0.7**。主表 = BASE vs OURS @ all-linear r=0.7(单工作点)。
  attn-only r=0.8 的两个压缩产物 **parked(保留权重,不做任何评测)**——r=0.8 压缩幅度不够,
  不作为工作点;日后若要压缩率趋势再另议。
- **`ratio` 语义(钉死,防历史歧义)**:`k = int(ratio·d_out·d_in/(d_out+d_in))`,
  故 compressed ≈ `ratio·d_out·d_in` = `ratio × 原始参数量`。即 **`ratio` = 参数保留比例**:
  `r=0.7` 保留约 70% 参数(压掉约 30%)。实测:q_proj kept=0.6997、ff kept=0.700。
  `compression_summary.json` **同时落实测 `kept_fraction = compressed/orig`**——以实测比值为准,
  不以 `ratio` 符号为准。summary diff 门禁核对 BASE/OURS 的 `kept_fraction` 与逐层 rank 一致。
- **评测协议差异备注(本轮不处理)**:我们 REF 已对齐 LLaDA 官方 EVAL.md 逐任务协议
  (arc/piqa/hella 0-shot、winogrande/mmlu 5-shot、cfg 逐任务),与 Sink-Aware 论文表格所用的
  统一 0-shot 不同。这只影响"能否直接引用 Sink-Aware 表格数字",**不影响主 claim**
  (BASE vs OURS 同流水线自比)。是否补跑统一 0-shot 对表协议,等主实验结果出来后再定。
- 压缩范围:`model.model.transformer.blocks` 内全部目标 Linear(32 blocks × 7 = **224 层**);
  `lm_head` 保持 dense(加载器硬防线)。
- MASK_ID = 126336;nsamples = 256;连续 2048 token 窗口。

---

## 目录

```
trajmc_main/
├── README.md                  ← 本文件(命题 + 判读规则)
├── docs/svdllm_port_diff.md    ← 忠实移植差异表(进论文附录)
├── docs/JOBS.md                ← job 台账(每提交一个 job 追加一行)
├── common.py                   ← 共享工具(模型加载/层遍历/hash/rank 公式)
├── calib/build_calib.py        ← 唯一允许 BASE/OURS 有差异的模块(加噪开关)
├── compress/compress.py        ← 共享压缩管线(增量 XtX + Cholesky 白化)
├── compress/official_collect.py← 官方结构收集路径(仅内存实测用,不产权重)
├── eval/eval.py                ← 共享评测 + per-item 落盘
├── analysis/{mcnemar,holm,merge_shards,subspace_angle}.py
├── jobs/                       ← sbatch 脚本
├── weights/{ref,base,ours}/
└── results/{calib,compress,eval/{ref,base,ours},efficiency,stats}/
```

⚠️ 所有产物一律写入 `results/` 下对应子目录,不散落到代码目录或 home。
每个结果文件名带 job id 与 git hash 前缀,便于追溯。

---

## 执行顺序(第 9 节,③ 后必须停下等确认)

① 归档旧目录 + 建目录 + 本 README + port_diff + JOBS ·
② 写全部代码 + 全部自检 ·
③ BASE/OURS dry_run 自检 → **停下等确认** ·
④ 4 个压缩 job → summary diff ·
⑤ 官方结构内存实测 ·
⑥ 评测 Dense+BASE+OURS ·
⑦ mcnemar+holm 出表 ·
⑧ 视结果定 CoT 1:1 消融范围。