Skip to content

EVAL ONLY (do not merge): microsoft/BitNet#633 against the I2_S kernel tests - #9

Closed
eejd wants to merge 9 commits into
mainfrom
eval/pr-633
Closed

eejd wants to merge 9 commits into
mainfrom
eval/pr-633

Conversation

@eejd

@eejd eejd commented Oct 31, 2026

Copy link
Copy Markdown
Owner

Evaluation only – do not merge. gh pr diff 633 --repo microsoft/BitNet applied unmodified on top of test/i2s-correctness-gate.

Result on Apple M6:

eejd added 9 commits October 31, 2026 13:11
…el needed)

utils/test_gemm_kernel.sh is a timing benchmark on random data and never
checks a result (it also needs Linux-only -fopenmp/clock_gettime/libggml.so).
Add utils/i2s_kernel_test/: a standalone test that compares

  L0 dequantize_row_i2_s / quantize_i2_s against the documented 128-weight /
     32-byte I2_S layout,
  L1 ggml_gemv_i2_i8_s / ggml_gemm_i2_i8_s against sum(code*y),
  L2 ggml_mul_mat(I2_S, F32) end to end (int8 activation quantization,
     act-sum correction, weight scale) at 1 and 4 threads,

for K/M/N including the BitNet b1.58 2B4T shapes (K=2560, 6912).
run.sh builds it against a static ggml build tree; --mad additionally
compiles src/ggml-bitnet-mad.cpp (not part of the CMake build) so the
kernels patched by microsoft#586/microsoft#633 can be tested.

Refs #3
The first draft used rel-L2 < 0.03 against float W@x. With an activation
outlier (amax/rms ~ 20) the int8 absmax quantization alone gives ~4-8 %,
so the fixed bound flagged a bit-exact kernel (L2 emulation error ~1e-7).
Use 4 * (amax/rms) / (127*sqrt(12)), derived from the quantization step,
and keep the primary check (exact emulation, 1e-4) unchanged.

Refs #3
…el-level run

tolerances.json fixes, with rationale, how close the engine must be to the
mlx_lm bitnet reference: teacher-forced top-1 agreement / KL / cosine,
free-running greedy prefix, and a perplexity ratio on a fixed text.
compare.py implements them; test_compare.py checks on synthetic data that
documented int8-activation noise passes and that scrambled weights,
constant output, NaN/Inf/1e27 garbage, flattened distributions and
perplexity blow-ups fail.

No GGUF or reference weights existed on the host when this was written.
Refs #3
…estrator, synthetic model, README

run_gate.py exits 3 (BLOCKED, with the list of missing files) when the
official GGUF or the reference weights are not present locally; it never
downloads. engine_logits dumps per-position logits through libllama on the
CPU and records llama_print_system_info(). make_synthetic_model.py writes a
tiny random BitNet in mlx and GGUF(I2_S) form from the same ternary weights
so the plumbing can be tested without the real checkpoint.

Refs #3
…capped

Documented post-hoc change. v1 used a fixed 0.25-logit near-tie margin. The
first synthetic end-to-end run (llama.cpp#6 kernel + relu2 vs mlx_lm) passed
every teacher-forced and perplexity check (top-1 0.972, mean KL 0.0028, min
cosine 0.9993, |ln ppl ratio| 0.0197 vs bound 0.02) but failed one of five
free-running greedy checks: a flip at reference margin 0.446 while the
measured margin-error sigma is ~0.15.

v2 uses max(0.25, 4*sigma) with sigma measured in the same run, and fails
outright if sigma > 10 % of the reference logit std, so an engine that is
wrong by O(1) can never excuse itself (unit-tested). When the cap is
exceeded the band falls back to the 0.25 floor so top-1 agreement stays
meaningful. Everything else (KL, cosine, perplexity bounds) is unchanged.
v1 results are kept in the evidence directory.

Refs #3
The official ggml-model-i2_s.gguf has no tokenizer.ggml.pre key, so llama.cpp falls back to the
'default' pre-tokenizer and splits e.g. "(n):\n" differently from the Llama-3 tokenizer the model was
trained with (engine ids 7,77,1680,198 vs reference 1471,997 for 'def fibonacci(n):\n'). With
tokenizer.ggml.pre=llama-bpe the engine reproduces the reference ids exactly (also checked against a
Llama-3.2 GGUF that carries the key). The tokenizer-parity check therefore fails on the unmodified
official GGUF; the gate can pass --override-pre llama-bpe to the engine to judge the numerics separately.

Refs #3
…tize tests

synthetic-f32.gguf carries the same ternary*scale values as float so that
'llama-quantize --token-embedding-type f16 f32.gguf out.gguf I2_S 1' (what setup_env.py does) can be
compared byte-for-byte with the canonical I2_S packing in synthetic-i2s.gguf.
…odified

Evaluation branch only. Diff taken verbatim from 'gh pr diff 633 --repo microsoft/BitNet'.
@eejd

eejd commented Nov 1, 2026

Copy link
Copy Markdown
Owner Author

Closing without merging: evaluation only. Results are recorded in #6 (merged) and the closed issue #3. Fix that went to main: #7.

@eejd eejd closed this Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant