TinyDecide / verify.mjs
TheREZOR's picture
TinyDecide release
3de31cf
Raw History Blame Contribute Delete
1.83 kB
// Parity: JS engine vs torch (same int8 weights). node web/verify.mjs
import { readFileSync } from "node:fs";
import { TinyDecide } from "./tinydecide.js";
const dir = new URL(".", import.meta.url).pathname;
const meta = JSON.parse(readFileSync(dir + "meta.json", "utf8"));
const bin = readFileSync(dir + "model.bin");
const buf = bin.buffer.slice(bin.byteOffset, bin.byteOffset + bin.byteLength);
const ref = JSON.parse(readFileSync(dir + "ref.json", "utf8"));
const m = new TinyDecide(meta, buf);
let idBad = 0, maxP = 0, spanBad = 0, pickBad = 0, n = 0, ms = 0;
for (const r of ref) {
const got = m.answer({ state: r.state, questions: r.questions });
ms += got.ms;
if (JSON.stringify(got.ids) !== JSON.stringify(r.ids)) {
idBad++;
if (idBad <= 3) console.log("ids differ:", JSON.stringify(r.state).slice(0, 80), "\n torch", r.ids.slice(0, 30).join(","), "\n js ", got.ids.slice(0, 30).join(","));
continue;
}
r.answers.forEach((a, i) => {
const b = got.answers[i]; n++;
if (a.type === "choice" || a.type === "score") {
a.probs.forEach((p, j) => { maxP = Math.max(maxP, Math.abs(p - b.probs[j])); });
if (a.pick !== b.pick) pickBad++;
} else if (a.type === "noul") maxP = Math.max(maxP, Math.abs(a.p - b.p));
else {
maxP = Math.max(maxP, Math.abs(a.p_present - b.p_present));
if ((a.text || "") !== (b.text || "") || a.tok[0] !== b.tok[0] || a.tok[1] !== b.tok[1]) { spanBad++; if (spanBad <= 3) console.log("span differs", a.text, "|", b.text, a.tok, b.tok); }
}
});
}
console.log(`requests ${ref.length} token-id mismatches ${idBad} answers ${n} max|dp| ${maxP.toExponential(2)} pick mismatches ${pickBad} span mismatches ${spanBad} avg ${(ms / ref.length).toFixed(0)} ms/request`);
process.exit(idBad || maxP > 1e-3 || spanBad || pickBad ? 1 : 0);