Spaces:
Running
Running
Upload qvac-gpu.js with huggingface_hub
Browse files- qvac-gpu.js +20 -5
qvac-gpu.js
CHANGED
|
@@ -1065,6 +1065,12 @@ export async function createQvacGPU(manifest, fetchTensor, cap = 64, eos = 2, st
|
|
| 1065 |
};
|
| 1066 |
if (!frameGran) await upW("lm_head"); // resident in resident/layer modes; TILED (played) in frame mode
|
| 1067 |
let RQ = null, RS = null, packLayout = null, packStride = 0, packQbytes = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
let opfsStore = null;
|
| 1069 |
const frameMan = {}; // name → {off, qlen, slen, N, K} (frame layout)
|
| 1070 |
if (frameGran) {
|
|
@@ -1104,20 +1110,27 @@ export async function createQvacGPU(manifest, fetchTensor, cap = 64, eos = 2, st
|
|
| 1104 |
// The packed bytes live in JS ("layer") or on DISK in OPFS ("opfs" — the
|
| 1105 |
// RAM-wall break); EITHER way the per-layer body is the SAME proven layerBody().
|
| 1106 |
const al = (n) => Math.ceil(n / 256) * 256;
|
| 1107 |
-
|
|
|
|
|
|
|
|
|
|
| 1108 |
packLayout = {}; let qo = 0, so = 0;
|
| 1109 |
-
for (const role of ROLES) { const t = tmap[`l0.${role}`]; qo = al(qo); so = al(so); packLayout[role] = { qoff: qo, qsize: qbl(t), soff: so, ssize:
|
| 1110 |
const packQ = al(qo), packS = al(so);
|
| 1111 |
RQ = dev.createBuffer({ size: packQ, usage: U.STORAGE | U.COPY_DST });
|
| 1112 |
RS = dev.createBuffer({ size: Math.max(16, packS), usage: U.STORAGE | U.COPY_DST });
|
| 1113 |
streamBuf = packQ + Math.max(16, packS);
|
|
|
|
|
|
|
| 1114 |
for (const role of ROLES) {
|
| 1115 |
const L = packLayout[role];
|
| 1116 |
-
R[role] =
|
|
|
|
|
|
|
| 1117 |
}
|
| 1118 |
-
const packLayer = async (l) => { // build one layer's packed (q,s) from the
|
| 1119 |
const q = new Uint8Array(packQ), s = new Uint8Array(packS);
|
| 1120 |
-
for (const role of ROLES) { const p = await parts(`l${l}.${role}`); q.set(p.q, packLayout[role].qoff); s.set(new Uint8Array(p.s.buffer, p.s.byteOffset, p.s.byteLength), packLayout[role].soff); }
|
| 1121 |
return { q, s };
|
| 1122 |
};
|
| 1123 |
if (opfs) { // DISK-backed: page each layer's packed blob in per token
|
|
@@ -1651,6 +1664,8 @@ export async function createQvacGPU(manifest, fetchTensor, cap = 64, eos = 2, st
|
|
| 1651 |
dev.queue.writeBuffer(RQ, 0, Wb[l].q); // one fat DMA for the whole layer's matrices
|
| 1652 |
dev.queue.writeBuffer(RS, 0, Wb[l].s); // + one for all its scales
|
| 1653 |
}
|
|
|
|
|
|
|
| 1654 |
const enc = dev.createCommandEncoder();
|
| 1655 |
cur = layerBody(enc, l, cur, (role) => R[role]);
|
| 1656 |
dev.queue.submit([enc.finish()]);
|
|
|
|
| 1065 |
};
|
| 1066 |
if (!frameGran) await upW("lm_head"); // resident in resident/layer modes; TILED (played) in frame mode
|
| 1067 |
let RQ = null, RS = null, packLayout = null, packStride = 0, packQbytes = 0;
|
| 1068 |
+
// DRAFT (t2 layer-streaming — needs WebGPU verification): BitNet/Falcon t2 has a SCALAR scale per matrix
|
| 1069 |
+
// (baked into the matmul uniform via fbits), not a per-block scale buffer. So a t2 streamed layer packs
|
| 1070 |
+
// q ONLY (no scale blob), and each layer's per-role scalar is written into the reusable R[role].uni before
|
| 1071 |
+
// that layer's matmul. t2scales[l][role] = fbits(scale) is precomputed from the manifest (no fetch).
|
| 1072 |
+
const t2stream = !!stream && !moe && !frameGran && ROLES.every((r) => (tmap[`l0.${r}`] || {}).fmt === "t2");
|
| 1073 |
+
let t2scales = null;
|
| 1074 |
let opfsStore = null;
|
| 1075 |
const frameMan = {}; // name → {off, qlen, slen, N, K} (frame layout)
|
| 1076 |
if (frameGran) {
|
|
|
|
| 1110 |
// The packed bytes live in JS ("layer") or on DISK in OPFS ("opfs" — the
|
| 1111 |
// RAM-wall break); EITHER way the per-layer body is the SAME proven layerBody().
|
| 1112 |
const al = (n) => Math.ceil(n / 256) * 256;
|
| 1113 |
+
// t2 (BitNet/Falcon): q is codes only (N·K/4 B, 4 trits/byte) + a SCALAR scale (→ uniform); no scale blob.
|
| 1114 |
+
// Every other stream fmt (q3f/q4/e8/t2r): q (padded) + a per-block scale blob at soff. Same packLayer shape.
|
| 1115 |
+
const qbl = (t) => t2stream ? Math.ceil((t.N * t.K / 4) / 4) * 4 : Math.ceil(qlenOf(t) / 4) * 4;
|
| 1116 |
+
const sbl = (t) => t2stream ? 0 : slenOf(t);
|
| 1117 |
packLayout = {}; let qo = 0, so = 0;
|
| 1118 |
+
for (const role of ROLES) { const t = tmap[`l0.${role}`]; qo = al(qo); so = al(so); packLayout[role] = { qoff: qo, qsize: qbl(t), soff: so, ssize: sbl(t), N: t.N, K: t.K }; qo += qbl(t); so += sbl(t); }
|
| 1119 |
const packQ = al(qo), packS = al(so);
|
| 1120 |
RQ = dev.createBuffer({ size: packQ, usage: U.STORAGE | U.COPY_DST });
|
| 1121 |
RS = dev.createBuffer({ size: Math.max(16, packS), usage: U.STORAGE | U.COPY_DST });
|
| 1122 |
streamBuf = packQ + Math.max(16, packS);
|
| 1123 |
+
// t2: per-layer-per-role scalar (fbits), refreshed into R[role].uni each layer in the forward. Manifest-only.
|
| 1124 |
+
if (t2stream) { t2scales = []; for (let l = 0; l < n_layers; l++) { const row = {}; for (const role of ROLES) row[role] = fbits((tmap[`l${l}.${role}`] || {}).s ?? 1); t2scales.push(row); } }
|
| 1125 |
for (const role of ROLES) {
|
| 1126 |
const L = packLayout[role];
|
| 1127 |
+
R[role] = t2stream
|
| 1128 |
+
? { qbuf: { buffer: RQ, offset: L.qoff, size: L.qsize }, uni: ubuf(new Uint32Array([L.K, L.N, L.K / 16, 0])), N: L.N, K: L.K, t2: true } // scale.w set per layer
|
| 1129 |
+
: { qbuf: { buffer: RQ, offset: L.qoff, size: L.qsize }, sbuf: { buffer: RS, offset: L.soff, size: L.ssize }, uni: ubuf(new Uint32Array([L.K, L.N, L.K / 32, 0])), N: L.N };
|
| 1130 |
}
|
| 1131 |
+
const packLayer = async (l) => { // build one layer's packed (q[,s]) from the κ-object
|
| 1132 |
const q = new Uint8Array(packQ), s = new Uint8Array(packS);
|
| 1133 |
+
for (const role of ROLES) { const p = await parts(`l${l}.${role}`); q.set(p.q, packLayout[role].qoff); if (!t2stream) s.set(new Uint8Array(p.s.buffer, p.s.byteOffset, p.s.byteLength), packLayout[role].soff); }
|
| 1134 |
return { q, s };
|
| 1135 |
};
|
| 1136 |
if (opfs) { // DISK-backed: page each layer's packed blob in per token
|
|
|
|
| 1664 |
dev.queue.writeBuffer(RQ, 0, Wb[l].q); // one fat DMA for the whole layer's matrices
|
| 1665 |
dev.queue.writeBuffer(RS, 0, Wb[l].s); // + one for all its scales
|
| 1666 |
}
|
| 1667 |
+
// t2: this layer's per-role scalar scales into the reused uniforms (matmul reads scale from uni.w).
|
| 1668 |
+
if (t2stream) for (const role of ROLES) { const L = packLayout[role]; dev.queue.writeBuffer(R[role].uni, 0, new Uint32Array([L.K, L.N, L.K / 16, t2scales[l][role]])); }
|
| 1669 |
const enc = dev.createCommandEncoder();
|
| 1670 |
cur = layerBody(enc, l, cur, (role) => R[role]);
|
| 1671 |
dev.queue.submit([enc.finish()]);
|