feat(qwen38): fold the calibration tap's Grams into libquant's imatrix GGUF
rad-convert's GPTQ path reads importance from an imatrix GGUF; the reference container's --kld-record pass emits per-expert and per-hidden Grams as raw recordings. This folds them into one v3 file: a single expert-major f32 entry per MoE layer plus the hidden-width entries, every data offset a multiple of general.alignment as the loader requires. Refusals, each one a silent-worse outcome the swift15 campaign hit: an expert with no gram of its own carries the layer's pooled diagonal and the count is reported (a silent zero is a down-quantized expert nobody priced); expert grams with no pooled gram, a gram short by one float (names the file), the same global expert recorded twice with different numbers, an empty recording directory, and an existing output. --min-rows sets the noise floor below which a recording is dropped. rows is u64 so a corpus that outgrows u32 survives the header instead of wrapping.
This commit is contained in:
1 parent
c13a2568d4
commit
3d8d18a45c
2 files changed
+863
No files matched your search
Executable
+445
@@ -0,0 +1,445 @@
|
||||
#!/usr/bin/env bats
|
||||
# Seam: scripts/grams-to-imatrix.py — the calibration recording (RADGRAM2 grams)
|
||||
# folded into the GGUF v3 imatrix `rad-convert --imatrix F` reads.
|
||||
#
|
||||
# The only contract that matters is the reader's: core/format/imatrix.cpp joins
|
||||
# `<base>.in_sum2` with `<base>.counts`, takes cols from in_sum2 dims[0] and
|
||||
# n_expert from dims[1], demands ggml f32 tensors and GGUF version 3, and
|
||||
# silently IGNORES an entry whose width does not match the weight it is asked
|
||||
# about. So every test here parses the artifact back with its own tiny GGUF
|
||||
# reader and asserts bytes — a file that merely exists and exits 0 proves
|
||||
# nothing about a quantiser that will read it hours later on another machine.
|
||||
#
|
||||
# Fixtures are synthetic: k=4 grams with real RADGRAM2 headers (rows is a u64
|
||||
# at offset 16 — pack it as u32 and 100 rows read back as 4294967296000) and
|
||||
# real f32 payloads whose OFF-DIAGONAL is filled with 99.0, so an entry built
|
||||
# from anything but the diagonal is instantly visible. Expected numbers are
|
||||
# worked examples from the fixture tables below, never recomputed the way the
|
||||
# tool computes them.
|
||||
|
||||
load helpers
|
||||
|
||||
TOOL="$REPO_ROOT/scripts/grams-to-imatrix.py"
|
||||
|
||||
# make_gram <path> <k> <rank> <rows> <domain> <diag,csv>
|
||||
# A RADGRAM2 file: 32-byte header <8sIIQI (magic, k, rank, rows, domain, pad)
|
||||
# then k*k f32 row-major. Off-diagonals are 99.0 — a sentinel, not data.
|
||||
make_gram() {
|
||||
python3 - "$@" <<'PY'
|
||||
import struct, sys
|
||||
path, k, rank, rows, domain = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), \
|
||||
int(sys.argv[4]), int(sys.argv[5])
|
||||
diag = [float(x) for x in sys.argv[6].split(",")]
|
||||
assert len(diag) == k, "diagonal must hold k values"
|
||||
vals = [99.0] * (k * k)
|
||||
for i, d in enumerate(diag):
|
||||
vals[i * k + i] = d
|
||||
hdr = struct.pack("<8sIIQI", b"RADGRAM2", k, rank, rows, domain) + struct.pack("<I", 0)
|
||||
with open(path, "wb") as f:
|
||||
f.write(hdr + struct.pack("<%df" % (k * k), *vals))
|
||||
PY
|
||||
}
|
||||
|
||||
# full_recording <dir> — the fixture every happy-path test reads.
|
||||
#
|
||||
# layer 0 (k=4, own-gram floor 4*k = 16 rows):
|
||||
# pooled r0 rows 40 diag 1,2,3,4 + r1 rows 8 diag .5,.5,.5,.5
|
||||
# -> summed gram (the engine's calib_sum law): diag 1.5,2.5,3.5,4.5,
|
||||
# pooled rows 48
|
||||
# expert 0 r0 rows 100 diag 10,20,30,40 (>= 16: own gram kept)
|
||||
# expert 1 r0 rows 3 diag 7,7,7,7 (< 16: inherits pooled)
|
||||
# expert 2 r1 rows 64 diag 1,1,1,2 (>= 16: own gram kept)
|
||||
# expert 3 no file at all (inherits pooled, count 0)
|
||||
# expert 4 r1 rows 100 diag 5,6,7,8 (>= 16: own gram kept)
|
||||
# -> n_expert 5, counts 100 3 64 0 100, inherited 2, routing 267
|
||||
# layer 1: pooled r0 rows 48 diag 2,2,2,2 ; expert 0 on r1 rows 48 diag 1,1,1,1
|
||||
# -> n_expert 1, counts 48, inherited 0, routing 48
|
||||
# Corpus rows = the largest single-layer pooled rows = 48.
|
||||
full_recording() {
|
||||
local d="$1"
|
||||
mkdir -p "$d"
|
||||
make_gram "$d/gram.r0.blk.0.ffn_down_exps.bin" 4 0 40 0 "1,2,3,4"
|
||||
make_gram "$d/gram.r1.blk.0.ffn_down_exps.bin" 4 1 8 0 "0.5,0.5,0.5,0.5"
|
||||
make_gram "$d/gram.r0.blk.0.ffn_down_exps.0.bin" 4 0 100 0 "10,20,30,40"
|
||||
make_gram "$d/gram.r0.blk.0.ffn_down_exps.1.bin" 4 0 3 0 "7,7,7,7"
|
||||
make_gram "$d/gram.r1.blk.0.ffn_down_exps.2.bin" 4 1 64 0 "1,1,1,2"
|
||||
make_gram "$d/gram.r1.blk.0.ffn_down_exps.4.bin" 4 1 100 0 "5,6,7,8"
|
||||
make_gram "$d/gram.r0.blk.1.ffn_down_exps.bin" 4 0 48 0 "2,2,2,2"
|
||||
make_gram "$d/gram.r1.blk.1.ffn_down_exps.0.bin" 4 1 48 0 "1,1,1,1"
|
||||
}
|
||||
|
||||
# gguf_read <file> [vals <tensor> <float-index> <count>] — an independent GGUF
|
||||
# v3 reader: KV block, tensor infos, and (on request) the f32 values behind a
|
||||
# tensor's own declared offset. Prints KV/HDR/TENSOR lines. Nothing here shares
|
||||
# code with the writer, which is the only reason the byte assertions mean
|
||||
# anything: imatrix.cpp walks the same three structures.
|
||||
gguf_read() {
|
||||
python3 - "$@" <<'PY'
|
||||
import struct, sys
|
||||
d = open(sys.argv[1], "rb").read()
|
||||
def u32(o): return struct.unpack_from("<I", d, o)[0]
|
||||
def u64(o): return struct.unpack_from("<Q", d, o)[0]
|
||||
def st(o):
|
||||
n = u64(o)
|
||||
return d[o + 8:o + 8 + n].decode(), o + 8 + n
|
||||
assert d[:4] == b"GGUF", "magic is %r" % d[:4]
|
||||
ver, n_t, n_kv = u32(4), u64(8), u64(16)
|
||||
p, align, out = 24, 32, []
|
||||
for _ in range(n_kv):
|
||||
key, p = st(p)
|
||||
ty = u32(p); p += 4
|
||||
if ty == 4: # uint32
|
||||
v = u32(p); p += 4
|
||||
if key == "general.alignment":
|
||||
align = v
|
||||
elif ty == 8: # string
|
||||
v, p = st(p)
|
||||
elif ty == 9: # array
|
||||
et = u32(p); n = u64(p + 4); p += 12
|
||||
got = []
|
||||
for _i in range(n):
|
||||
if et != 8:
|
||||
raise SystemExit("kv array element type %d" % et)
|
||||
s, p = st(p)
|
||||
got.append(s)
|
||||
v = ",".join(got)
|
||||
else:
|
||||
raise SystemExit("kv type %d is not steppable" % ty)
|
||||
out.append("KV %s %s" % (key, v))
|
||||
tens = []
|
||||
for _ in range(n_t):
|
||||
name, p = st(p)
|
||||
nd = u32(p); p += 4
|
||||
dims = [u64(p + 8 * i) for i in range(nd)]; p += 8 * nd
|
||||
ty = u32(p); off = u64(p + 4); p += 12
|
||||
tens.append((name, dims, ty, off))
|
||||
ds = (p + align - 1) // align * align
|
||||
out.append("HDR version=%d n_tensors=%d n_kv=%d alignment=%d data_start=%d"
|
||||
% (ver, n_t, n_kv, align, ds))
|
||||
for name, dims, ty, off in tens:
|
||||
out.append("TENSOR %s %s %d %d" % (name, "x".join(str(x) for x in dims), ty, off))
|
||||
if len(sys.argv) > 2 and sys.argv[2] == "vals":
|
||||
name, i0, n = sys.argv[3], int(sys.argv[4]), int(sys.argv[5])
|
||||
for nm, dims, ty, off in tens:
|
||||
if nm == name:
|
||||
base = ds + off
|
||||
vals = [("%d" % v) if float(v).is_integer() else repr(v)
|
||||
for v in (struct.unpack_from("<f", d, base + 4 * (i0 + i))[0]
|
||||
for i in range(n))]
|
||||
out.append("VALS %s %s" % (name, " ".join(vals)))
|
||||
print("\n".join(out))
|
||||
PY
|
||||
}
|
||||
|
||||
# aligned_offsets <file> — exit 0 iff the data section starts aligned AND every
|
||||
# tensor's absolute data offset (data_start + t.off) is a multiple of
|
||||
# general.alignment. This is the writer bug that no value assertion can see: an
|
||||
# unaligned offset makes the reader's extent arithmetic land mid-float in the
|
||||
# previous tensor, and it reads the result without complaining.
|
||||
aligned_offsets() {
|
||||
python3 - "$1" <<'PY'
|
||||
import struct, sys
|
||||
d = open(sys.argv[1], "rb").read()
|
||||
def u32(o): return struct.unpack_from("<I", d, o)[0]
|
||||
def u64(o): return struct.unpack_from("<Q", d, o)[0]
|
||||
def st(o):
|
||||
n = u64(o)
|
||||
return d[o + 8:o + 8 + n].decode(), o + 8 + n
|
||||
ver, n_t, n_kv = u32(4), u64(8), u64(16)
|
||||
p, align = 24, 32
|
||||
for _ in range(n_kv):
|
||||
key, p = st(p)
|
||||
ty = u32(p); p += 4
|
||||
if ty == 4:
|
||||
v = u32(p); p += 4
|
||||
if key == "general.alignment":
|
||||
align = v
|
||||
if ty == 8:
|
||||
_v, p = st(p)
|
||||
elif ty == 9:
|
||||
et = u32(p); n = u64(p + 4); p += 12
|
||||
for _i in range(n):
|
||||
if et == 8:
|
||||
_v, p = st(p)
|
||||
elif et == 4:
|
||||
p += 4
|
||||
else:
|
||||
raise SystemExit("kv array element type %d" % et)
|
||||
elif ty in (0, 1):
|
||||
p += 1
|
||||
elif ty in (2, 3):
|
||||
p += 2
|
||||
elif ty in (5, 6):
|
||||
p += 4
|
||||
elif ty in (10, 11, 12):
|
||||
p += 8
|
||||
tens = []
|
||||
for _ in range(n_t):
|
||||
name, p = st(p)
|
||||
nd = u32(p); p += 4
|
||||
p += 8 * nd
|
||||
ty = u32(p); off = u64(p + 4); p += 12
|
||||
tens.append((name, ty, off))
|
||||
ds = (p + align - 1) // align * align
|
||||
bad = [] if ds % align == 0 else ["data_start=%d" % ds]
|
||||
bad += ["%s=%d" % (nm, ds + off) for nm, _ty, off in tens if (ds + off) % align]
|
||||
if bad:
|
||||
print("UNALIGNED", ";".join(bad))
|
||||
sys.exit(1)
|
||||
print("ALIGNED %d tensor(s), data_start=%d, alignment=%d" % (len(tens), ds, align))
|
||||
PY
|
||||
}
|
||||
|
||||
# --- the artifact -----------------------------------------------------------
|
||||
|
||||
@test "a complete recording becomes a GGUF v3 file and the run reports itself" {
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im.gguf" \
|
||||
--datasets calib,chat --chunk-size 16
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"IMATRIX_OK"* ]]
|
||||
head -c 4 "$BATS_TEST_TMPDIR/im.gguf" | grep -q "GGUF"
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[[ "$output" == *"HDR version=3"* ]]
|
||||
# The reader refuses anything but version 3, so this is the whole gate.
|
||||
[[ "$output" != *"version=2"* ]]
|
||||
# Everything the reader looks for by key, and the honesty of the chunk math:
|
||||
# 48 corpus rows over 16-row chunks is 3 chunks.
|
||||
[[ "$output" == *"KV general.alignment 32"* ]]
|
||||
[[ "$output" == *"KV imatrix.chunk_size 16"* ]]
|
||||
[[ "$output" == *"KV imatrix.chunk_count 3"* ]]
|
||||
[[ "$output" == *"KV imatrix.datasets calib,chat"* ]]
|
||||
[[ "$output" == *"n_tensors=12"* ]]
|
||||
}
|
||||
|
||||
@test "the reader finds the folded MoE entry: one per layer, expert-major, f32" {
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[ "$status" -eq 0 ]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf"
|
||||
# dims (k, n_expert) with k fastest, ggml type 0 (f32) or the entry is
|
||||
# warned away, and 5 experts because the fixture's largest global id is 4.
|
||||
[[ "$output" == *"TENSOR blk.0.ffn_down_exps.in_sum2 4x5 0 "* ]]
|
||||
[[ "$output" == *"TENSOR blk.0.ffn_down_exps.counts 1x5 0 "* ]]
|
||||
# counts are the routing rows, not the energy trace: 100 3 64 0 100.
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.counts 0 5
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.counts 100 3 64 0 100"* ]]
|
||||
# Expert 0 (floats 0..3) and expert 4 (floats 16..19) carry their own
|
||||
# matrices' diagonals; the 99.0 off-diagonal fill appears nowhere.
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.in_sum2 0 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.in_sum2 10 20 30 40"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.in_sum2 16 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.in_sum2 5 6 7 8"* ]]
|
||||
[[ "$output" != *"99"* ]]
|
||||
}
|
||||
|
||||
@test "an expert with no own gram carries the pooled diagonal, and the count of them is reported" {
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"inherited=2"* ]]
|
||||
# Expert 1 has a gram (3 rows, under the 4*k floor) and expert 3 has none at
|
||||
# all; both slices must be the POOLED diag 1+0.5, 2+0.5, 3+0.5, 4+0.5.
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.in_sum2 4 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.in_sum2 1.5 2.5 3.5 4.5"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.in_sum2 12 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.in_sum2 1.5 2.5 3.5 4.5"* ]]
|
||||
# Their counts stay their own routing: 3 for the under-threshold expert, 0
|
||||
# for the unrecorded one — popularity is count's job, never the gram's.
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_down_exps.counts 1 3
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.counts 3 64 0"* ]]
|
||||
# The census is a report for the operator, so it belongs on stderr. `run`
|
||||
# folds both streams into $output, so a second run into a different -o (an
|
||||
# existing output is refused by design) captures stderr alone: without the
|
||||
# stderr write there is no file to grep and this assertion goes red.
|
||||
python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im2.gguf" 2>"$BATS_TEST_TMPDIR/err"
|
||||
[ -s "$BATS_TEST_TMPDIR/err" ]
|
||||
grep -q "inherited=2" "$BATS_TEST_TMPDIR/err"
|
||||
}
|
||||
|
||||
@test "the hidden-width entries are the same bytes, and nothing else is emitted" {
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[ "$status" -eq 0 ]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf"
|
||||
# gate_up shares the down matrices (same hidden-state rows), so its slice 4
|
||||
# must read 5 6 7 8 at its own tensor info's offset.
|
||||
[[ "$output" == *"TENSOR blk.0.ffn_gate_up_exps.in_sum2 4x5 0 "* ]]
|
||||
[[ "$output" == *"TENSOR blk.0.ssm_inz.in_sum2 4 0 "* ]]
|
||||
[[ "$output" == *"TENSOR blk.0.ssm_inz.counts 1 0 "* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ffn_gate_up_exps.in_sum2 16 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_gate_up_exps.in_sum2 5 6 7 8"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ssm_inz.in_sum2 0 4
|
||||
[[ "$output" == *"VALS blk.0.ssm_inz.in_sum2 1.5 2.5 3.5 4.5"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/im.gguf" vals blk.0.ssm_inz.counts 0 1
|
||||
[[ "$output" == *"VALS blk.0.ssm_inz.counts 48"* ]]
|
||||
# The stop rule: importance_for() false-on-a-width-mismatch means an entry
|
||||
# for a projection whose input is NOT the gram's width is a silent lie.
|
||||
[[ "$output" != *"ssm_out"* ]]
|
||||
[[ "$output" != *"attn"* ]]
|
||||
[[ "$output" != *"mtp."* ]]
|
||||
[[ "$output" != *"ple_ngram"* ]]
|
||||
[[ "$output" != *"output.weight"* ]]
|
||||
}
|
||||
|
||||
@test "rows is a u64: a corpus too big for u32 survives the header" {
|
||||
# The trap this fixture law exists for: pack rows as u32 at offset 16 and a
|
||||
# 100-row file reads back as 4294967296000. 2**32 is exactly representable
|
||||
# in f32, so the count round-trips only if the tool read 8 bytes.
|
||||
C="$BATS_TEST_TMPDIR/wide"
|
||||
mkdir -p "$C"
|
||||
make_gram "$C/gram.r0.blk.0.ffn_down_exps.bin" 4 0 4294967296 0 "1,1,1,1"
|
||||
make_gram "$C/gram.r0.blk.0.ffn_down_exps.0.bin" 4 0 4294967296 0 "3,3,3,3"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/wide.gguf" --chunk-size 4096
|
||||
[ "$status" -eq 0 ]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/wide.gguf" vals blk.0.ffn_down_exps.counts 0 1
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.counts 4294967296"* ]]
|
||||
[[ "$output" != *"4294967296000"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/wide.gguf"
|
||||
[[ "$output" == *"KV imatrix.chunk_count 1048576"* ]]
|
||||
# imatrix.chunk_count is a u32 field, so 2**32 rows in 1-row chunks has no
|
||||
# legal encoding: wrapping it would put a number downstream believes.
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/wide2.gguf" --chunk-size 1
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"CHUNK_COUNT"* ]]
|
||||
[ ! -e "$BATS_TEST_TMPDIR/wide2.gguf" ]
|
||||
}
|
||||
|
||||
@test "every tensor's data offset is a multiple of general.alignment" {
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[ "$status" -eq 0 ]
|
||||
run aligned_offsets "$BATS_TEST_TMPDIR/im.gguf"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == "ALIGNED 12 tensor(s),"*"alignment=32" ]]
|
||||
|
||||
# Red proof, in the same test so the assertion cannot rot: the same file
|
||||
# with one tensor's declared offset nudged by 4. A counts tensor is 4 bytes,
|
||||
# so a writer that forgets to pad between tensors produces exactly this
|
||||
# shape of file — and every value assertion above still passes on it.
|
||||
python3 - "$BATS_TEST_TMPDIR/im.gguf" "$BATS_TEST_TMPDIR/unaligned.gguf" <<'PY'
|
||||
import struct, sys
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
d = bytearray(open(src, "rb").read())
|
||||
def u32(o): return struct.unpack_from("<I", d, o)[0]
|
||||
def u64(o): return struct.unpack_from("<Q", d, o)[0]
|
||||
def st(o):
|
||||
n = u64(o)
|
||||
return d[o + 8:o + 8 + n].decode(), o + 8 + n
|
||||
p = 24
|
||||
for _ in range(u64(16)):
|
||||
key, p = st(p)
|
||||
ty = u32(p); p += 4
|
||||
if ty == 4:
|
||||
p += 4
|
||||
elif ty == 8:
|
||||
_v, p = st(p)
|
||||
elif ty == 9:
|
||||
et = u32(p); n = u64(p + 4); p += 12
|
||||
for _i in range(n):
|
||||
_v, p = st(p)
|
||||
for _ in range(u64(8)):
|
||||
name, p = st(p)
|
||||
nd = u32(p); p += 4
|
||||
p += 8 * nd
|
||||
off_at = p + 4 # the u64 offset field of this tensor
|
||||
if name == "blk.0.ssm_inz.counts":
|
||||
struct.pack_into("<Q", d, off_at, u64(off_at) + 4)
|
||||
p += 12
|
||||
open(dst, "wb").write(bytes(d))
|
||||
PY
|
||||
run aligned_offsets "$BATS_TEST_TMPDIR/unaligned.gguf"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"UNALIGNED"*"blk.0.ssm_inz.counts"* ]]
|
||||
}
|
||||
|
||||
# --- the refusals -----------------------------------------------------------
|
||||
|
||||
@test "a gram short by one float is refused and the file is named" {
|
||||
C="$BATS_TEST_TMPDIR/short"
|
||||
full_recording "$C"
|
||||
# Cut the last 4 bytes of one expert gram: a torn write, which is what a
|
||||
# killed tap actually leaves behind.
|
||||
p="$C/gram.r0.blk.0.ffn_down_exps.0.bin"
|
||||
python3 -c 'import sys
|
||||
p = sys.argv[1]
|
||||
open(p, "wb").write(open(p, "rb").read()[:-4])' "$p"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/no.gguf"
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"SHORT"* ]]
|
||||
[[ "$output" == *"gram.r0.blk.0.ffn_down_exps.0.bin"* ]]
|
||||
[ ! -e "$BATS_TEST_TMPDIR/no.gguf" ]
|
||||
}
|
||||
|
||||
@test "an empty recording directory is refused" {
|
||||
mkdir -p "$BATS_TEST_TMPDIR/empty"
|
||||
run python3 "$TOOL" "$BATS_TEST_TMPDIR/empty" -o "$BATS_TEST_TMPDIR/no.gguf"
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"NO_GRAMS"* ]]
|
||||
[[ "$output" == *"$BATS_TEST_TMPDIR/empty"* ]]
|
||||
[ ! -e "$BATS_TEST_TMPDIR/no.gguf" ]
|
||||
}
|
||||
|
||||
@test "expert grams with no pooled gram for the layer are refused" {
|
||||
# Without the pooled gram there is nothing for an under-threshold expert to
|
||||
# inherit, and the tool would quietly invent a zero diagonal for it.
|
||||
C="$BATS_TEST_TMPDIR/nopooled"
|
||||
mkdir -p "$C"
|
||||
make_gram "$C/gram.r0.blk.3.ffn_down_exps.7.bin" 4 0 500 0 "1,2,3,4"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/no.gguf"
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"NO_POOLED"*"layer 3"* ]]
|
||||
[[ "$output" == *"gram.r<rank>.blk.3.ffn_down_exps.bin"* ]]
|
||||
}
|
||||
|
||||
@test "the same global expert recorded twice with different numbers is refused" {
|
||||
# Rank files carry GLOBAL expert numbering and so describe disjoint experts;
|
||||
# a collision means the recording is corrupt, and whichever file sorted last
|
||||
# would win.
|
||||
C="$BATS_TEST_TMPDIR/conflict"
|
||||
full_recording "$C"
|
||||
make_gram "$C/gram.r1.blk.0.ffn_down_exps.0.bin" 4 1 77 0 "10,20,30,40"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/no.gguf"
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"EXPERT_CONFLICT"*"expert 0"* ]]
|
||||
[[ "$output" == *"gram.r0.blk.0.ffn_down_exps.0.bin"* ]]
|
||||
[[ "$output" == *"gram.r1.blk.0.ffn_down_exps.0.bin"* ]]
|
||||
}
|
||||
|
||||
@test "an existing output is refused by name rather than overwritten" {
|
||||
# The trash law: a re-run must not destroy the imatrix a convert is reading.
|
||||
C="$BATS_TEST_TMPDIR/full"
|
||||
full_recording "$C"
|
||||
: > "$BATS_TEST_TMPDIR/keep.gguf"
|
||||
printf 'do not clobber me\n' > "$BATS_TEST_TMPDIR/keep.gguf"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/keep.gguf"
|
||||
[ "$status" -eq 2 ]
|
||||
[[ "$output" == *"REFUSED"*"EXISTS"*"keep.gguf"* ]]
|
||||
run cat "$BATS_TEST_TMPDIR/keep.gguf"
|
||||
[[ "$output" == *"do not clobber me"* ]]
|
||||
}
|
||||
|
||||
@test "--min-rows moves the threshold and the bytes follow it" {
|
||||
# The default threshold is the engine's own law (4*k rows, lq_hess.h), but
|
||||
# the operator has to be able to raise it when a corpus is thin. Asserted on
|
||||
# the slices, not on a report line: a flag that only changes prose is a
|
||||
# flag that changes nothing.
|
||||
C="$BATS_TEST_TMPDIR/floor"
|
||||
full_recording "$C"
|
||||
run python3 "$TOOL" "$C" -o "$BATS_TEST_TMPDIR/far.gguf" --min-rows 200
|
||||
[ "$status" -eq 0 ]
|
||||
# 200 is above every expert's routing (100, 3, 64, 0, 100 and layer 1's 48),
|
||||
# so all six slices now inherit.
|
||||
[[ "$output" == *"inherited=6"* ]]
|
||||
run gguf_read "$BATS_TEST_TMPDIR/far.gguf" vals blk.0.ffn_down_exps.in_sum2 0 4
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.in_sum2 1.5 2.5 3.5 4.5"* ]]
|
||||
# The counts do not move with the threshold: routing is a measurement, not a
|
||||
# judgement about how much data is enough.
|
||||
run gguf_read "$BATS_TEST_TMPDIR/far.gguf" vals blk.0.ffn_down_exps.counts 0 5
|
||||
[[ "$output" == *"VALS blk.0.ffn_down_exps.counts 100 3 64 0 100"* ]]
|
||||
}
|
||||
Reference in new issue
Block a user