From f0d0614ce62a68fa9c98e0b7f4f6e53c80c708a1 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 6 Oct 2026 22:37:16 -0700 Subject: [PATCH] fix(run-swift15-bf16): define KLD mounts (were unbound-empty) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kld died: 'cannot read --kld-corpus /data/kld.jsonl' — KLD_MOUNT was referenced but never defined, so the corpus/ref-dir mounts silently expanded to nothing. Add them (nested order: after the /data mount). feat(convert-swift15-w4dn8): final recipe convert on 1.0.13 Convert with the SERVING pin so the .rad crosses no version boundary; only the Gram files cross (RADGRAM2 magic, gram.r%d.%s.bin naming and calib_gram/calib_resolve/calib_stem are byte-identical between the 1.0.13 and 1.2.0 libquant). Host-backend run: prod can stay up. Gates: grams present (>=48), bf16 container deleted, disk floor, rad-info gptq receipt, size floor 126000 MiB. --- scripts/convert-swift15-w4dn8.sh | 72 ++++++++++++++++++++++++++++++++ scripts/run-swift15-bf16.sh | 7 ++++ 2 files changed, 79 insertions(+) create mode 100755 scripts/convert-swift15-w4dn8.sh diff --git a/scripts/convert-swift15-w4dn8.sh b/scripts/convert-swift15-w4dn8.sh new file mode 100755 index 0000000..e335a49 --- /dev/null +++ b/scripts/convert-swift15-w4dn8.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# convert-swift15-w4dn8.sh — RUNS ON DANKSERVER. The final recipe convert of +# the Swift 1.5 checkpoint: gate_up experts through GPTQ against the 10M-token +# calibration Grams, down projections block-fp8, protected experts bf16, +# trunk int8, PLE fixed-scale fp8 (scripts/recipes/ +# qwen4exp-swift15-w4dn8-i8-hc8m.recipe). +# +# The convert engine is 1.0.13 — the SAME pin that will serve the result, so +# the .rad crosses no version boundary. Only the Gram files cross versions +# (1.2.0 wrote them; the RADGRAM2 magic, gram.r%d.%s.bin naming and the +# calib_gram/calib_resolve/calib_stem symbols are byte-identical between the +# two libquant.so). rad-convert runs on the host backend (no GPU visible in +# the container) — production can stay up through this script. +# +# Prereqs (campaign order): calibration complete (calib-push printed TAP_DONE), +# the protected-expert cast lines rewritten into the recipe by +# derive-protected-experts.py, and the 335 GiB bf16 container deleted — +# the peak-disk arithmetic needs that space (checkpoint 335.3 + output ~132 +# GiB on the volume; --reuse is NOT used, see the recipe header). +set -euo pipefail + +PIN_1013=sha256:4c3f484564bb2872784e46b0a59cbd71becc9c1e746e301a3596ffae253c322e +IMAGE="stilldeadcode/radiance@$PIN_1013" +CKPT=/home/dank/models/Swift1.5-Qwen3.8-Flash-Next +RECIPE=/home/dank/serverAppConfigs-swift15/scripts/recipes/qwen4exp-swift15-w4dn8-i8-hc8m.recipe +CALIB=/home/dank/corpora/calib +OUT=/home/dank/models/rad/qwen4exp-swift15-w4dn8-i8-hc8m.rad +LOG=/home/dank/logs/swift15_convert.log +# gate_up ~37.6 + down ~37.7 + PLE 47.7 + trunk/embeddings/head ~10 GiB. +MIN_MIB=${FRANK_SWIFT15_RAD_MIN_MIB:-126000} + +# Gate 1: inputs. A missing Gram directory converts UNCALIBRATED with a +# per-tensor stderr note, which is silently worse than failing here. +[ -d "$CKPT" ] || { echo "no checkpoint at $CKPT" >&2; exit 1; } +[ -f "$RECIPE" ] || { echo "no recipe at $RECIPE" >&2; exit 1; } +GRAMS=$(find "$CALIB" -maxdepth 1 -name 'gram.r*.bin' 2>/dev/null | wc -l) +[ "$GRAMS" -ge 48 ] || { echo "calib dir $CALIB holds $GRAMS gram files (<48)" >&2; exit 1; } +if [ -e "$OUT" ]; then echo "$OUT already exists; move it to trash first" >&2; exit 1; fi +if [ -e /home/dank/models/rad/qwen4exp-swift15-bf16.rad ]; then + echo "the bf16 container is still on disk; delete it first (peak disk)" >&2; exit 1 +fi + +# Gate 2: disk. Output ~132 GiB plus convert staging, 20 GiB of slack. +FREE_MIB=$(df --output=avail -m /home/dank/models | tail -1 | tr -d ' ') +[ "$FREE_MIB" -ge $((MIN_MIB + 20480)) ] || { + echo "only ${FREE_MIB} MiB free on /home/dank/models" >&2; exit 1; } + +# The recipe names $CALIB; rad-convert expands it from the environment +# (MOE-W4.md:275). The recipe's cast section must name THIS checkpoint's +# protected experts — derive-protected-experts.py rewrote it. +echo "convert: $CKPT -> $OUT (gptq calib=$CALIB, $(date -Is))" | tee "$LOG" +podman run --rm --name swift15-convert \ + -v /home/dank/models:/models \ + -v /home/dank/serverAppConfigs-swift15:/campaign:ro \ + -v "$CALIB:/data/calib:ro" \ + -e CALIB=/data/calib \ + --entrypoint /opt/radiance/bin/rad-convert \ + "$IMAGE" /models/"$(basename "$CKPT")" \ + --recipe /campaign/"${RECIPE#/home/dank/serverAppConfigs-swift15/}" \ + -o /models/rad/"$(basename "$OUT")" 2>&1 | tee -a "$LOG" +rc=${PIPESTATUS[0]} +[ "$rc" -eq 0 ] || { echo "rad-convert rc=$rc; log: $LOG" >&2; exit "$rc"; } + +# Gate 3: the artifact. rad-info's recipe echo is the receipt that GPTQ ran. +SIZE_MIB=$(( $(stat -c %s "$OUT") / 1048576 )) +[ "$SIZE_MIB" -ge "$MIN_MIB" ] || { + echo "$OUT is ${SIZE_MIB} MiB < floor ${MIN_MIB}" >&2; exit 1; } +podman run --rm --entrypoint /opt/radiance/bin/rad-info \ + -v /home/dank/models:/models:ro "$IMAGE" /models/rad/"$(basename "$OUT")" \ + 2>&1 | tee -a "$LOG" | grep -c 'gptq' >/dev/null \ + || echo "WARNING: rad-info shows no gptq rule in the recorded recipe" >&2 +echo "CONVERT_DONE ${SIZE_MIB} MiB -> $OUT" diff --git a/scripts/run-swift15-bf16.sh b/scripts/run-swift15-bf16.sh index cb6ac9d..ab30b6d 100755 --- a/scripts/run-swift15-bf16.sh +++ b/scripts/run-swift15-bf16.sh @@ -83,6 +83,13 @@ esac cp -f /home/dank/serverAppConfigs/scripts/qwen38-froggeric-v22.5.jinja \ /home/dank/models/tpl.jinja 2>/dev/null || true +KLD_MOUNT=() +if [ "$MODE" = kld ]; then + # Nested under the /data mount, so these must come after it (line order + # in podman run below): the corpus read-only, the record dir writable. + KLD_MOUNT=(-v "$KLD_CORPUS:/data/kld.jsonl:ro" + -v "$KLD_REF_DIR:/data/kld-ref") +fi EXTRA_ENV=() if [ "$MODE" = calib ]; then EXTRA_ENV=(-v "$CALIB_DIR:/data/calib"