| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function (root) { |
| "use strict"; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function planStages(spec, caps) { |
| const n = caps.length; |
| if (n < 1) throw new Error("no devices to plan across"); |
| const total = caps.reduce((a, d) => a + Math.max(1e-6, d.capacity), 0); |
| const exact = caps.map(d => spec.layers * Math.max(1e-6, d.capacity) / total); |
| const floor = exact.map(Math.floor); |
| let left = spec.layers - floor.reduce((a, b) => a + b, 0); |
| const order = exact.map((e, i) => [e - floor[i], i]).sort((a, b) => b[0] - a[0] || a[1] - b[1]); |
| for (let i = 0; i < order.length && left > 0; i++, left--) floor[order[i][1]]++; |
| const stages = []; |
| let lo = 0; |
| for (let i = 0; i < n; i++) { |
| const hi = lo + floor[i]; |
| stages.push({ id: caps[i].id, index: i, lo, hi, head: i === 0, |
| backend: caps[i].backend, capacity: caps[i].capacity }); |
| lo = hi; |
| } |
| |
| |
| return stages.filter(s => s.head || s.hi > s.lo).map((s, i) => ({ ...s, index: i })); |
| } |
|
|
| |
| |
| |
| function stageBytes(spec, available, st, ArchMod) { |
| const names = ArchMod.tensorsFor(spec, available, st); |
| let n = 0; |
| for (const name of names) n += available.get(name).elems * 4; |
| return n; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function toKN(w, outDim, inDim, layout) { |
| if (layout === "in_out") return w; |
| const out = new Float32Array(w.length); |
| for (let o = 0; o < outDim; o++) |
| for (let i = 0; i < inDim; i++) out[i * outDim + o] = w[o * inDim + i]; |
| return out; |
| } |
|
|
| function stageWeights(spec, st, got, ArchMod) { |
| const resolve = ArchMod.resolver(new Map([...got.keys()].map(k => [k, true]))); |
| const pick = (name, opt) => { const r = resolve(name, opt); return r ? got.get(r) : null; }; |
| const C = spec.hidden, L = spec.weightLayout; |
| const w = { layers: [] }; |
|
|
| if (st.head) { |
| const h = ArchMod.headTensors(spec); |
| w.emb = pick(h.emb); |
| w.pos = pick(h.pos, true); |
| w.nrmF = pick(h.nrmF, true); |
| w.nrmFb = pick(h.nrmFb, true); |
| |
| const lm = pick(h.lmHead, true); |
| w.lmHead = lm ? toKN(lm, spec.vocab, C, L) : transposeEmb(w.emb, spec.vocab, C); |
| if (!w.nrmF) w.nrmF = new Float32Array(C).fill(1); |
| } |
|
|
| const qDim = spec.heads * spec.headDim, kvDim = spec.kvHeads * spec.headDim; |
| for (let l = st.lo; l < st.hi; l++) { |
| const t = ArchMod.layerTensors(spec, l); |
| const ly = { nrm1: pick(t.nrm1), nrm1b: pick(t.nrm1b, true), |
| nrm2: pick(t.nrm2), nrm2b: pick(t.nrm2b, true) }; |
| if (spec.qkvFused) { |
| ly.Wqkv = toKN(pick(t.Wqkv), 3 * C, C, L); |
| ly.bqkv = pick(t.bqkv, true); |
| } else { |
| ly.Wq = toKN(pick(t.Wq), qDim, C, L); ly.bq = pick(t.bq, true); |
| ly.Wk = toKN(pick(t.Wk), kvDim, C, L); ly.bk = pick(t.bk, true); |
| ly.Wv = toKN(pick(t.Wv), kvDim, C, L); ly.bv = pick(t.bv, true); |
| } |
| ly.Wo = toKN(pick(t.Wo), C, qDim, L); ly.bo = pick(t.bo, true); |
| if (spec.gated) { |
| ly.Wgate = toKN(pick(t.Wgate), spec.inter, C, L); |
| ly.Wup = toKN(pick(t.Wup), spec.inter, C, L); |
| } else { |
| ly.Wfc = toKN(pick(t.Wfc), spec.inter, C, L); ly.bfc = pick(t.bfc, true); |
| } |
| ly.Wdown = toKN(pick(t.Wdown), C, spec.inter, L); ly.bdown = pick(t.bdown, true); |
| w.layers.push(ly); |
| } |
| return w; |
| } |
| function transposeEmb(emb, vocab, C) { |
| const out = new Float32Array(emb.length); |
| for (let v = 0; v < vocab; v++) |
| for (let c = 0; c < C; c++) out[c * vocab + v] = emb[v * C + c]; |
| return out; |
| } |
|
|
| |
| |
| |
| function fnv1a(bytes) { |
| let h = 0x811c9dc5; |
| for (let i = 0; i < bytes.length; i++) { h ^= bytes[i]; h = Math.imul(h, 0x01000193); } |
| return h >>> 0; |
| } |
| function hashF32(a) { return fnv1a(new Uint8Array(a.buffer, a.byteOffset, a.byteLength)); } |
|
|
| |
| |
| |
| |
| function modelFingerprint(repo, revision, tensors) { |
| const parts = [repo, revision || "main"]; |
| for (const name of [...tensors.keys()].sort()) { |
| const t = tensors.get(name); |
| parts.push(`${name}:${t.dtype}:${t.shape.join("x")}:${t.start}:${t.end}`); |
| } |
| return fnv1a(new TextEncoder().encode(parts.join("|"))); |
| } |
|
|
| const api = { planStages, stageBytes, stageWeights, toKN, transposeEmb, |
| fnv1a, hashF32, modelFingerprint }; |
| if (typeof module !== "undefined" && module.exports) module.exports = api; |
| else root.Shard = api; |
| })(typeof self !== "undefined" ? self : this); |
|
|