Files
ds4/misc/qwen-drift-2026-10-03/run-dense-ab.py
T
Giorgio Oppo 575369b19d Research: isolate Qwen prefill arithmetic and token drift
Archive the investigation of PR #1056 comment 5963229415 comparing main
0aaea5a with 02313128 on M4 Max/Q2 resident. Trace the device-independent
prefill policy introduced by 2d6a207b: small F16/Q8 prompt batches change
operand precision, while GDN alpha/beta F32 projections stop using split-K.
Distinguish this policy from the numerically neutral M2-M4 tuning gate,
89986c3c attention partitions and the secondary HC arithmetic candidate.

Record ten full-vocabulary captures and four 64-step greedy comparisons
from one frozen HEAD snapshot on M1 Max/Q4/SSD, with inherited DS4 flags
removed. Restoring only F32 split-K changes the 575-token frontier by
0.41702342; restoring the complete dense policy produces identical logits
on that fixture. The 29/575 repeated HEAD controls are byte-identical.
The 5942-token tail-only split ablation changes logits by 0.33132219.

With ordinary T1 decode policy held constant, the dense-policy ablation
changes the first generated token at step 59 for Rome29 and step 20 for
book575. Preserve raw logits, top-20 logprobs, logs, token-ID fixtures,
commands, source hashes and independent provenance/numerical audits.
These fixtures do not reproduce the tester's exact M4/Q2 prompts or
attribute every component of the reported deltas; they are not quality
or performance evaluations.

Provide a preparation script that recreates 103 tracked source files from
0231312820, applies the isolated diagnostic
patch and verifies all source hashes. Add fresh snapshot/output arguments
to both runners and document serial reproduction using the local Q4 GGUF.
Keep generated snapshot copies, executables and object files outside Git.

Validation:
- Independent recalculation of all ten 248320-logit dumps and greedy
  common prefixes, selected token IDs and bytes passed.
- Preparation in a fresh temporary directory reproduced all 103 source
  hashes and applied only the reviewed diagnostic patch.
- Python AST/JSON parsing and both runner help commands passed.
- git diff --cached --check passed.

This commit archives research only; pending production optimization
experiments remain outside its scope. No production dispatch is changed.
2026-10-03 09:21:17 +02:00

49 lines
3.8 KiB
Python

from pathlib import Path
import argparse
import hashlib, json, os, subprocess, time, struct, math, re
lane = Path(__file__).resolve().parent
repo = lane.parents[1]
parser = argparse.ArgumentParser(description="Repeat the isolated dense prefill ablation on a local Q4 GGUF.")
parser.add_argument("--snapshot", default="head", help="Snapshot directory, relative to this archive or absolute")
parser.add_argument("--output", default="dense-ab", help="Fresh output directory, relative to this archive or absolute")
args = parser.parse_args()
head = (lane / args.snapshot).resolve()
out = (lane / args.output).resolve()
out.mkdir(exist_ok=False)
env = {k:v for k,v in os.environ.items() if not k.startswith("DS4_")}
env["DS4_DIAG_TRACE_PREFILL_DENSE"] = "1"
arms = {"head": {}, "base_dense": {"DS4_DIAG_BASE_PREFILL_DENSE":"1"}, "base_split": {"DS4_DIAG_BASE_PREFILL_SPLIT_ONLY":"1"}}
report = {"scope":"same committed HEAD snapshot with diagnostic dense policies; M1 Max Q4 SSD; not M4 Q2 replication", "runs":[], "comparisons":[]}
source_paths = [head / "ds4", head / "ds4.c", head / "ds4_metal.m", *sorted((head / "metal").glob("*.metal"))]
report["source_sha256"] = {str(p):hashlib.sha256(p.read_bytes()).hexdigest() for p in source_paths}
references = {}
schedule = [(name,arm) for name in ("rome29","book575") for arm in ("head","base_dense","base_split","head_repeat")] + [("book5942",arm) for arm in ("head","base_split")]
for name,arm in schedule:
run_env = env | arms["head" if arm == "head_repeat" else arm]
target = out / f"{name}-{arm}.json"
cmd = [str(head / "ds4"), "-m", str(repo / "gguf/Qwen3.8-Flash-Next-Q4.gguf"), "--metal", "--ssd-streaming", "--ctx", "16384", "--prefill-chunk", "2048", "--nothink", "--temp", "0", "--prompt-file", str(lane / "fixtures" / (name + ".txt")), "--dump-logits", str(target)]
print("START", name, arm, flush=True)
started = time.monotonic()
with (out / f"{name}-{arm}.log").open("wb") as log:
rc = subprocess.run(cmd, cwd=head, env=run_env, stdout=log, stderr=subprocess.STDOUT).returncode
assert rc == 0 and target.is_file(), (name,arm,rc)
data = json.loads(target.read_text())
assert data["vocab"] == len(data["logits"]) == 248320
assert data["prompt_tokens"] == int(re.search(r"(\d+)$",name).group(1))
assert all(x is not None and math.isfinite(x) for x in data["logits"])
bits = b"".join(struct.pack("<f",x) for x in data["logits"])
row = {"name":name,"arm":arm,"seconds":time.monotonic()-started,"command":cmd,"env":{k:v for k,v in run_env.items() if k.startswith("DS4_")},"prompt_tokens":data["prompt_tokens"],"argmax":data["argmax_token"],"argmax_logit":data["argmax_logit"],"float32_sha256":hashlib.sha256(bits).hexdigest()}
report["runs"].append(row)
if arm == "head": references[name] = data
else:
ref = references[name]; delta=[abs(a-b) for a,b in zip(ref["logits"],data["logits"])]
comparison = {"name":name,"arm":arm,"max_abs":max(delta),"max_abs_token":delta.index(max(delta)),"mean_abs":sum(delta)/len(delta),"different_float32":sum(struct.pack("<f",a)!=struct.pack("<f",b) for a,b in zip(ref["logits"],data["logits"])),"same_argmax":ref["argmax_token"]==data["argmax_token"],"json_identical":(out / f"{name}-head.json").read_bytes()==target.read_bytes()}
report["comparisons"].append(comparison)
if arm == "head_repeat": assert comparison["json_identical"], "control not repeatable"
print("COMPARE",json.dumps(comparison),flush=True)
assert all(hashlib.sha256(p.read_bytes()).hexdigest()==report["source_sha256"][str(p)] for p in source_paths)
(out / "results.json").write_text(json.dumps(report,indent=2)+"\n")
print("DONE",name,arm,round(row["seconds"],2),flush=True)
report["status"]="COMPLETE"
(out / "results.json").write_text(json.dumps(report,indent=2)+"\n")