GOVINDFROM commited on
Commit
55003bd
·
verified ·
1 Parent(s): dbbc6f9

Automated push from Zaratan

Browse files
README.md CHANGED
@@ -52,8 +52,11 @@ Answers are unique but only ~10 characters with shallow, local dependencies. One
52
  | georgian | 93.9 | 93.9 | +0.0 |
53
  | german | 78.9 | 79.3 | +0.4 |
54
  | german | 75.6 | 79.5 | +3.9 |
 
55
  | german | 78.9 | 79.3 | +0.4 |
56
  | german | 77.9 | 78.0 | +0.1 |
 
 
57
  | german | 75.6 | 79.5 | +3.9 |
58
  | german | 76.4 | 78.9 | +2.5 |
59
  | german | 77.2 | 78.3 | +1.0 |
@@ -106,10 +109,11 @@ Every apparent failure at 10+ digits was a learning-rate artifact, not a limit o
106
 
107
  The account in THEORY.md predicts minimum depth growing as log2(n), since the carry is a prefix scan. A ripple-carry account predicts linear growth; an impossibility account predicts no depth suffices.
108
 
109
- | digits | 2L | 3L | 4L | 6L | 8L | log2(n) | min depth >90% |
110
- |---|---|---|---|---|---|---|---|
111
- | **4** | 100 | 100 | 100 | 100 | 100 | 2.0 | 2 |
112
- | **8** | 99 | 100 | – | – | – | 3.0 | 2 |
 
113
 
114
  ## Table 7 — Which component carries the gain (inflection)
115
 
@@ -117,9 +121,20 @@ The account in THEORY.md predicts minimum depth growing as log2(n), since the ca
117
  |---|---|---|---|---|---|
118
  | finnish | 51.4 | – | – | 51.9 | +7.7 / – / – / +4.9 |
119
  | georgian | 94.6 | – | – | 94.1 | -0.0 / – / – / -0.0 |
120
- | german | 76.0 | – | – | 78.4 | +3.2 / – / – / +0.2 |
121
  | navajo | 28.0 | – | – | 26.9 | +8.0 / – / – / +4.5 |
122
  | russian | 71.6 | – | – | 72.3 | +2.2 / – / – / -0.3 |
123
  | turkish | 78.7 | – | – | 82.3 | +3.5 / – / – / +0.8 |
124
 
 
 
 
 
 
 
 
 
 
 
 
125
 
 
52
  | georgian | 93.9 | 93.9 | +0.0 |
53
  | german | 78.9 | 79.3 | +0.4 |
54
  | german | 75.6 | 79.5 | +3.9 |
55
+ | german | 78.6 | 78.9 | +0.3 |
56
  | german | 78.9 | 79.3 | +0.4 |
57
  | german | 77.9 | 78.0 | +0.1 |
58
+ | german | 79.4 | 81.0 | +1.7 |
59
+ | german | 76.5 | 77.6 | +1.0 |
60
  | german | 75.6 | 79.5 | +3.9 |
61
  | german | 76.4 | 78.9 | +2.5 |
62
  | german | 77.2 | 78.3 | +1.0 |
 
109
 
110
  The account in THEORY.md predicts minimum depth growing as log2(n), since the carry is a prefix scan. A ripple-carry account predicts linear growth; an impossibility account predicts no depth suffices.
111
 
112
+ | digits | 2L | 3L | 4L | 6L | 8L | 12L | log2(n) | min depth >90% |
113
+ |---|---|---|---|---|---|---|---|---|
114
+ | **4** | 100 | 100 | 100 | 100 | 100 | 100 | 2.0 | 2 |
115
+ | **8** | 99 | 100 | 100 | 100 | 100 | – | 3.0 | 2 |
116
+ | **12** | 48 | 100 | 100 | – | – | – | 3.6 | 3 |
117
 
118
  ## Table 7 — Which component carries the gain (inflection)
119
 
 
121
  |---|---|---|---|---|---|
122
  | finnish | 51.4 | – | – | 51.9 | +7.7 / – / – / +4.9 |
123
  | georgian | 94.6 | – | – | 94.1 | -0.0 / – / – / -0.0 |
124
+ | german | 76.0 | 77.9 | 78.6 | 78.4 | +3.2 / +1.4 / +0.3 / +0.2 |
125
  | navajo | 28.0 | – | – | 26.9 | +8.0 / – / – / +4.5 |
126
  | russian | 71.6 | – | – | 72.3 | +2.2 / – / – / -0.3 |
127
  | turkish | 78.7 | – | – | 82.3 | +3.5 / – / – / +0.8 |
128
 
129
+ ## Table 9 — Did the baseline fail to parallelise, or fail to learn?
130
+
131
+ A 20-digit answer occupies 21 slots, so the standard 16-pass grid is not a sequential decode. Re-decoded at one token per pass, the two explanations separate.
132
+
133
+ | digits | mode | @1 pass | fully sequential | reading |
134
+ |---|---|---|---|---|
135
+ | 20 | full | 99.8 | 85.7 | learned it and parallelises |
136
+ | 20 | mdlm | 0.0 | 0.0 | never learned the task |
137
+ | 24 | full | 33.7 | 33.3 | learned it and parallelises |
138
+ | 24 | mdlm | 0.0 | 0.0 | never learned the task |
139
+
140
 
figures/beat_d12.json CHANGED
@@ -4,37 +4,37 @@
4
  "confidence": [
5
  0.766875,
6
  0.764375,
7
- 0.7637499999999999,
8
  0.763125,
9
  0.7625
10
  ],
11
  "entropy": [
12
  0.766875,
13
  0.764375,
14
- 0.7637499999999999,
15
  0.763125,
16
  0.7625
17
  ],
18
  "entropy-gated": [
19
  0.766875,
20
  0.764375,
21
- 0.7637499999999999,
22
- 0.7618750000000001,
23
  0.7625
24
  ],
25
  "margin": [
26
  0.766875,
27
  0.764375,
28
- 0.7637499999999999,
29
  0.763125,
30
- 0.7618750000000001
31
  ],
32
  "random": [
33
  0.766875,
34
- 0.771875,
35
- 0.76875,
36
- 0.7675000000000001,
37
- 0.7637499999999999
38
  ]
39
  },
40
  "ours": {
@@ -46,9 +46,10 @@
46
  0.999375
47
  ]
48
  },
 
49
  "summary": {
50
  "best_inference_1pass": 0.766875,
51
- "best_inference_any_budget": 0.771875,
52
  "ours_1pass": 1.0
53
  }
54
  }
 
4
  "confidence": [
5
  0.766875,
6
  0.764375,
7
+ 0.76375,
8
  0.763125,
9
  0.7625
10
  ],
11
  "entropy": [
12
  0.766875,
13
  0.764375,
14
+ 0.76375,
15
  0.763125,
16
  0.7625
17
  ],
18
  "entropy-gated": [
19
  0.766875,
20
  0.764375,
21
+ 0.76375,
22
+ 0.761875,
23
  0.7625
24
  ],
25
  "margin": [
26
  0.766875,
27
  0.764375,
28
+ 0.76375,
29
  0.763125,
30
+ 0.761875
31
  ],
32
  "random": [
33
  0.766875,
34
+ 0.764375,
35
+ 0.768125,
36
+ 0.770625,
37
+ 0.76625
38
  ]
39
  },
40
  "ours": {
 
46
  0.999375
47
  ]
48
  },
49
+ "significance": {},
50
  "summary": {
51
  "best_inference_1pass": 0.766875,
52
+ "best_inference_any_budget": 0.770625,
53
  "ours_1pass": 1.0
54
  }
55
  }
figures/beat_d16.json CHANGED
@@ -46,6 +46,7 @@
46
  0.749375
47
  ]
48
  },
 
49
  "summary": {
50
  "best_inference_1pass": 0.25,
51
  "best_inference_any_budget": 0.25,
 
46
  0.749375
47
  ]
48
  },
49
+ "significance": {},
50
  "summary": {
51
  "best_inference_1pass": 0.25,
52
  "best_inference_any_budget": 0.25,
figures/fig3_depth_scaling.png CHANGED
figures/seq_check_g13.json ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "run": "g13-d20-full-s0",
4
+ "digits": 20,
5
+ "mode": "full",
6
+ "seed": 0,
7
+ "slots": 20,
8
+ "acc_1pass": 1.0,
9
+ "acc_sequential": 1.0
10
+ },
11
+ {
12
+ "run": "g13-d20-full-s1",
13
+ "digits": 20,
14
+ "mode": "full",
15
+ "seed": 1,
16
+ "slots": 20,
17
+ "acc_1pass": 0.995,
18
+ "acc_sequential": 0.5700000000000001
19
+ },
20
+ {
21
+ "run": "g13-d20-full-s2",
22
+ "digits": 20,
23
+ "mode": "full",
24
+ "seed": 2,
25
+ "slots": 20,
26
+ "acc_1pass": 1.0,
27
+ "acc_sequential": 1.0
28
+ },
29
+ {
30
+ "run": "g13-d20-mdlm-s0",
31
+ "digits": 20,
32
+ "mode": "mdlm",
33
+ "seed": 0,
34
+ "slots": 20,
35
+ "acc_1pass": 0.0,
36
+ "acc_sequential": 0.0
37
+ },
38
+ {
39
+ "run": "g13-d20-mdlm-s1",
40
+ "digits": 20,
41
+ "mode": "mdlm",
42
+ "seed": 1,
43
+ "slots": 20,
44
+ "acc_1pass": 0.0,
45
+ "acc_sequential": 0.0
46
+ },
47
+ {
48
+ "run": "g13-d20-mdlm-s2",
49
+ "digits": 20,
50
+ "mode": "mdlm",
51
+ "seed": 2,
52
+ "slots": 20,
53
+ "acc_1pass": 0.0,
54
+ "acc_sequential": 0.0
55
+ },
56
+ {
57
+ "run": "g13-d24-full-s0",
58
+ "digits": 24,
59
+ "mode": "full",
60
+ "seed": 0,
61
+ "slots": 25,
62
+ "acc_1pass": 1.0,
63
+ "acc_sequential": 1.0
64
+ },
65
+ {
66
+ "run": "g13-d24-full-s1",
67
+ "digits": 24,
68
+ "mode": "full",
69
+ "seed": 1,
70
+ "slots": 25,
71
+ "acc_1pass": 0.01,
72
+ "acc_sequential": 0.0
73
+ },
74
+ {
75
+ "run": "g13-d24-full-s2",
76
+ "digits": 24,
77
+ "mode": "full",
78
+ "seed": 2,
79
+ "slots": 25,
80
+ "acc_1pass": 0.0,
81
+ "acc_sequential": 0.0
82
+ },
83
+ {
84
+ "run": "g13-d24-mdlm-s0",
85
+ "digits": 24,
86
+ "mode": "mdlm",
87
+ "seed": 0,
88
+ "slots": 25,
89
+ "acc_1pass": 0.0,
90
+ "acc_sequential": 0.0
91
+ },
92
+ {
93
+ "run": "g13-d24-mdlm-s1",
94
+ "digits": 24,
95
+ "mode": "mdlm",
96
+ "seed": 1,
97
+ "slots": 25,
98
+ "acc_1pass": 0.0,
99
+ "acc_sequential": 0.0
100
+ },
101
+ {
102
+ "run": "g13-d24-mdlm-s2",
103
+ "digits": 24,
104
+ "mode": "mdlm",
105
+ "seed": 2,
106
+ "slots": 25,
107
+ "acc_1pass": 0.0,
108
+ "acc_sequential": 0.0
109
+ }
110
+ ]
figures/summary.md CHANGED
@@ -35,8 +35,11 @@ Answers are unique but only ~10 characters with shallow, local dependencies. One
35
  | georgian | 93.9 | 93.9 | +0.0 |
36
  | german | 78.9 | 79.3 | +0.4 |
37
  | german | 75.6 | 79.5 | +3.9 |
 
38
  | german | 78.9 | 79.3 | +0.4 |
39
  | german | 77.9 | 78.0 | +0.1 |
 
 
40
  | german | 75.6 | 79.5 | +3.9 |
41
  | german | 76.4 | 78.9 | +2.5 |
42
  | german | 77.2 | 78.3 | +1.0 |
@@ -89,10 +92,11 @@ Every apparent failure at 10+ digits was a learning-rate artifact, not a limit o
89
 
90
  The account in THEORY.md predicts minimum depth growing as log2(n), since the carry is a prefix scan. A ripple-carry account predicts linear growth; an impossibility account predicts no depth suffices.
91
 
92
- | digits | 2L | 3L | 4L | 6L | 8L | log2(n) | min depth >90% |
93
- |---|---|---|---|---|---|---|---|
94
- | **4** | 100 | 100 | 100 | 100 | 100 | 2.0 | 2 |
95
- | **8** | 99 | 100 | – | – | – | 3.0 | 2 |
 
96
 
97
  ## Table 7 — Which component carries the gain (inflection)
98
 
@@ -100,8 +104,19 @@ The account in THEORY.md predicts minimum depth growing as log2(n), since the ca
100
  |---|---|---|---|---|---|
101
  | finnish | 51.4 | – | – | 51.9 | +7.7 / – / – / +4.9 |
102
  | georgian | 94.6 | – | – | 94.1 | -0.0 / – / – / -0.0 |
103
- | german | 76.0 | – | – | 78.4 | +3.2 / – / – / +0.2 |
104
  | navajo | 28.0 | – | – | 26.9 | +8.0 / – / – / +4.5 |
105
  | russian | 71.6 | – | – | 72.3 | +2.2 / – / – / -0.3 |
106
  | turkish | 78.7 | – | – | 82.3 | +3.5 / – / – / +0.8 |
107
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  | georgian | 93.9 | 93.9 | +0.0 |
36
  | german | 78.9 | 79.3 | +0.4 |
37
  | german | 75.6 | 79.5 | +3.9 |
38
+ | german | 78.6 | 78.9 | +0.3 |
39
  | german | 78.9 | 79.3 | +0.4 |
40
  | german | 77.9 | 78.0 | +0.1 |
41
+ | german | 79.4 | 81.0 | +1.7 |
42
+ | german | 76.5 | 77.6 | +1.0 |
43
  | german | 75.6 | 79.5 | +3.9 |
44
  | german | 76.4 | 78.9 | +2.5 |
45
  | german | 77.2 | 78.3 | +1.0 |
 
92
 
93
  The account in THEORY.md predicts minimum depth growing as log2(n), since the carry is a prefix scan. A ripple-carry account predicts linear growth; an impossibility account predicts no depth suffices.
94
 
95
+ | digits | 2L | 3L | 4L | 6L | 8L | 12L | log2(n) | min depth >90% |
96
+ |---|---|---|---|---|---|---|---|---|
97
+ | **4** | 100 | 100 | 100 | 100 | 100 | 100 | 2.0 | 2 |
98
+ | **8** | 99 | 100 | 100 | 100 | 100 | – | 3.0 | 2 |
99
+ | **12** | 48 | 100 | 100 | – | – | – | 3.6 | 3 |
100
 
101
  ## Table 7 — Which component carries the gain (inflection)
102
 
 
104
  |---|---|---|---|---|---|
105
  | finnish | 51.4 | – | – | 51.9 | +7.7 / – / – / +4.9 |
106
  | georgian | 94.6 | – | – | 94.1 | -0.0 / – / – / -0.0 |
107
+ | german | 76.0 | 77.9 | 78.6 | 78.4 | +3.2 / +1.4 / +0.3 / +0.2 |
108
  | navajo | 28.0 | – | – | 26.9 | +8.0 / – / – / +4.5 |
109
  | russian | 71.6 | – | – | 72.3 | +2.2 / – / – / -0.3 |
110
  | turkish | 78.7 | – | – | 82.3 | +3.5 / – / – / +0.8 |
111
 
112
+ ## Table 9 — Did the baseline fail to parallelise, or fail to learn?
113
+
114
+ A 20-digit answer occupies 21 slots, so the standard 16-pass grid is not a sequential decode. Re-decoded at one token per pass, the two explanations separate.
115
+
116
+ | digits | mode | @1 pass | fully sequential | reading |
117
+ |---|---|---|---|---|
118
+ | 20 | full | 99.8 | 85.7 | learned it and parallelises |
119
+ | 20 | mdlm | 0.0 | 0.0 | never learned the task |
120
+ | 24 | full | 33.7 | 33.3 | learned it and parallelises |
121
+ | 24 | mdlm | 0.0 | 0.0 | never learned the task |
122
+
results/g14-d12-L2-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 2,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L2-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 0.0125,
25
+ "2": 0.0125,
26
+ "3": 0.0175,
27
+ "4": 0.02,
28
+ "6": 0.02,
29
+ "8": 0.015,
30
+ "12": 0.0175,
31
+ "16": 0.0175
32
+ },
33
+ "minutes": 7.428513753414154,
34
+ "compute": {
35
+ "params": 3557376,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d12-L2-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 2,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L2-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 0.9450000000000001,
25
+ "2": 0.9724999999999999,
26
+ "3": 0.985,
27
+ "4": 0.9975,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 7.385485406716665,
34
+ "compute": {
35
+ "params": 3557376,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d12-L3-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 3,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L3-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 9.707445001602172,
34
+ "compute": {
35
+ "params": 5330304,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d12-L3-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 3,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L3-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 0.9975,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 9.8550892273585,
34
+ "compute": {
35
+ "params": 5330304,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d12-L4-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 4,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L4-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 0.9975,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 12.583855005105336,
34
+ "compute": {
35
+ "params": 7103232,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d12-L4-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 12,
8
+ "seq_len": 40,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 4,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d12-L4-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 12.607550446192423,
34
+ "compute": {
35
+ "params": 7103232,
36
+ "train_tokens": 307200000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d4-L12-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 4,
8
+ "seq_len": 16,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 12,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d4-L12-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 31.564673300584158,
34
+ "compute": {
35
+ "params": 21286656,
36
+ "train_tokens": 122880000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d4-L12-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 4,
8
+ "seq_len": 16,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 12,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d4-L12-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 30.931939947605134,
34
+ "compute": {
35
+ "params": 21286656,
36
+ "train_tokens": 122880000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d8-L6-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 8,
8
+ "seq_len": 28,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 6,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d8-L6-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 17.343261142571766,
34
+ "compute": {
35
+ "params": 10649088,
36
+ "train_tokens": 215040000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d8-L6-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 8,
8
+ "seq_len": 28,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 6,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d8-L6-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 17.595031853516897,
34
+ "compute": {
35
+ "params": 10649088,
36
+ "train_tokens": 215040000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d8-L8-s0.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 8,
8
+ "seq_len": 28,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 8,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 0,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d8-L8-s0"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 22.44843115409215,
34
+ "compute": {
35
+ "params": 14194944,
36
+ "train_tokens": 215040000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g14-d8-L8-s1.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "mode": "full",
4
+ "K_max": 16,
5
+ "K": 4,
6
+ "lam": 1.0,
7
+ "digits": 8,
8
+ "seq_len": 28,
9
+ "n_train": 800000,
10
+ "n_eval": 400,
11
+ "eval_bs": 100,
12
+ "d": 384,
13
+ "layers": 8,
14
+ "heads": 6,
15
+ "pe": "rope",
16
+ "bs": 128,
17
+ "steps": 60000,
18
+ "lr": 0.0001,
19
+ "warmup": 4000,
20
+ "seed": 1,
21
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g14-d8-L8-s1"
22
+ },
23
+ "accuracy_by_passes": {
24
+ "1": 1.0,
25
+ "2": 1.0,
26
+ "3": 1.0,
27
+ "4": 1.0,
28
+ "6": 1.0,
29
+ "8": 1.0,
30
+ "12": 1.0,
31
+ "16": 1.0
32
+ },
33
+ "minutes": 21.78090745608012,
34
+ "compute": {
35
+ "params": 14194944,
36
+ "train_tokens": 215040000,
37
+ "fwd_per_step": 2
38
+ }
39
+ }
results/g15-german-distill-s0.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "lang": "german",
4
+ "size": "medium",
5
+ "mode": "distill",
6
+ "seq_len": 48,
7
+ "d": 256,
8
+ "layers": 6,
9
+ "heads": 8,
10
+ "pe": "rope",
11
+ "bs": 64,
12
+ "steps": 15000,
13
+ "lr": 0.0001,
14
+ "warmup": 1000,
15
+ "K": 4,
16
+ "lam": 1.0,
17
+ "seed": 0,
18
+ "data_root": "/scratch/zt1/project/msml612/user/govind02/pcmd/data/sig",
19
+ "eval_bs": 128,
20
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g15-german-distill-s0"
21
+ },
22
+ "accuracy_by_passes": {
23
+ "1": 0.7861328125,
24
+ "2": 0.7795703125,
25
+ "4": 0.783203125,
26
+ "8": 0.788359375,
27
+ "16": 0.7893359375,
28
+ "32": 0.7893359375,
29
+ "ar": 0.0776171875
30
+ },
31
+ "minutes": 4.292282120386759,
32
+ "compute": {
33
+ "params": 4776448,
34
+ "answer_len_mean": 10.743975639343262
35
+ }
36
+ }
results/g15-german-matched-s0.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "lang": "german",
4
+ "size": "medium",
5
+ "mode": "matched",
6
+ "seq_len": 48,
7
+ "d": 256,
8
+ "layers": 6,
9
+ "heads": 8,
10
+ "pe": "rope",
11
+ "bs": 64,
12
+ "steps": 15000,
13
+ "lr": 0.0001,
14
+ "warmup": 1000,
15
+ "K": 4,
16
+ "lam": 1.0,
17
+ "seed": 0,
18
+ "data_root": "/scratch/zt1/project/msml612/user/govind02/pcmd/data/sig",
19
+ "eval_bs": 128,
20
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g15-german-matched-s0"
21
+ },
22
+ "accuracy_by_passes": {
23
+ "1": 0.793515625,
24
+ "2": 0.7919921875,
25
+ "4": 0.796171875,
26
+ "8": 0.8094140625,
27
+ "16": 0.810390625,
28
+ "32": 0.810390625,
29
+ "ar": 0.080546875
30
+ },
31
+ "minutes": 2.4515843311945598,
32
+ "compute": {
33
+ "params": 4776448,
34
+ "answer_len_mean": 10.743975639343262
35
+ }
36
+ }
results/g15-german-matched-s1.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "args": {
3
+ "lang": "german",
4
+ "size": "medium",
5
+ "mode": "matched",
6
+ "seq_len": 48,
7
+ "d": 256,
8
+ "layers": 6,
9
+ "heads": 8,
10
+ "pe": "rope",
11
+ "bs": 64,
12
+ "steps": 15000,
13
+ "lr": 0.0001,
14
+ "warmup": 1000,
15
+ "K": 4,
16
+ "lam": 1.0,
17
+ "seed": 1,
18
+ "data_root": "/scratch/zt1/project/msml612/user/govind02/pcmd/data/sig",
19
+ "eval_bs": 128,
20
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g15-german-matched-s1"
21
+ },
22
+ "accuracy_by_passes": {
23
+ "1": 0.7653515625,
24
+ "2": 0.7673046875,
25
+ "4": 0.776640625,
26
+ "8": 0.7758203125,
27
+ "16": 0.7758203125,
28
+ "32": 0.7758203125,
29
+ "ar": 0.0721875
30
+ },
31
+ "minutes": 2.444871123631795,
32
+ "compute": {
33
+ "params": 4776448,
34
+ "answer_len_mean": 10.743975639343262
35
+ }
36
+ }
slurm/g18.sh ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Grid 18 - does budget conditioning remove the crossover?
3
+ #
4
+ # At 20 digits, same config as g13, we already have both endpoints measured:
5
+ # mdlm 0.0 @1 pass, 0.0 @sequential (never learned the task)
6
+ # full 99.8 @1 pass, 85.7 @sequential (wins at 1, LOSES at 20)
7
+ # so this grid only needs the two new arms to complete a 4-way comparison at a
8
+ # single configuration.
9
+ #
10
+ # anybudget sample K per example AND condition the model on it
11
+ # anybudget_nc sample K identically but do NOT condition - the ablation that
12
+ # separates "mixing budgets" from "knowing the budget"
13
+ #
14
+ # Prediction: anybudget is strong at BOTH ends; anybudget_nc improves the
15
+ # sequential end but gives back the one-pass end, because without conditioning
16
+ # one set of weights has to serve contradictory targets.
17
+ #SBATCH -J g18
18
+ #SBATCH -p gpu-h100
19
+ #SBATCH --gpus=h100:1
20
+ #SBATCH -c 8
21
+ #SBATCH --mem=64g
22
+ #SBATCH -t 8:00:00
23
+ #SBATCH -o logs/g18-%A_%a.out
24
+ #SBATCH --array=0-5%6
25
+ source /etc/profile
26
+ SCR=/scratch/zt1/project/msml612/user/$USER
27
+ module load python/3.10.10
28
+ export PYTHONPATH=
29
+ cd $SCR/pcmd/src
30
+ MODES=(anybudget anybudget_nc); SEEDS=(0 1 2)
31
+ I=$SLURM_ARRAY_TASK_ID
32
+ M=${MODES[$((I / 3))]}; S=${SEEDS[$((I % 3))]}
33
+ NAME="g18-d20-$M-s$S"
34
+ echo "=== $NAME ==="
35
+ $SCR/hf_env/bin/python -u train_add.py --mode $M --digits 20 --seq_len 64 --seed $S \
36
+ --n_train 1500000 --n_eval 400 --eval_bs 100 \
37
+ --d 512 --layers 12 --heads 8 --bs 128 --steps 150000 --lr 1e-4 --warmup 6000 \
38
+ --out $SCR/pcmd/runs/$NAME
slurm/t8b.sh ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # The capstone experiment: does the training-side fix compose with the
3
+ # inference-side fix on data that contains BOTH failure modes at once?
4
+ #SBATCH -J t8
5
+ #SBATCH -p gpu-h100
6
+ #SBATCH --gpus=h100:1
7
+ #SBATCH -c 8
8
+ #SBATCH --mem=64g
9
+ #SBATCH -t 16:00:00
10
+ #SBATCH -o logs/t8-%A_%a.out
11
+ #SBATCH --array=0-5
12
+ source /etc/profile
13
+ SCR=/scratch/zt1/project/msml612/user/$USER
14
+ module load python/3.10.10
15
+ export PYTHONPATH=
16
+ cd $SCR/pcmd/src
17
+ MODES=(mdlm matched anybudget); SEEDS=(0 1)
18
+ I=$SLURM_ARRAY_TASK_ID
19
+ M=${MODES[$((I / 2))]}; S=${SEEDS[$((I % 2))]}
20
+ NAME="t8-$M-s$S"
21
+ echo "=== $NAME ==="
22
+ $SCR/hf_env/bin/python -u train_text8.py --mode $M --seed $S \
23
+ --root $SCR/pcmd/data/text8 --seq_len 256 \
24
+ --d 512 --layers 12 --heads 8 --bs 128 --steps 60000 --lr 1e-4 --warmup 4000 \
25
+ --K 8 --lam 1.0 --n_gen 256 --gen_bs 64 \
26
+ --evallm $SCR/pcmd/runs/evallm --out $SCR/pcmd/runs/$NAME
src/beat_baselines.py CHANGED
@@ -138,14 +138,15 @@ print(f"{'strategy':<22}{'1 pass':>9}{'2':>8}{'4':>8}{'8':>8}{'16':>8}")
138
  ITEMS = {}
139
  for strat, tau in [("confidence", None), ("entropy", None), ("entropy-gated", 0.5),
140
  ("margin", None), ("random", None)]:
141
- row = []
142
  for steps in (1, 2, 4, 8, 16):
143
- vals = []
144
- for d in base_dirs:
145
- m, _ = load(d)
146
- vals.append(run(m, steps, "entropy" if strat == "entropy-gated" else strat, tau))
147
- row.append(float(np.mean(vals)))
148
  results["inference_time_on_baseline"][strat] = row
 
149
  print(f"{strat:<22}" + "".join(f"{v*100:8.1f}" for v in row))
150
 
151
  row, ours_items = [], []
 
138
  ITEMS = {}
139
  for strat, tau in [("confidence", None), ("entropy", None), ("entropy-gated", 0.5),
140
  ("margin", None), ("random", None)]:
141
+ row, row_items = [], []
142
  for steps in (1, 2, 4, 8, 16):
143
+ vals = [run(load(d)[0], steps,
144
+ "entropy" if strat == "entropy-gated" else strat, tau)
145
+ for d in base_dirs]
146
+ per = np.mean(np.stack(vals), axis=0) # per-item, averaged over seeds
147
+ row.append(float(per.mean())); row_items.append(per)
148
  results["inference_time_on_baseline"][strat] = row
149
+ ITEMS[strat] = row_items
150
  print(f"{strat:<22}" + "".join(f"{v*100:8.1f}" for v in row))
151
 
152
  row, ours_items = [], []
src/diffusion.py CHANGED
@@ -532,7 +532,7 @@ def real_probs(logits, tok):
532
 
533
  @torch.no_grad()
534
  def entropy_budget_decode(model, x, tok, device, budget=0.5, max_steps=256,
535
- temperature=1.0, fillable=None):
536
  """FIX (ii): commit a set whose summed conditional entropy stays under `budget`.
537
 
538
  At each pass, rank the still-masked positions by conditional entropy and
@@ -556,7 +556,7 @@ def entropy_budget_decode(model, x, tok, device, budget=0.5, max_steps=256,
556
  has = masked.any(1)
557
  if not has.any():
558
  break
559
- logits = model(x)
560
  nfe += 1
561
  if temperature != 1.0:
562
  logits = logits / temperature
@@ -578,7 +578,7 @@ def entropy_budget_decode(model, x, tok, device, budget=0.5, max_steps=256,
578
 
579
  @torch.no_grad()
580
  def confidence_threshold_decode(model, x, tok, device, tau=0.9, max_steps=256,
581
- temperature=1.0, fillable=None):
582
  """The published inference-time competitor (confidence-threshold family).
583
 
584
  Commit every masked position whose top-1 probability exceeds `tau`. This is
@@ -597,7 +597,7 @@ def confidence_threshold_decode(model, x, tok, device, tau=0.9, max_steps=256,
597
  has = masked.any(1)
598
  if not has.any():
599
  break
600
- logits = model(x)
601
  nfe += 1
602
  if temperature != 1.0:
603
  logits = logits / temperature
@@ -616,7 +616,8 @@ def confidence_threshold_decode(model, x, tok, device, tau=0.9, max_steps=256,
616
 
617
 
618
  @torch.no_grad()
619
- def fixed_k_decode(model, x, tok, device, steps, temperature=1.0, fillable=None):
 
620
  """Plain K-pass decoding: reveal an equal share of positions per pass,
621
  highest-confidence first. The non-adaptive reference point, and the setting
622
  in which the addition results are reported."""
@@ -631,7 +632,7 @@ def fixed_k_decode(model, x, tok, device, steps, temperature=1.0, fillable=None)
631
  has = masked.any(1)
632
  if not has.any():
633
  break
634
- logits = model(x)
635
  nfe += 1
636
  if temperature != 1.0:
637
  logits = logits / temperature
@@ -691,3 +692,110 @@ def text_loss(model, x0, tok, mode="mdlm", K=8, lam=1.0):
691
  return uncond_mdlm_loss(model, x0, tok, "matched", K)
692
  base = uncond_mdlm_loss(model, x0, tok, "matched", K)
693
  return base + lam * uncond_mdlm_loss(model, x0, tok, "matched", 2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
 
533
  @torch.no_grad()
534
  def entropy_budget_decode(model, x, tok, device, budget=0.5, max_steps=256,
535
+ temperature=1.0, fillable=None, budget_cond=None):
536
  """FIX (ii): commit a set whose summed conditional entropy stays under `budget`.
537
 
538
  At each pass, rank the still-masked positions by conditional entropy and
 
556
  has = masked.any(1)
557
  if not has.any():
558
  break
559
+ logits = model(x, budget=budget_cond)
560
  nfe += 1
561
  if temperature != 1.0:
562
  logits = logits / temperature
 
578
 
579
  @torch.no_grad()
580
  def confidence_threshold_decode(model, x, tok, device, tau=0.9, max_steps=256,
581
+ temperature=1.0, fillable=None, budget_cond=None):
582
  """The published inference-time competitor (confidence-threshold family).
583
 
584
  Commit every masked position whose top-1 probability exceeds `tau`. This is
 
597
  has = masked.any(1)
598
  if not has.any():
599
  break
600
+ logits = model(x, budget=budget_cond)
601
  nfe += 1
602
  if temperature != 1.0:
603
  logits = logits / temperature
 
616
 
617
 
618
  @torch.no_grad()
619
+ def fixed_k_decode(model, x, tok, device, steps, temperature=1.0, fillable=None,
620
+ budget_cond=None):
621
  """Plain K-pass decoding: reveal an equal share of positions per pass,
622
  highest-confidence first. The non-adaptive reference point, and the setting
623
  in which the addition results are reported."""
 
632
  has = masked.any(1)
633
  if not has.any():
634
  break
635
+ logits = model(x, budget=budget_cond)
636
  nfe += 1
637
  if temperature != 1.0:
638
  logits = logits / temperature
 
692
  return uncond_mdlm_loss(model, x0, tok, "matched", K)
693
  base = uncond_mdlm_loss(model, x0, tok, "matched", K)
694
  return base + lam * uncond_mdlm_loss(model, x0, tok, "matched", 2)
695
+
696
+
697
+ # ------------------------------------------------ any-budget masked diffusion ---
698
+ # The limitation the fixed-K method has, stated plainly: training at a single K
699
+ # is a COMMITMENT to one decoding budget. Measured on 20-digit addition, a model
700
+ # trained for one pass scores 99.8% at one pass and 85.7% at twenty - the
701
+ # baseline's own disease with the roles swapped, because intermediate
702
+ # partially-decoded states are themselves off-distribution for it.
703
+ #
704
+ # That makes a fixed-K method unable to dominate a quality-vs-compute frontier:
705
+ # it wins at K and loses away from K. Since the frontier is precisely the axis
706
+ # the parallel-decoding literature competes on, fixing this is what turns a
707
+ # single good operating point into a curve that dominates.
708
+ #
709
+ # The fix: sample K during training and TELL the model which K it is being
710
+ # trained for. One network then serves every budget. Cost is one embedding
711
+ # lookup and no extra forward passes, so it is cheaper than the fixed-K method
712
+ # it replaces.
713
+
714
+ BUDGETS = (1, 2, 4, 8, 16, 32, 64, 128, 256)
715
+
716
+
717
+ def sample_budget(B, device, choices=BUDGETS, weights=None):
718
+ """Draw a decoding budget per example.
719
+
720
+ Per-example rather than per-batch so a single step covers many budgets,
721
+ which keeps the gradient signal for every bin alive at every step.
722
+ """
723
+ c = torch.as_tensor(choices, device=device, dtype=torch.float)
724
+ if weights is None:
725
+ idx = torch.randint(0, len(c), (B,), device=device)
726
+ else:
727
+ w = torch.as_tensor(weights, device=device, dtype=torch.float)
728
+ idx = torch.multinomial(w.expand(B, -1), 1).squeeze(1)
729
+ return c[idx]
730
+
731
+
732
+ def _t_for_budget(K):
733
+ """Draw t from the mask ratios a K-pass decode actually visits.
734
+
735
+ A K-pass decode evaluates the model at {1, (K-1)/K, ..., 1/K}. Drawing the
736
+ step index uniformly in [1, K] and dividing reproduces exactly that set,
737
+ including the atom at t = 1 that continuous U(0,1) never supplies.
738
+ """
739
+ step = (torch.rand_like(K) * K).floor() + 1.0
740
+ return (step / K).clamp(1e-6, 1.0)
741
+
742
+
743
+ def cond_any_budget_loss(model, x0, amask, tok, choices=BUDGETS, condition=True):
744
+ """Any-budget objective for conditional tasks (addition, inflection)."""
745
+ B = x0.shape[0]
746
+ dev = x0.device
747
+ K = sample_budget(B, dev, choices)
748
+ t = _t_for_budget(K)
749
+
750
+ m = _cond_mask(x0, amask, tok, t)
751
+ xt = torch.where(m, torch.full_like(x0, tok.mask), x0)
752
+ logits = model(xt, budget=K if condition else None)
753
+ ce = F.cross_entropy(logits.reshape(-1, logits.size(-1)), x0.reshape(-1),
754
+ reduction="none").view(B, -1)
755
+ return ((ce * m).sum(1) / m.sum(1).clamp_min(1)).mean()
756
+
757
+
758
+ def uncond_any_budget_loss(model, x0, tok, choices=BUDGETS, condition=True):
759
+ """Any-budget objective for unconditional text.
760
+
761
+ Keeps the 1/t ELBO weighting so that, with a uniform-t schedule and no
762
+ conditioning, this reduces exactly to the published MDLM objective.
763
+ """
764
+ B, L = x0.shape
765
+ dev = x0.device
766
+ K = sample_budget(B, dev, choices)
767
+ t = _t_for_budget(K)
768
+
769
+ m = torch.rand(B, L, device=dev) < t[:, None]
770
+ m[torch.arange(B, device=dev), torch.randint(0, L, (B,), device=dev)] = True
771
+ xt = torch.where(m, torch.full_like(x0, tok.mask), x0)
772
+ logits = model(xt, budget=K if condition else None)
773
+ ce = F.cross_entropy(logits.reshape(-1, logits.size(-1)), x0.reshape(-1),
774
+ reduction="none").view(B, L)
775
+ return ((1.0 / t) * (ce * m).sum(1) / L).mean()
776
+
777
+
778
+ @torch.no_grad()
779
+ def cond_decode_budget(model, x0, amask, tok, steps, device, condition=True):
780
+ """`cond_decode`, but the model is told the budget it is being run at."""
781
+ x = torch.where(amask, torch.full_like(x0, tok.mask), x0).to(device)
782
+ am = amask.to(device)
783
+ B, L = x.shape
784
+ n_ans = int(am[0].sum())
785
+ bud = torch.full((B,), float(steps), device=device) if condition else None
786
+ pred = None
787
+ for s in range(steps, 0, -1):
788
+ masked = (x == tok.mask) & am
789
+ if not masked.any():
790
+ break
791
+ conf, pred = real_probs(model(x, budget=bud), tok).max(-1)
792
+ conf = conf.masked_fill(~masked, -1e9)
793
+ left = int(n_ans * (s - 1) / steps)
794
+ for b in range(B):
795
+ k = max(0, int(masked[b].sum()) - left)
796
+ if k:
797
+ x[b, conf[b].topk(k).indices] = pred[b, conf[b].topk(k).indices]
798
+ rem = (x == tok.mask) & am
799
+ if rem.any() and pred is not None:
800
+ x[rem] = pred[rem]
801
+ return x
src/model.py CHANGED
@@ -93,10 +93,22 @@ class Block(nn.Module):
93
 
94
 
95
  class Transformer(nn.Module):
96
- def __init__(self, vocab, d=384, n_layers=6, n_heads=6, pe="ape", causal=False, max_len=256):
 
97
  super().__init__()
98
  self.pe_kind, self.causal = pe, causal
 
99
  self.emb = nn.Embedding(vocab, d)
 
 
 
 
 
 
 
 
 
 
100
  # Segment embedding: which part of the equation a token belongs to.
101
  # Place-value ids deliberately collide across operands and answer, so a
102
  # bidirectional model needs this to tell those tokens apart; a causal
@@ -118,9 +130,26 @@ class Transformer(nn.Module):
118
  if isinstance(m, nn.Linear) and m.bias is not None:
119
  nn.init.zeros_(m.bias)
120
 
121
- def forward(self, idx, pad_mask=None, pos_ids=None):
 
 
 
 
 
 
 
 
 
 
 
 
122
  B, L = idx.shape
123
  x = self.emb(idx)
 
 
 
 
 
124
  if self.pe_kind == "ape":
125
  p = torch.arange(L, device=idx.device)[None] if pos_ids is None else pos_ids
126
  x = x + self.pos(p)
 
93
 
94
 
95
  class Transformer(nn.Module):
96
+ def __init__(self, vocab, d=384, n_layers=6, n_heads=6, pe="ape", causal=False,
97
+ max_len=256, budget_bins=0):
98
  super().__init__()
99
  self.pe_kind, self.causal = pe, causal
100
+ self.budget_bins = budget_bins
101
  self.emb = nn.Embedding(vocab, d)
102
+ # Budget conditioning. A K-pass decode only visits mask ratios
103
+ # {1, (K-1)/K, ..., 1/K}, so a model trained for one K is mis-specified
104
+ # at every other K - measured directly: our 20-digit model scores 99.8%
105
+ # at one pass and 85.7% at twenty. Telling the model which budget it is
106
+ # being decoded at lets ONE network serve every budget instead of a
107
+ # family of networks each good at a single point.
108
+ # budget_bins=0 keeps the parameter absent entirely, so checkpoints
109
+ # trained before this existed still load.
110
+ if budget_bins:
111
+ self.budget_emb = nn.Embedding(budget_bins, d)
112
  # Segment embedding: which part of the equation a token belongs to.
113
  # Place-value ids deliberately collide across operands and answer, so a
114
  # bidirectional model needs this to tell those tokens apart; a causal
 
130
  if isinstance(m, nn.Linear) and m.bias is not None:
131
  nn.init.zeros_(m.bias)
132
 
133
+ @staticmethod
134
+ def budget_bin(K, n_bins, device):
135
+ """Map a decoding budget K to a bin index by log2, clamped.
136
+
137
+ Budgets are used on a log scale (1, 2, 4, ... L), so log2 is the natural
138
+ parameterisation and keeps the table small.
139
+ """
140
+ if not torch.is_tensor(K):
141
+ K = torch.as_tensor(K, device=device)
142
+ K = K.to(device).float().clamp_min(1.0)
143
+ return torch.log2(K).round().long().clamp_(0, n_bins - 1)
144
+
145
+ def forward(self, idx, pad_mask=None, pos_ids=None, budget=None):
146
  B, L = idx.shape
147
  x = self.emb(idx)
148
+ if self.budget_bins and budget is not None:
149
+ b = self.budget_bin(budget, self.budget_bins, idx.device)
150
+ if b.ndim == 0:
151
+ b = b.expand(B)
152
+ x = x + self.budget_emb(b)[:, None, :]
153
  if self.pe_kind == "ape":
154
  p = torch.arange(L, device=idx.device)[None] if pos_ids is None else pos_ids
155
  x = x + self.pos(p)
src/train_add.py CHANGED
@@ -20,8 +20,15 @@ import diffusion as dfn
20
 
21
  def get_args():
22
  p = argparse.ArgumentParser()
23
- p.add_argument("--mode", choices=["mdlm", "matched", "distill", "full", "prog"],
24
- default="mdlm", help="prog = parallelism curriculum (the method)")
 
 
 
 
 
 
 
25
  p.add_argument("--K_max", type=int, default=16)
26
  p.add_argument("--K", type=int, default=8, help="parallelism the schedule is matched to")
27
  p.add_argument("--lam", type=float, default=1.0, help="one-pass supervision weight")
@@ -57,15 +64,25 @@ def exact_match(pred, gold, amask, tok):
57
 
58
  @torch.no_grad()
59
  def evaluate(model, a, tok, device):
 
 
 
 
 
 
 
60
  model.eval()
61
  out = {}
62
  X, A, _ = build_addition(a.n_eval, a.digits, a.seq_len, seed=90_000, exact=True)
63
  X, A = torch.from_numpy(X), torch.from_numpy(A)
64
- for steps in PASS_GRID:
 
 
65
  accs = []
66
  for i in range(0, len(X), a.eval_bs):
67
  xb, ab = X[i:i + a.eval_bs].to(device), A[i:i + a.eval_bs].to(device)
68
- pred = dfn.cond_decode(model, xb, ab, tok, steps, device)
 
69
  accs.append(exact_match(pred.cpu(), xb.cpu(), ab.cpu(), tok))
70
  out[str(steps)] = float(np.mean(accs))
71
  model.train()
@@ -81,8 +98,10 @@ def main():
81
  X, A, tok = build_addition(a.n_train, a.digits, a.seq_len, seed=a.seed)
82
  X, A = torch.from_numpy(X), torch.from_numpy(A)
83
 
 
84
  model = Transformer(len(tok), a.d, a.layers, a.heads, a.pe,
85
- causal=False, max_len=a.seq_len + 8).to(dev)
 
86
  print(f"[{a.mode}] params={model.n_params()/1e6:.2f}M digits<={a.digits} "
87
  f"K={a.K} device={dev}", flush=True)
88
 
@@ -102,6 +121,9 @@ def main():
102
  if a.mode == "prog":
103
  loss, K_now, lam_now = dfn.pmd_progressive(
104
  model, xb, ab, tok, step / max(1, a.steps), a.K_max, a.lam)
 
 
 
105
  else:
106
  loss = dfn.pmd_loss(model, xb, ab, tok, a.mode, a.K, a.lam)
107
  loss.backward()
 
20
 
21
  def get_args():
22
  p = argparse.ArgumentParser()
23
+ p.add_argument("--mode",
24
+ choices=["mdlm", "matched", "distill", "full", "prog",
25
+ "anybudget", "anybudget_nc"],
26
+ default="mdlm",
27
+ help="anybudget = sample K and condition on it (the method); "
28
+ "anybudget_nc = same K sampling WITHOUT conditioning, "
29
+ "the ablation that isolates what conditioning buys")
30
+ p.add_argument("--budget_bins", type=int, default=10,
31
+ help="log2 bins for budget conditioning; 0 disables")
32
  p.add_argument("--K_max", type=int, default=16)
33
  p.add_argument("--K", type=int, default=8, help="parallelism the schedule is matched to")
34
  p.add_argument("--lam", type=float, default=1.0, help="one-pass supervision weight")
 
64
 
65
  @torch.no_grad()
66
  def evaluate(model, a, tok, device):
67
+ """Accuracy across the whole pass grid.
68
+
69
+ The grid now runs out to a FULLY SEQUENTIAL decode (one token per pass), not
70
+ just 16: a 20-digit answer has 21 slots, so stopping at 16 never measures
71
+ sequential decoding at all and cannot tell "failed to parallelise" apart
72
+ from "failed to learn".
73
+ """
74
  model.eval()
75
  out = {}
76
  X, A, _ = build_addition(a.n_eval, a.digits, a.seq_len, seed=90_000, exact=True)
77
  X, A = torch.from_numpy(X), torch.from_numpy(A)
78
+ cond = getattr(model, "budget_bins", 0) > 0
79
+ grid = sorted(set(PASS_GRID) | {int(A[0].sum())})
80
+ for steps in grid:
81
  accs = []
82
  for i in range(0, len(X), a.eval_bs):
83
  xb, ab = X[i:i + a.eval_bs].to(device), A[i:i + a.eval_bs].to(device)
84
+ pred = (dfn.cond_decode_budget(model, xb, ab, tok, steps, device)
85
+ if cond else dfn.cond_decode(model, xb, ab, tok, steps, device))
86
  accs.append(exact_match(pred.cpu(), xb.cpu(), ab.cpu(), tok))
87
  out[str(steps)] = float(np.mean(accs))
88
  model.train()
 
98
  X, A, tok = build_addition(a.n_train, a.digits, a.seq_len, seed=a.seed)
99
  X, A = torch.from_numpy(X), torch.from_numpy(A)
100
 
101
+ cond = a.mode == "anybudget"
102
  model = Transformer(len(tok), a.d, a.layers, a.heads, a.pe,
103
+ causal=False, max_len=a.seq_len + 8,
104
+ budget_bins=a.budget_bins if cond else 0).to(dev)
105
  print(f"[{a.mode}] params={model.n_params()/1e6:.2f}M digits<={a.digits} "
106
  f"K={a.K} device={dev}", flush=True)
107
 
 
121
  if a.mode == "prog":
122
  loss, K_now, lam_now = dfn.pmd_progressive(
123
  model, xb, ab, tok, step / max(1, a.steps), a.K_max, a.lam)
124
+ elif a.mode in ("anybudget", "anybudget_nc"):
125
+ loss = dfn.cond_any_budget_loss(model, xb, ab, tok,
126
+ condition=cond)
127
  else:
128
  loss = dfn.pmd_loss(model, xb, ab, tok, a.mode, a.K, a.lam)
129
  loss.backward()
src/train_text8.py CHANGED
@@ -40,7 +40,10 @@ import diffusion as dfn
40
 
41
  def get_args():
42
  p = argparse.ArgumentParser()
43
- p.add_argument("--mode", choices=["mdlm", "matched", "full"], default="mdlm")
 
 
 
44
  p.add_argument("--K", type=int, default=8, help="parallelism the schedule is matched to")
45
  p.add_argument("--lam", type=float, default=1.0)
46
  p.add_argument("--root", default="data/text8")
@@ -70,8 +73,10 @@ tr, va, te, tok = load_text8(a.root, a.seq_len)
70
  print(f"text8: train {tr.shape} valid {va.shape} test {te.shape} vocab {len(tok)}",
71
  flush=True)
72
 
73
- model = Transformer(len(tok), a.d, a.layers, a.heads, "rope",
74
- causal=False, max_len=a.seq_len + 8).to(dev)
 
 
75
  print(f"denoiser params: {sum(q.numel() for q in model.parameters())/1e6:.1f}M", flush=True)
76
  opt = torch.optim.AdamW(model.parameters(), lr=a.lr, weight_decay=0.01, betas=(0.9, 0.95))
77
  sched = torch.optim.lr_scheduler.LambdaLR(
@@ -82,7 +87,10 @@ t0 = time.time()
82
  for step in range(a.steps):
83
  x = torch.from_numpy(next(it)).to(dev)
84
  with torch.autocast("cuda", dtype=torch.bfloat16, enabled=(dev == "cuda")):
85
- loss = dfn.text_loss(model, x, tok, a.mode, a.K, a.lam)
 
 
 
86
  opt.zero_grad(set_to_none=True)
87
  loss.backward()
88
  torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
@@ -176,23 +184,30 @@ def evaluate(tag, fn):
176
  print("\n=== decoding: quality against compute ===", flush=True)
177
  res["decode"] = {}
178
 
 
 
 
 
 
179
  print("fixed-K (non-adaptive reference):", flush=True)
180
  for K in (1, 2, 4, 8, 16, 32, 64, 128, 256):
181
  res["decode"][f"fixedK_{K}"] = evaluate(
182
  f"fixed-K K={K}",
183
- lambda b, K=K: dfn.fixed_k_decode(model, b, tok, dev, K))
184
 
185
  print("confidence-threshold (published inference-time method):", flush=True)
186
  for tau in (0.5, 0.7, 0.9, 0.95, 0.99):
187
  res["decode"][f"conf_{tau}"] = evaluate(
188
  f"confidence tau={tau}",
189
- lambda b, tau=tau: dfn.confidence_threshold_decode(model, b, tok, dev, tau))
 
190
 
191
  print("entropy-budget (ours, fix (ii)):", flush=True)
192
  for B in (0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0):
193
  res["decode"][f"entbudget_{B}"] = evaluate(
194
  f"entropy-budget B={B}",
195
- lambda b, B=B: dfn.entropy_budget_decode(model, b, tok, dev, B))
 
196
 
197
  torch.save(model.state_dict(), os.path.join(a.out, "model.pt"))
198
  json.dump(res, open(os.path.join(a.out, "result.json"), "w"), indent=2)
 
40
 
41
  def get_args():
42
  p = argparse.ArgumentParser()
43
+ p.add_argument("--mode",
44
+ choices=["mdlm", "matched", "full", "anybudget", "anybudget_nc"],
45
+ default="mdlm")
46
+ p.add_argument("--budget_bins", type=int, default=10)
47
  p.add_argument("--K", type=int, default=8, help="parallelism the schedule is matched to")
48
  p.add_argument("--lam", type=float, default=1.0)
49
  p.add_argument("--root", default="data/text8")
 
73
  print(f"text8: train {tr.shape} valid {va.shape} test {te.shape} vocab {len(tok)}",
74
  flush=True)
75
 
76
+ COND = a.mode == "anybudget"
77
+ model = Transformer(len(tok), a.d, a.layers, a.heads, "rope", causal=False,
78
+ max_len=a.seq_len + 8,
79
+ budget_bins=a.budget_bins if COND else 0).to(dev)
80
  print(f"denoiser params: {sum(q.numel() for q in model.parameters())/1e6:.1f}M", flush=True)
81
  opt = torch.optim.AdamW(model.parameters(), lr=a.lr, weight_decay=0.01, betas=(0.9, 0.95))
82
  sched = torch.optim.lr_scheduler.LambdaLR(
 
87
  for step in range(a.steps):
88
  x = torch.from_numpy(next(it)).to(dev)
89
  with torch.autocast("cuda", dtype=torch.bfloat16, enabled=(dev == "cuda")):
90
+ if a.mode in ("anybudget", "anybudget_nc"):
91
+ loss = dfn.uncond_any_budget_loss(model, x, tok, condition=COND)
92
+ else:
93
+ loss = dfn.text_loss(model, x, tok, a.mode, a.K, a.lam)
94
  opt.zero_grad(set_to_none=True)
95
  loss.backward()
96
  torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
 
184
  print("\n=== decoding: quality against compute ===", flush=True)
185
  res["decode"] = {}
186
 
187
+ def bud(K):
188
+ """The budget to declare to the model, or None if it is not conditioned."""
189
+ return (torch.full((a.gen_bs,), float(K), device=dev)) if COND else None
190
+
191
+
192
  print("fixed-K (non-adaptive reference):", flush=True)
193
  for K in (1, 2, 4, 8, 16, 32, 64, 128, 256):
194
  res["decode"][f"fixedK_{K}"] = evaluate(
195
  f"fixed-K K={K}",
196
+ lambda b, K=K: dfn.fixed_k_decode(model, b, tok, dev, K, budget_cond=bud(K)))
197
 
198
  print("confidence-threshold (published inference-time method):", flush=True)
199
  for tau in (0.5, 0.7, 0.9, 0.95, 0.99):
200
  res["decode"][f"conf_{tau}"] = evaluate(
201
  f"confidence tau={tau}",
202
+ lambda b, tau=tau: dfn.confidence_threshold_decode(
203
+ model, b, tok, dev, tau, budget_cond=bud(8)))
204
 
205
  print("entropy-budget (ours, fix (ii)):", flush=True)
206
  for B in (0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0):
207
  res["decode"][f"entbudget_{B}"] = evaluate(
208
  f"entropy-budget B={B}",
209
+ lambda b, B=B: dfn.entropy_budget_decode(
210
+ model, b, tok, dev, B, budget_cond=bud(8)))
211
 
212
  torch.save(model.state_dict(), os.path.join(a.out, "model.pt"))
213
  json.dump(res, open(os.path.join(a.out, "result.json"), "w"), indent=2)