Skip to content

Latest commit

 

History

History
44 lines (29 loc) · 3.72 KB

File metadata and controls

44 lines (29 loc) · 3.72 KB

Statistical power: how many cases does a damage claim need?

Spec §12 makes this a precondition, not a postmortem: "算力账之外必须算统计账 … 用 bootstrap CI 宽度随 n 的收敛关系倒推所需 case 数;预算内达不到功效的对比在设计期就降级为探索性结论". This file is that calculation, run against the real v0.1.0 data rather than assumed.

Reproduce: python scripts/power_check.py

What v0.1.0 (24 cases) could actually detect: nothing

Paired bootstrap over the case set (5,000 resamples, the same estimator report.damage_records uses), qwen3-1.7b, content_correct:

chain comparison baseline quantized damage 95% CI verdict
gguf f16 → Q4_K_M 0.833 0.750 +0.083 [+0.000, +0.208] not credible — touches 0
mlx bf16 → 4bit 0.833 0.833 +0.000 [+0.000, +0.000] no damage detected

(lenient tier. The strict tier gives the identical CI: it is the same two cases that flip. Strict scores every function_call case 0 by construction — that gap is the parser-gap signal, not a scoring bug — so 8 of the 24 cases are constant there and carry no information about damage either way.)

Only 2 of 24 cases discriminate f16 from Q4_K_M. The width of the CI is driven by that discordant count, not by the accuracy level — which is why a headline like "Q4 costs you 8 points" was not sayable at n=24, and was correctly reported as inconclusive.

Required n, by effect size

Simulated: paired differences drawn at the stated discordance rates, 5,000-resample bootstrap per trial, 400 trials per cell, requiring the 95% CI lower bound to clear 0 in ≥90% of trials.

true (net) damage reverse flips (quant beats baseline) cases needed
0.05 0% 140
0.05 10% >400
0.10 0% 68
0.10 10% 304
0.15 0% 48
0.15 10% 152

Reverse flips do not cancel out. They leave the mean damage where it was and widen the CI, so a 10% reverse-flip rate costs 4–5× the sample size — which is why the column exists, and why the required n must be recomputed against the measured flip rate rather than read off the optimistic column.

Spec §12 anticipates effect sizes of 0.05–0.10. So the pack needs to be on the order of 140 cases, and the measured f16→Q4_K_M damage (+0.083) sits exactly in the band that 24 cases cannot resolve.

Reverse flips are the dominant unknown. At Q4 there were none (2 discordant, both baseline-right). At Q2_K/Q3_K_M — the tiers experiments 2 and 3 are actually about — noise cuts both ways and the required n climbs steeply. Recompute this table against the measured flip rate once the full ladder has run; do not assume the 0% column.

Consequences, applied

  1. The pack grows to 150 single-turn cases (v0.6.0, 18 → 150). Not "more is better" — 150 is what a 0.05–0.10 effect costs.
  2. Damage at Q5_K_M/Q8_0 will likely stay inconclusive, and that is a result, not a failure: the honest statement is a bound ("no damage detectable above ±0.07"), which is what a deployer asking "is Q8 safe?" actually needs.
  3. dev/test halves have ~75 cases each, enough for ~0.10 but not 0.05. So the split is applied where spec §6 requires it — prescribe selects on dev, confirm reports on test — and not to the Section A damage tables, which select nothing and therefore have nothing to overfit. A damage number is a measurement; a prescription is a choice. Only the choice needs holding out.
  4. Every run that predates the v0.6.0 pack is not comparable to one after it: the pack's sha256 is in the report header for exactly this reason, and scripts/rescore_report.py refuses to rescore across pack versions.