GOVINDFROM commited on
Commit
7fa1b76
·
verified ·
1 Parent(s): 98c193b

Automated push from Zaratan

Browse files
results/g1-copy-mdlm-s0.json CHANGED
@@ -13,6 +13,7 @@
13
  "objective": "mdlm",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
 
16
  "task": "copy",
17
  "coupling": 4,
18
  "seq_len": 128,
@@ -31,7 +32,7 @@
31
  "eval_bs": 100,
32
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-mdlm-s0"
33
  },
34
- "minutes": 3.757214069366455,
35
  "compute": {
36
  "params": 10660608,
37
  "train_tokens": 163840000,
 
13
  "objective": "mdlm",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
16
+ "ramp_frac": 0.3,
17
  "task": "copy",
18
  "coupling": 4,
19
  "seq_len": 128,
 
32
  "eval_bs": 100,
33
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-mdlm-s0"
34
  },
35
+ "minutes": 3.7576344490051268,
36
  "compute": {
37
  "params": 10660608,
38
  "train_tokens": 163840000,
results/g1-copy-mdlm-s1.json CHANGED
@@ -13,6 +13,7 @@
13
  "objective": "mdlm",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
 
16
  "task": "copy",
17
  "coupling": 4,
18
  "seq_len": 128,
@@ -31,7 +32,7 @@
31
  "eval_bs": 100,
32
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-mdlm-s1"
33
  },
34
- "minutes": 3.7269402066866557,
35
  "compute": {
36
  "params": 10660608,
37
  "train_tokens": 163840000,
 
13
  "objective": "mdlm",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
16
+ "ramp_frac": 0.3,
17
  "task": "copy",
18
  "coupling": 4,
19
  "seq_len": 128,
 
32
  "eval_bs": 100,
33
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-mdlm-s1"
34
  },
35
+ "minutes": 3.7286835312843323,
36
  "compute": {
37
  "params": 10660608,
38
  "train_tokens": 163840000,
results/g1-copy-selfcorrupt-s0.json CHANGED
@@ -1,18 +1,19 @@
1
  {
2
  "accuracy_by_passes": {
3
- "1": 0.0,
4
- "2": 0.0,
5
- "4": 0.0,
6
- "8": 0.0,
7
- "16": 0.0,
8
- "32": 0.0,
9
- "64": 0.0,
10
- "128": 0.0
11
  },
12
  "args": {
13
  "objective": "selfcorrupt",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
 
16
  "task": "copy",
17
  "coupling": 4,
18
  "seq_len": 128,
@@ -31,7 +32,7 @@
31
  "eval_bs": 100,
32
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-selfcorrupt-s0"
33
  },
34
- "minutes": 4.29505068063736,
35
  "compute": {
36
  "params": 10660608,
37
  "train_tokens": 163840000,
 
1
  {
2
  "accuracy_by_passes": {
3
+ "1": 0.346,
4
+ "2": 0.346,
5
+ "4": 0.602,
6
+ "8": 0.6639999999999999,
7
+ "16": 0.6460000000000001,
8
+ "32": 0.64,
9
+ "64": 0.6200000000000001,
10
+ "128": 0.6140000000000001
11
  },
12
  "args": {
13
  "objective": "selfcorrupt",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
16
+ "ramp_frac": 0.3,
17
  "task": "copy",
18
  "coupling": 4,
19
  "seq_len": 128,
 
32
  "eval_bs": 100,
33
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-selfcorrupt-s0"
34
  },
35
+ "minutes": 4.341549547513326,
36
  "compute": {
37
  "params": 10660608,
38
  "train_tokens": 163840000,
results/g1-copy-selfcorrupt-s1.json CHANGED
@@ -1,18 +1,19 @@
1
  {
2
  "accuracy_by_passes": {
3
- "1": 0.0,
4
- "2": 0.0,
5
- "4": 0.0,
6
- "8": 0.0,
7
- "16": 0.0,
8
- "32": 0.0,
9
- "64": 0.0,
10
- "128": 0.0
11
  },
12
  "args": {
13
  "objective": "selfcorrupt",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
 
16
  "task": "copy",
17
  "coupling": 4,
18
  "seq_len": 128,
@@ -31,7 +32,7 @@
31
  "eval_bs": 100,
32
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-selfcorrupt-s1"
33
  },
34
- "minutes": 4.269979015986125,
35
  "compute": {
36
  "params": 10660608,
37
  "train_tokens": 163840000,
 
1
  {
2
  "accuracy_by_passes": {
3
+ "1": 0.024,
4
+ "2": 0.024,
5
+ "4": 0.21800000000000003,
6
+ "8": 0.28400000000000003,
7
+ "16": 0.306,
8
+ "32": 0.33199999999999996,
9
+ "64": 0.354,
10
+ "128": 0.352
11
  },
12
  "args": {
13
  "objective": "selfcorrupt",
14
  "k_frac": 0.25,
15
  "correct_weight": 1.0,
16
+ "ramp_frac": 0.3,
17
  "task": "copy",
18
  "coupling": 4,
19
  "seq_len": 128,
 
32
  "eval_bs": 100,
33
  "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g1-copy-selfcorrupt-s1"
34
  },
35
+ "minutes": 4.30184254248937,
36
  "compute": {
37
  "params": 10660608,
38
  "train_tokens": 163840000,
results/g2-agree-mdlm-s0.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 0.0,
4
+ "2": 0.0,
5
+ "4": 0.0,
6
+ "8": 0.0,
7
+ "16": 0.0,
8
+ "32": 0.0,
9
+ "64": 0.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "mdlm",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "agree",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 0,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-agree-mdlm-s0"
38
+ },
39
+ "minutes": 3.6784939726193744,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
results/g2-agree-mdlm-s1.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 0.0,
4
+ "2": 0.0,
5
+ "4": 0.0,
6
+ "8": 0.0,
7
+ "16": 0.0,
8
+ "32": 0.0,
9
+ "64": 0.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "mdlm",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "agree",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 1,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-agree-mdlm-s1"
38
+ },
39
+ "minutes": 3.7346819678942365,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
results/g2-copy-coord-s0.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 1.0,
4
+ "2": 1.0,
5
+ "4": 1.0,
6
+ "8": 1.0,
7
+ "16": 1.0,
8
+ "32": 1.0,
9
+ "64": 1.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "coord",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "copy",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 0,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-copy-coord-s0"
38
+ },
39
+ "minutes": 5.439730898539225,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
results/g2-copy-coord-s1.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 1.0,
4
+ "2": 1.0,
5
+ "4": 1.0,
6
+ "8": 1.0,
7
+ "16": 1.0,
8
+ "32": 1.0,
9
+ "64": 1.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "coord",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "copy",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 1,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-copy-coord-s1"
38
+ },
39
+ "minutes": 5.407112606366476,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
results/g2-copy-mdlm-s0.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 1.0,
4
+ "2": 1.0,
5
+ "4": 1.0,
6
+ "8": 1.0,
7
+ "16": 1.0,
8
+ "32": 1.0,
9
+ "64": 1.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "mdlm",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "copy",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 0,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-copy-mdlm-s0"
38
+ },
39
+ "minutes": 3.6734960357348125,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
results/g2-copy-mdlm-s1.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "accuracy_by_passes": {
3
+ "1": 1.0,
4
+ "2": 1.0,
5
+ "4": 1.0,
6
+ "8": 1.0,
7
+ "16": 1.0,
8
+ "32": 1.0,
9
+ "64": 1.0,
10
+ "128": 1.0
11
+ },
12
+ "args": {
13
+ "objective": "mdlm",
14
+ "alpha": 0.5,
15
+ "beta": 1.0,
16
+ "group": 4,
17
+ "coord_every": 4,
18
+ "k_frac": 0.25,
19
+ "correct_weight": 1.0,
20
+ "ramp_frac": 0.3,
21
+ "task": "copy",
22
+ "coupling": 4,
23
+ "seq_len": 128,
24
+ "n_train": 200000,
25
+ "n_eval": 500,
26
+ "d": 384,
27
+ "layers": 6,
28
+ "heads": 6,
29
+ "pe": "rope",
30
+ "bs": 64,
31
+ "steps": 20000,
32
+ "lr": 0.0003,
33
+ "warmup": 500,
34
+ "seed": 1,
35
+ "data_root": "data",
36
+ "eval_bs": 100,
37
+ "out": "/scratch/zt1/project/msml612/user/govind02/pcmd/runs/g2-copy-mdlm-s1"
38
+ },
39
+ "minutes": 3.669589972496033,
40
+ "compute": {
41
+ "params": 10660608,
42
+ "train_tokens": 163840000,
43
+ "train_flops_approx": 10479804088320000,
44
+ "fwd_per_step": 1
45
+ }
46
+ }
slurm/grid1b.sh ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Grid 1 — learnability gate and the first quality-vs-parallelism curves.
3
+ #
4
+ # Doubles as a gate: if a model cannot solve a probe even at FULLY SEQUENTIAL
5
+ # decoding (128 passes for a 128-token canvas), the task is not learnable at
6
+ # this scale and no parallel-decoding claim built on it would mean anything.
7
+ # Launching a large grid before establishing this is the mistake that cost a
8
+ # day on the previous project.
9
+ #SBATCH -J g1
10
+ #SBATCH -p gpu-h100
11
+ #SBATCH --gpus=h100:1
12
+ #SBATCH -c 8
13
+ #SBATCH --mem=64g
14
+ #SBATCH -t 04:00:00
15
+ #SBATCH -o logs/g1-%A_%a.out
16
+ #SBATCH --array=0-3%4
17
+
18
+ source /etc/profile
19
+ SCR=/scratch/zt1/project/msml612/user/$USER
20
+ module load python/3.10.10
21
+ export PYTHONPATH=
22
+ PY=$SCR/hf_env/bin/python
23
+ cd $SCR/pcmd/src
24
+
25
+ I=$SLURM_ARRAY_TASK_ID
26
+ TASKS=(copy); OBJ=(mdlm selfcorrupt); SEEDS=(0 1)
27
+ T=${TASKS[$((I / 4))]}
28
+ O=${OBJ[$(((I % 4) / 2))]}
29
+ S=${SEEDS[$((I % 2))]}
30
+
31
+ NAME="g1-$T-$O-s$S"
32
+ echo "=== $NAME ==="
33
+ $PY train.py --task $T --objective $O --coupling 4 --seed $S \
34
+ --seq_len 128 --n_train 200000 --n_eval 500 --eval_bs 100 \
35
+ --d 384 --layers 6 --heads 6 --bs 64 --steps 20000 --lr 3e-4 \
36
+ --out $SCR/pcmd/runs/$NAME
slurm/grid2.sh ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Grid 2 — the method vs its ablations vs the baseline, on all three probes.
3
+ #
4
+ # Objectives
5
+ # mdlm ELBO only (standard masked diffusion)
6
+ # selfcorrupt ELBO + self-conditioning (component 1)
7
+ # coord ELBO + coordination (component 2, the core)
8
+ # cmd ELBO + both (full method)
9
+ #
10
+ # The probes make the claim falsifiable: `copy` has independent answer
11
+ # positions, so the method must NOT hurt there; `agree` and `parity` have
12
+ # jointly-dependent positions, which is where it must win.
13
+ #SBATCH -J g2
14
+ #SBATCH -p gpu-h100
15
+ #SBATCH --gpus=h100:1
16
+ #SBATCH -c 8
17
+ #SBATCH --mem=64g
18
+ #SBATCH -t 08:00:00
19
+ #SBATCH -o logs/g2-%A_%a.out
20
+ #SBATCH --array=0-23%12
21
+
22
+ source /etc/profile
23
+ SCR=/scratch/zt1/project/msml612/user/$USER
24
+ module load python/3.10.10
25
+ export PYTHONPATH=
26
+ PY=$SCR/hf_env/bin/python
27
+ cd $SCR/pcmd/src
28
+
29
+ I=$SLURM_ARRAY_TASK_ID
30
+ TASKS=(copy agree parity); OBJ=(mdlm selfcorrupt coord cmd); SEEDS=(0 1)
31
+ T=${TASKS[$((I / 8))]}
32
+ O=${OBJ[$(((I % 8) / 2))]}
33
+ S=${SEEDS[$((I % 2))]}
34
+
35
+ NAME="g2-$T-$O-s$S"
36
+ echo "=== $NAME ==="
37
+ $PY train.py --task $T --objective $O --coupling 4 --seed $S \
38
+ --seq_len 128 --n_train 200000 --n_eval 500 --eval_bs 100 \
39
+ --d 384 --layers 6 --heads 6 --bs 64 --steps 20000 --lr 3e-4 \
40
+ --alpha 0.5 --beta 1.0 --group 4 --coord_every 4 --ramp_frac 0.3 \
41
+ --out $SCR/pcmd/runs/$NAME
slurm/sm.sh ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #SBATCH -J smoke
3
+ #SBATCH -p gpu-h100
4
+ #SBATCH --gpus=h100:1
5
+ #SBATCH -c 8
6
+ #SBATCH --mem=32g
7
+ #SBATCH -t 00:25:00
8
+ #SBATCH -o logs/smoke-%j.out
9
+ source /etc/profile
10
+ SCR=/scratch/zt1/project/msml612/user/$USER
11
+ module load python/3.10.10
12
+ export PYTHONPATH=
13
+ cd $SCR/pcmd/src
14
+ for O in mdlm selfcorrupt coord cmd; do
15
+ echo "--- $O ---"
16
+ $SCR/hf_env/bin/python train.py --objective $O --task agree --coupling 4 \
17
+ --seq_len 32 --n_train 2000 --n_eval 40 --d 64 --layers 2 --heads 2 --bs 16 \
18
+ --steps 60 --group 4 --coord_every 4 --eval_bs 20 --out /tmp/sm$O 2>&1 | tail -2
19
+ done
src/diffusion.py CHANGED
@@ -37,7 +37,7 @@ def mdlm_loss(model, x0, tok, t_min=None, fixed_t=None):
37
 
38
 
39
  def self_corrupted_loss(model, x0, tok, k_frac=0.25, t_min=None,
40
- correct_weight=1.0):
41
  """OUR METHOD. Train on states that parallel decoding actually produces.
42
 
43
  1. mask as usual and take a NO-GRAD pass to get the current marginals
@@ -51,6 +51,12 @@ def self_corrupted_loss(model, x0, tok, k_frac=0.25, t_min=None,
51
 
52
  The model is therefore optimised for the distribution it meets at inference
53
  rather than for ground-truth context it will never see.
 
 
 
 
 
 
54
  """
55
  B, L = x0.shape
56
  dev = x0.device
@@ -65,7 +71,7 @@ def self_corrupted_loss(model, x0, tok, k_frac=0.25, t_min=None,
65
  samp = torch.distributions.Categorical(probs=probs).sample()
66
 
67
  # commit a random subset of masked positions from the model's own samples
68
- commit = m & (torch.rand(B, L, device=dev) < k_frac)
69
  x_self = torch.where(commit, samp, xt)
70
  still = m & ~commit
71
 
@@ -73,11 +79,11 @@ def self_corrupted_loss(model, x0, tok, k_frac=0.25, t_min=None,
73
  ce = F.cross_entropy(logits.reshape(-1, logits.size(-1)), x0.reshape(-1),
74
  reduction="none").view(B, L)
75
 
76
- denom = still.sum(1).clamp_min(1)
77
- main = ((1.0 / t) * (ce * still).sum(1) / denom).mean()
78
- # repair term: committed positions are supervised against ground truth too
79
- rep = (ce * commit).sum(1) / commit.sum(1).clamp_min(1)
80
- return main + correct_weight * rep.mean()
81
 
82
 
83
  # --------------------------------------------------------------- decoding ---
@@ -157,3 +163,79 @@ def nll_bpc(model, batches, tok, device, mc=8):
157
  tot += float(((1.0 / t) * (ce * m).sum(1) / L).sum())
158
  n += B
159
  return tot / max(n, 1) / torch.log(torch.tensor(2.0)).item()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
 
39
  def self_corrupted_loss(model, x0, tok, k_frac=0.25, t_min=None,
40
+ correct_weight=1.0, ramp=1.0):
41
  """OUR METHOD. Train on states that parallel decoding actually produces.
42
 
43
  1. mask as usual and take a NO-GRAD pass to get the current marginals
 
51
 
52
  The model is therefore optimised for the distribution it meets at inference
53
  rather than for ground-truth context it will never see.
54
+
55
+ `ramp` in [0,1] scales the corruption rate. It must start near zero: a
56
+ randomly-initialised model samples noise, so corrupting from step 0 trains
57
+ on pure garbage context and the model never learns the task at all (it
58
+ scored 0% even on copy, which the baseline solves trivially). This is the
59
+ same reason scheduled sampling anneals its mixing probability.
60
  """
61
  B, L = x0.shape
62
  dev = x0.device
 
71
  samp = torch.distributions.Categorical(probs=probs).sample()
72
 
73
  # commit a random subset of masked positions from the model's own samples
74
+ commit = m & (torch.rand(B, L, device=dev) < k_frac * ramp)
75
  x_self = torch.where(commit, samp, xt)
76
  still = m & ~commit
77
 
 
79
  ce = F.cross_entropy(logits.reshape(-1, logits.size(-1)), x0.reshape(-1),
80
  reduction="none").view(B, L)
81
 
82
+ # Normalise by L exactly as mdlm_loss does, so the two objectives are on the
83
+ # same scale and any difference in results is the method, not the loss size.
84
+ main = ((1.0 / t) * (ce * still).sum(1) / L).mean()
85
+ rep = ((1.0 / t) * (ce * commit).sum(1) / L).mean()
86
+ return main + correct_weight * rep
87
 
88
 
89
  # --------------------------------------------------------------- decoding ---
 
163
  tot += float(((1.0 / t) * (ce * m).sum(1) / L).sum())
164
  n += B
165
  return tot / max(n, 1) / torch.log(torch.tensor(2.0)).item()
166
+
167
+
168
+ def coordination_loss(model, x0, tok, group=4, t_min=None):
169
+ """CORE OF THE METHOD: make parallel sampling reproduce sequential sampling.
170
+
171
+ The measured failure: on jointly-constrained-but-individually-free positions
172
+ (our `agree` probe), each position's likelihood-optimal marginal is uniform
173
+ over the valid values, so sampling them independently is guaranteed to be
174
+ inconsistent - 0% accuracy at every parallelism, 100% only when decoded one
175
+ at a time. No decoding schedule can fix that, because the marginals
176
+ themselves carry no coordination.
177
+
178
+ So we change the marginals. For a random subset S:
179
+
180
+ teacher : decode S SEQUENTIALLY with no gradient, each position
181
+ conditioned on the ones already chosen. Because each step sees
182
+ the previous choices, the result is a coherent joint sample.
183
+ student : the marginals S gets from ONE parallel forward pass.
184
+ loss : cross-entropy of the teacher's joint sample under the student's
185
+ parallel marginals.
186
+
187
+ The model is its own teacher, so this needs no external model and works in
188
+ pretraining from scratch. It deliberately trades likelihood (marginals move
189
+ off the true conditional, toward a coordinated mode) for parallel
190
+ decodability - a trade the standard ELBO can never make.
191
+
192
+ COST: the teacher costs `group` sequential forward passes, so `group` is the
193
+ knob that keeps training affordable. An early version coordinated over 32
194
+ positions and made every step 32x more expensive, which simply never
195
+ finished. Combined with applying the term every `coord_every` steps, the
196
+ amortised overhead is roughly 1 + group/coord_every.
197
+ """
198
+ B, L = x0.shape
199
+ dev = x0.device
200
+ t_min = t_min if t_min is not None else 1.0 / L
201
+ t = t_min + (1.0 - t_min) * torch.rand(B, device=dev)
202
+ m = torch.rand(B, L, device=dev) < t[:, None]
203
+ m[torch.arange(B, device=dev), torch.randint(0, L, (B,), device=dev)] = True
204
+ xt = torch.where(m, torch.full_like(x0, tok.mask), x0)
205
+
206
+ # choose, per example, a subset S of masked positions to coordinate over
207
+ score = torch.rand(B, L, device=dev).masked_fill(~m, -1.0)
208
+ k = min(group, L)
209
+ S = score.topk(k, dim=1).indices # (B, k)
210
+
211
+ # ---- teacher: reveal S one position at a time, conditioning as we go ----
212
+ with torch.no_grad():
213
+ x_seq = xt.clone()
214
+ for j in range(k):
215
+ idx = S[:, j]
216
+ logits = model(x_seq)
217
+ pick = logits[torch.arange(B, device=dev), idx].argmax(-1)
218
+ x_seq[torch.arange(B, device=dev), idx] = pick
219
+ target = x_seq.gather(1, S) # the joint sample
220
+
221
+ # ---- student: one parallel pass over the same masked state --------------
222
+ logits = model(xt)
223
+ sel = logits.gather(1, S[..., None].expand(-1, -1, logits.size(-1)))
224
+ return F.cross_entropy(sel.reshape(-1, sel.size(-1)), target.reshape(-1))
225
+
226
+
227
+ def cmd_loss(model, x0, tok, alpha=0.5, beta=1.0, k_frac=0.25, ramp=1.0,
228
+ group=4, use_coord=True):
229
+ """Coordinated Masked Diffusion: ELBO + self-conditioning + coordination.
230
+
231
+ The ELBO term is always present. The two additions are auxiliaries, not
232
+ replacements: an earlier version used self-conditioning INSTEAD of the ELBO
233
+ and scored 35% where the plain baseline scored 100%.
234
+ """
235
+ total = mdlm_loss(model, x0, tok)
236
+ if alpha > 0 and ramp > 0:
237
+ total = total + alpha * self_corrupted_loss(
238
+ model, x0, tok, k_frac=k_frac, correct_weight=1.0, ramp=ramp)
239
+ if beta > 0 and ramp > 0 and use_coord:
240
+ total = total + beta * ramp * coordination_loss(model, x0, tok, group=group)
241
+ return total
src/train.py CHANGED
@@ -16,12 +16,23 @@ import diffusion as dfn
16
 
17
  def get_args():
18
  p = argparse.ArgumentParser()
19
- p.add_argument("--objective", choices=["mdlm", "selfcorrupt"], default="mdlm",
20
- help="mdlm = standard marginal training; selfcorrupt = ours")
 
 
 
 
 
 
 
21
  p.add_argument("--k_frac", type=float, default=0.25,
22
  help="fraction of masked positions committed from the model's "
23
  "own parallel samples during self-corrupted training")
24
  p.add_argument("--correct_weight", type=float, default=1.0)
 
 
 
 
25
  p.add_argument("--task", choices=["text8", "copy", "agree", "parity"], default="agree")
26
  p.add_argument("--coupling", type=int, default=4,
27
  help="probe tasks: how many positions are bound together")
@@ -142,10 +153,18 @@ def main():
142
  x0 = train[idx].to(dev)
143
  opt.zero_grad(set_to_none=True)
144
  with torch.autocast(**amp):
145
- loss = (dfn.self_corrupted_loss(model, x0, tok, a.k_frac,
146
- correct_weight=a.correct_weight)
147
- if a.objective == "selfcorrupt"
148
- else dfn.mdlm_loss(model, x0, tok))
 
 
 
 
 
 
 
 
149
  loss.backward()
150
  torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
151
  opt.step(); sched.step()
 
16
 
17
  def get_args():
18
  p = argparse.ArgumentParser()
19
+ p.add_argument("--objective", choices=["mdlm", "selfcorrupt", "coord", "cmd"],
20
+ default="mdlm",
21
+ help="mdlm=ELBO baseline; selfcorrupt=+self-conditioning; "
22
+ "coord=+coordination; cmd=full method (all three)")
23
+ p.add_argument("--alpha", type=float, default=0.5, help="self-conditioning weight")
24
+ p.add_argument("--beta", type=float, default=1.0, help="coordination weight")
25
+ p.add_argument("--group", type=int, default=4)
26
+ p.add_argument("--coord_every", type=int, default=4,
27
+ help="apply the coordination term every N steps; the teacher\n costs `group` sequential passes, so this amortises it")
28
  p.add_argument("--k_frac", type=float, default=0.25,
29
  help="fraction of masked positions committed from the model's "
30
  "own parallel samples during self-corrupted training")
31
  p.add_argument("--correct_weight", type=float, default=1.0)
32
+ p.add_argument("--ramp_frac", type=float, default=0.3,
33
+ help="fraction of training over which self-corruption ramps "
34
+ "from 0 to --k_frac; corrupting from step 0 trains on a "
35
+ "random model's noise and prevents learning entirely")
36
  p.add_argument("--task", choices=["text8", "copy", "agree", "parity"], default="agree")
37
  p.add_argument("--coupling", type=int, default=4,
38
  help="probe tasks: how many positions are bound together")
 
153
  x0 = train[idx].to(dev)
154
  opt.zero_grad(set_to_none=True)
155
  with torch.autocast(**amp):
156
+ ramp = min(1.0, step / max(1, a.ramp_frac * a.steps))
157
+ uc = (step % a.coord_every == 0)
158
+ if a.objective == "cmd":
159
+ loss = dfn.cmd_loss(model, x0, tok, a.alpha, a.beta, a.k_frac,
160
+ ramp, a.group, use_coord=uc)
161
+ elif a.objective == "coord":
162
+ loss = dfn.cmd_loss(model, x0, tok, 0.0, a.beta, a.k_frac,
163
+ ramp, a.group, use_coord=uc)
164
+ elif a.objective == "selfcorrupt":
165
+ loss = dfn.cmd_loss(model, x0, tok, a.alpha, 0.0, a.k_frac, ramp)
166
+ else:
167
+ loss = dfn.mdlm_loss(model, x0, tok)
168
  loss.backward()
169
  torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
170
  opt.step(); sched.step()