File size: 2,193 Bytes
b9cbc2e 4cf5cdc b9cbc2e 4cf5cdc b9cbc2e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // Mini transformer through the verified units: (a) loss drops well below the
// uniform baseline ln(V), (b) two replicas fed the same averaged gradients stay
// bit-identical, (c) generation produces corpus-like text.
const fs = require("fs");
const path = require("path");
const T = require("./public/traincore.js");
const V = require("./public/verified_core.js");
const X = require("./public/transformer.js");
function loadLUTs() {
const p = (f) => path.join(__dirname, "public", f);
return { mul: new Int16Array(fs.readFileSync(p("mul_lut.bin")).buffer.slice(0)),
requant: new Int8Array(fs.readFileSync(p("requant_lut.bin")).buffer.slice(0)),
relu: new Int8Array(fs.readFileSync(p("relu_lut.bin")).buffer.slice(0)) };
}
const L = loadLUTs();
const matmulInt8 = (Xq, Wq, m, k, n, LL) => V.lutMatmulJS(Xq, Wq, m, k, n, LL);
const cfg = { c: 32, t: 32, b: 8, layers: 2, heads: 2, steps: 120, lr: 0.02 };
(async function () {
const A = X.init(cfg, L, matmulInt8);
const B = X.init(cfg, L, matmulInt8);
console.log(`vocab=${X.vocabSize()}, params=${A.nParams}, baseline loss=${Math.log(X.vocabSize()).toFixed(3)}`);
const oa = T.makeAdam(A.nParams, { lr: cfg.lr });
const ob = T.makeAdam(B.nParams, { lr: cfg.lr });
let first = 0, loss = 0;
for (let s = 0; s < cfg.steps; s++) {
const ra = await X.trainStep(A);
const rb = await X.trainStep(B);
const avg = T.averageGrads([ra.grad, rb.grad]);
X.applyUpdate(A, oa.step(avg));
X.applyUpdate(B, ob.step(avg));
loss = (ra.loss + rb.loss) / 2;
if (s === 0) first = loss;
if (s % 30 === 0 || s === cfg.steps - 1) console.log(` step ${s} loss ${loss.toFixed(4)}`);
}
const pa = X.getFlatParams(A), pb = X.getFlatParams(B);
let diff = 0;
for (let i = 0; i < pa.length; i++) diff = Math.max(diff, Math.abs(pa[i] - pb[i]));
const sample = await X.generate(A, "the ", 60);
console.log(`sample: "${sample}"`);
console.log(`replica max param diff: ${diff.toExponential(3)}`);
const ok = loss < first * 0.75 && loss < Math.log(X.vocabSize()) && diff === 0;
console.log(ok ? "TRANSFORMER TEST PASSED" : "TRANSFORMER TEST FAILED");
process.exit(ok ? 0 : 1);
})();
|