add padding-trigger ablation for the 4096-cap parity bug
Browse files- diag/diagnose_padding_trigger.py +55 -26
diag/diagnose_padding_trigger.py
CHANGED
|
@@ -102,17 +102,6 @@ def main() -> None:
|
|
| 102 |
n_r = int(lengths[r])
|
| 103 |
lone_ids = ids[r:r + 1, :n_r].clone()
|
| 104 |
|
| 105 |
-
with torch.inference_mode():
|
| 106 |
-
ref = model(input_ids=lone_ids.cuda(), use_cache=False).logits[0]
|
| 107 |
-
|
| 108 |
-
def forward_row(x, a, positions):
|
| 109 |
-
with torch.inference_mode():
|
| 110 |
-
out = model(input_ids=x.cuda(),
|
| 111 |
-
attention_mask=(a.cuda() if a is not None else None),
|
| 112 |
-
position_ids=(positions.cuda() if positions is not None else None),
|
| 113 |
-
use_cache=False).logits
|
| 114 |
-
return out[r] if out.dim() == 3 else out[0]
|
| 115 |
-
|
| 116 |
def positions_for(a):
|
| 117 |
p = a.long().cumsum(-1) - 1
|
| 118 |
p.masked_fill_(a == 0, 1)
|
|
@@ -168,26 +157,66 @@ def main() -> None:
|
|
| 168 |
pad_ids[0, :n_r] = ids[r, :n_r]
|
| 169 |
pad_attn[0, :n_r] = 1
|
| 170 |
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
]
|
| 180 |
variants: dict[str, dict[str, Any]] = {}
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
|
|
|
|
|
|
| 188 |
torch.cuda.empty_cache()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
print("TRIGGER_VARIANT=" + json.dumps({"variant": name, **variants[name]},
|
| 190 |
sort_keys=True), flush=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
report["variants"] = variants
|
| 193 |
ranked = sorted((v["max_abs_dlogit"], k) for k, v in variants.items())
|
|
|
|
| 102 |
n_r = int(lengths[r])
|
| 103 |
lone_ids = ids[r:r + 1, :n_r].clone()
|
| 104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
def positions_for(a):
|
| 106 |
p = a.long().cumsum(-1) - 1
|
| 107 |
p.masked_fill_(a == 0, 1)
|
|
|
|
| 157 |
pad_ids[0, :n_r] = ids[r, :n_r]
|
| 158 |
pad_attn[0, :n_r] = 1
|
| 159 |
|
| 160 |
+
n_rows = int(ids.shape[0])
|
| 161 |
+
# One reference per row: that row forwarded alone, no mask and no position_ids.
|
| 162 |
+
# This is the semantics SGLang serves, and it is what the fix must reproduce.
|
| 163 |
+
refs: list[Any] = []
|
| 164 |
+
for i in range(n_rows):
|
| 165 |
+
n_i = int(lengths[i])
|
| 166 |
+
with torch.inference_mode():
|
| 167 |
+
refs.append(model(input_ids=ids[i:i + 1, :n_i].cuda(),
|
| 168 |
+
use_cache=False).logits[0])
|
| 169 |
+
torch.cuda.empty_cache()
|
| 170 |
+
|
| 171 |
+
plans: list[tuple[str, Any, Any, Any, list[int]]] = [
|
| 172 |
+
("base", ids, attn, pos_stored, list(range(n_rows))),
|
| 173 |
+
("base_nopos", ids, attn, None, list(range(n_rows))),
|
| 174 |
+
("pad_zero", torch.where(attn.bool(), ids, torch.zeros_like(ids)), attn,
|
| 175 |
+
pos_stored, list(range(n_rows))),
|
| 176 |
+
("attn_prefix", ids, prefix, None, list(range(n_rows))),
|
| 177 |
+
("attn_all_ones", ids, torch.ones_like(attn), None, list(range(n_rows))),
|
| 178 |
+
("long_only_pad", pad_ids, pad_attn, None, [r]),
|
| 179 |
+
("long_only", lone_ids, torch.ones_like(lone_ids), None, [r]),
|
| 180 |
]
|
| 181 |
variants: dict[str, dict[str, Any]] = {}
|
| 182 |
+
per_variant_row: dict[str, dict[str, Any]] = {}
|
| 183 |
+
for name, x, a, p, row_map in plans:
|
| 184 |
+
with torch.inference_mode():
|
| 185 |
+
out = model(input_ids=x.cuda(),
|
| 186 |
+
attention_mask=(a.cuda() if a is not None else None),
|
| 187 |
+
position_ids=(p.cuda() if p is not None else None),
|
| 188 |
+
use_cache=False).logits
|
| 189 |
+
out3 = out if out.dim() == 3 else out.unsqueeze(0)
|
| 190 |
+
del out
|
| 191 |
torch.cuda.empty_cache()
|
| 192 |
+
per_variant_row[name] = {}
|
| 193 |
+
for j, capture_row in enumerate(row_map):
|
| 194 |
+
n_i = int(lengths[capture_row])
|
| 195 |
+
d = max_logit_delta(out3[j, :n_i], refs[capture_row])
|
| 196 |
+
per_variant_row[name][str(capture_row)] = d
|
| 197 |
+
print("TRIGGER_VARIANT_ROW=" + json.dumps(
|
| 198 |
+
{"variant": name, "row": capture_row, "length": n_i,
|
| 199 |
+
"max_abs_dlogit": d["max_abs_dlogit"],
|
| 200 |
+
"mean_abs_dlogit": round(d["mean_abs_dlogit"], 6)}, sort_keys=True),
|
| 201 |
+
flush=True)
|
| 202 |
+
del out3
|
| 203 |
+
torch.cuda.empty_cache()
|
| 204 |
+
# Headline = the longest row, which is the one the parity guard trips on.
|
| 205 |
+
variants[name] = per_variant_row[name][str(r)]
|
| 206 |
print("TRIGGER_VARIANT=" + json.dumps({"variant": name, **variants[name]},
|
| 207 |
sort_keys=True), flush=True)
|
| 208 |
+
del refs
|
| 209 |
+
torch.cuda.empty_cache()
|
| 210 |
+
report["per_variant_row"] = per_variant_row
|
| 211 |
+
# Does dropping position_ids reproduce the per-row reference for EVERY row?
|
| 212 |
+
fixed = {k: round(v["max_abs_dlogit"], 6)
|
| 213 |
+
for k, v in per_variant_row.get("base_nopos", {}).items()}
|
| 214 |
+
broken = {k: round(v["max_abs_dlogit"], 6)
|
| 215 |
+
for k, v in per_variant_row.get("base", {}).items()}
|
| 216 |
+
report["fix_check"] = {"base_max_per_row": broken, "base_nopos_max_per_row": fixed,
|
| 217 |
+
"fix_removes_the_effect_on_all_rows":
|
| 218 |
+
all(v == 0.0 for v in fixed.values()) if fixed else None}
|
| 219 |
+
print("TRIGGER_FIX_CHECK=" + json.dumps(report["fix_check"], sort_keys=True), flush=True)
|
| 220 |
|
| 221 |
report["variants"] = variants
|
| 222 |
ranked = sorted((v["max_abs_dlogit"], k) for k, v in variants.items())
|