@tryhamster/gerbil 1.4.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +10 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/cli.mjs +7 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/frameworks/express.mjs +1 -1
- package/dist/frameworks/fastify.mjs +1 -1
- package/dist/frameworks/hono.mjs +1 -1
- package/dist/frameworks/next.mjs +1 -1
- package/dist/frameworks/trpc.mjs +1 -1
- package/dist/gerbil-CNyb67ca.mjs +4 -0
- package/dist/{gerbil-DGrCwGtJ.mjs → gerbil-DsgYlkgf.mjs} +12 -2
- package/dist/gerbil-DsgYlkgf.mjs.map +1 -0
- package/dist/gpu/hooks.d.mts.map +1 -1
- package/dist/gpu/index.mjs +2 -2
- package/dist/{gpu-DbB321DN.mjs → gpu-DfUBMUGe.mjs} +2 -2
- package/dist/{gpu-DbB321DN.mjs.map → gpu-DfUBMUGe.mjs.map} +1 -1
- package/dist/index-BdbeBDTz.d.mts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/integrations/ai-sdk.mjs +1 -1
- package/dist/integrations/langchain.mjs +1 -1
- package/dist/integrations/llamaindex.mjs +1 -1
- package/dist/integrations/mcp.mjs +4 -4
- package/dist/{mcp-DcE3wn-L.mjs → mcp-D3XRaVAc.mjs} +3 -3
- package/dist/{mcp-DcE3wn-L.mjs.map → mcp-D3XRaVAc.mjs.map} +1 -1
- package/dist/moonshine-stt-B0dwDCgT.mjs +4 -0
- package/dist/{moonshine-stt-BGmctcdO.mjs → moonshine-stt-bExSnd2o.mjs} +271 -66
- package/dist/moonshine-stt-bExSnd2o.mjs.map +1 -0
- package/dist/{one-liner-DTGg6zdm.mjs → one-liner-UvMt5g0G.mjs} +2 -2
- package/dist/{one-liner-DTGg6zdm.mjs.map → one-liner-UvMt5g0G.mjs.map} +1 -1
- package/dist/{repl-Ci0zXCT_.mjs → repl-B5xHAr9n.mjs} +3 -3
- package/dist/skills/index.d.mts +2 -2
- package/dist/skills/index.mjs +3 -3
- package/dist/{skills-Dsf0op66.mjs → skills-BJUofoaY.mjs} +2 -2
- package/dist/{skills-Dsf0op66.mjs.map → skills-BJUofoaY.mjs.map} +1 -1
- package/package.json +1 -1
- package/dist/gerbil-CUzVDAU7.mjs +0 -4
- package/dist/gerbil-DGrCwGtJ.mjs.map +0 -1
- package/dist/moonshine-stt-BGmctcdO.mjs.map +0 -1
- package/dist/moonshine-stt-QoNJeCzR.mjs +0 -4
|
@@ -27,7 +27,7 @@ async function initGPU(options) {
|
|
|
27
27
|
if (!adapter) throw new Error("No WebGPU adapter found. Your GPU may not support WebGPU, or another tab may be using it. Try closing other tabs.");
|
|
28
28
|
const hasF16 = adapter.features.has("shader-f16");
|
|
29
29
|
const hasSubgroups = adapter.features.has("subgroups");
|
|
30
|
-
const hasTimestamp = typeof process !== "undefined" && process.env?.GERBIL_PROFILE != null && adapter.features.has("timestamp-query");
|
|
30
|
+
const hasTimestamp = typeof process !== "undefined" && (process.env?.GERBIL_PROFILE != null || process.env?.GERBIL_TS_TOTAL != null) && adapter.features.has("timestamp-query");
|
|
31
31
|
const requiredFeatures = [];
|
|
32
32
|
if (hasF16) requiredFeatures.push("shader-f16");
|
|
33
33
|
if (hasSubgroups) requiredFeatures.push("subgroups");
|
|
@@ -3864,8 +3864,10 @@ fn main(
|
|
|
3864
3864
|
`;
|
|
3865
3865
|
const WGSL_SWIGLU_MATVEC_INT4 = `\
|
|
3866
3866
|
// CONSTRAINT: N_TILE must equal workgroup_size / K_THREADS
|
|
3867
|
-
|
|
3868
|
-
|
|
3867
|
+
// 16/16 matches the plain-matvec sweep winner (8/32 measured slower at every
|
|
3868
|
+
// production shape; this fused kernel had never been re-swept).
|
|
3869
|
+
const N_TILE: u32 = 16u;
|
|
3870
|
+
const K_THREADS: u32 = 16u;
|
|
3869
3871
|
|
|
3870
3872
|
struct Params {
|
|
3871
3873
|
K: u32,
|
|
@@ -3969,8 +3971,8 @@ fn main(
|
|
|
3969
3971
|
}
|
|
3970
3972
|
`;
|
|
3971
3973
|
const WGSL_DUAL_MATVEC_INT4 = `\
|
|
3972
|
-
const N_TILE: u32 =
|
|
3973
|
-
const K_THREADS: u32 =
|
|
3974
|
+
const N_TILE: u32 = 16u;
|
|
3975
|
+
const K_THREADS: u32 = 16u;
|
|
3974
3976
|
|
|
3975
3977
|
struct Params {
|
|
3976
3978
|
K: u32,
|
|
@@ -4470,20 +4472,45 @@ struct Params {
|
|
|
4470
4472
|
@group(0) @binding(6) var<storage, read_write> output: array<f32>;
|
|
4471
4473
|
@group(0) @binding(7) var<storage, read> params: Params;
|
|
4472
4474
|
|
|
4473
|
-
//
|
|
4475
|
+
// OCCUPANCY FAN-OUT: one workgroup per (head, d-chunk) instead of per head.
|
|
4476
|
+
// Each head's state column d is touched ONLY by the workgroup owning d's chunk
|
|
4477
|
+
// (kv_dot for lane d reads state[:, d]; the rank-1 update writes state[:, d]),
|
|
4478
|
+
// so chunks are fully independent across timesteps — no cross-workgroup sync.
|
|
4479
|
+
// 16 heads → 128 workgroups (vs 16), each 128 threads = D_LANES(16) × K_SPLITS(8).
|
|
4480
|
+
// Requires val_dim % (D_CHUNKS*... ) handled via bounds guards; key_dim <= 128.
|
|
4481
|
+
|
|
4482
|
+
const D_CHUNKS: u32 = 8u; // workgroups per head (must match JS dispatch)
|
|
4483
|
+
const D_LANES: u32 = 16u; // d lanes per workgroup
|
|
4484
|
+
const K_SPLITS: u32 = 8u; // threads cooperating on each d lane's k loop
|
|
4485
|
+
|
|
4486
|
+
// Shared memory for Q and K vectors (L2-normalized), reduction, partials
|
|
4474
4487
|
var<workgroup> shared_q: array<f32, 128>;
|
|
4475
4488
|
var<workgroup> shared_k: array<f32, 128>;
|
|
4476
4489
|
var<workgroup> shared_norm: array<f32, 128>;
|
|
4490
|
+
var<workgroup> shared_partial: array<f32, 128>; // [D_LANES][K_SPLITS]
|
|
4491
|
+
var<workgroup> shared_kvmem: array<f32, D_LANES>;
|
|
4477
4492
|
|
|
4478
4493
|
@compute @workgroup_size(128)
|
|
4479
4494
|
fn main(
|
|
4480
4495
|
@builtin(local_invocation_id) lid: vec3u,
|
|
4481
4496
|
@builtin(workgroup_id) wid: vec3u,
|
|
4482
4497
|
) {
|
|
4483
|
-
let h = wid.x
|
|
4498
|
+
let h = wid.x / D_CHUNKS;
|
|
4499
|
+
let chunk = wid.x % D_CHUNKS;
|
|
4484
4500
|
if (h >= params.num_heads) { return; }
|
|
4485
4501
|
|
|
4486
|
-
let
|
|
4502
|
+
let tid = lid.x; // 0..127
|
|
4503
|
+
let d_local = tid % D_LANES; // lane within chunk
|
|
4504
|
+
let k_split = tid / D_LANES; // 0..K_SPLITS-1
|
|
4505
|
+
let d_per_chunk = (params.val_dim + D_CHUNKS - 1u) / D_CHUNKS;
|
|
4506
|
+
// This lane's output dim (may exceed val_dim for ragged sizes — guarded below).
|
|
4507
|
+
// d_per_chunk > D_LANES is unsupported (val_dim > 128 with D_CHUNKS=8).
|
|
4508
|
+
let d = chunk * d_per_chunk + d_local;
|
|
4509
|
+
let d_ok = d < params.val_dim && d_local < d_per_chunk;
|
|
4510
|
+
|
|
4511
|
+
let k_slice = (params.key_dim + K_SPLITS - 1u) / K_SPLITS;
|
|
4512
|
+
let k_begin = k_split * k_slice;
|
|
4513
|
+
let k_end = min(k_begin + k_slice, params.key_dim);
|
|
4487
4514
|
|
|
4488
4515
|
let A_val = -exp(A_log[h]);
|
|
4489
4516
|
let state_base = h * params.key_dim * params.val_dim;
|
|
@@ -4497,37 +4524,48 @@ fn main(
|
|
|
4497
4524
|
for (var t: u32 = 0u; t < params.T; t = t + 1u) {
|
|
4498
4525
|
let qkv_base = t * params.qkv_dim;
|
|
4499
4526
|
|
|
4500
|
-
// ── Load Q and K into shared memory ──
|
|
4501
|
-
|
|
4502
|
-
|
|
4527
|
+
// ── Load Q and K into shared memory (lane tid covers key_dim <= 128) ──
|
|
4528
|
+
if (tid < params.key_dim) {
|
|
4529
|
+
shared_q[tid] = qkv_conv[qkv_base + q_off + tid];
|
|
4530
|
+
shared_k[tid] = qkv_conv[qkv_base + k_off + tid];
|
|
4531
|
+
shared_norm[tid] = shared_q[tid] * shared_q[tid];
|
|
4532
|
+
} else {
|
|
4533
|
+
shared_norm[tid] = 0.0;
|
|
4534
|
+
}
|
|
4503
4535
|
workgroupBarrier();
|
|
4504
4536
|
|
|
4505
4537
|
// ── L2-normalize Q (parallel reduction) ──
|
|
4506
|
-
shared_norm[d] = shared_q[d] * shared_q[d];
|
|
4507
|
-
workgroupBarrier();
|
|
4508
4538
|
var stride: u32 = 64u;
|
|
4509
4539
|
while (stride > 0u) {
|
|
4510
|
-
if (
|
|
4540
|
+
if (tid < stride) { shared_norm[tid] += shared_norm[tid + stride]; }
|
|
4511
4541
|
workgroupBarrier();
|
|
4512
4542
|
stride /= 2u;
|
|
4513
4543
|
}
|
|
4514
4544
|
let q_inv_norm = 1.0 / sqrt(shared_norm[0] + 1e-12);
|
|
4515
|
-
|
|
4545
|
+
workgroupBarrier();
|
|
4516
4546
|
|
|
4517
4547
|
// ── L2-normalize K (parallel reduction) ──
|
|
4518
|
-
|
|
4548
|
+
if (tid < params.key_dim) {
|
|
4549
|
+
shared_q[tid] *= q_inv_norm;
|
|
4550
|
+
shared_norm[tid] = shared_k[tid] * shared_k[tid];
|
|
4551
|
+
} else {
|
|
4552
|
+
shared_norm[tid] = 0.0;
|
|
4553
|
+
}
|
|
4519
4554
|
workgroupBarrier();
|
|
4520
4555
|
stride = 64u;
|
|
4521
4556
|
while (stride > 0u) {
|
|
4522
|
-
if (
|
|
4557
|
+
if (tid < stride) { shared_norm[tid] += shared_norm[tid + stride]; }
|
|
4523
4558
|
workgroupBarrier();
|
|
4524
4559
|
stride /= 2u;
|
|
4525
4560
|
}
|
|
4526
4561
|
let k_inv_norm = 1.0 / sqrt(shared_norm[0] + 1e-12);
|
|
4527
|
-
|
|
4562
|
+
workgroupBarrier();
|
|
4563
|
+
if (tid < params.key_dim) {
|
|
4564
|
+
shared_k[tid] *= k_inv_norm;
|
|
4565
|
+
}
|
|
4528
4566
|
workgroupBarrier();
|
|
4529
4567
|
|
|
4530
|
-
// ── Compute decay and beta ──
|
|
4568
|
+
// ── Compute decay and beta (redundantly per thread — trivial scalars) ──
|
|
4531
4569
|
let a_val = a_input[t * params.num_heads + h];
|
|
4532
4570
|
let b_val = b_input[t * params.num_heads + h];
|
|
4533
4571
|
let dt_in = a_val + dt_bias[h];
|
|
@@ -4536,32 +4574,52 @@ fn main(
|
|
|
4536
4574
|
let decay = exp(max(g, -80.0));
|
|
4537
4575
|
let beta = 1.0 / (1.0 + exp(max(-b_val, -80.0)));
|
|
4538
4576
|
|
|
4539
|
-
// ── 1+2.
|
|
4540
|
-
// out of the dot product): kv_mem[d] = decay * Σ_k state[k,d] * k_norm[k] ──
|
|
4541
|
-
let v_val = qkv_conv[qkv_base + v_off + d];
|
|
4577
|
+
// ── 1+2. kv_mem[d] = decay * Σ_k state[k,d] * k_norm[k], k split 8 ways ──
|
|
4542
4578
|
var kv_dot: f32 = 0.0;
|
|
4543
|
-
|
|
4544
|
-
|
|
4579
|
+
if (d_ok) {
|
|
4580
|
+
for (var k: u32 = k_begin; k < k_end; k = k + 1u) {
|
|
4581
|
+
kv_dot += f32(ssm_state[state_base + k * params.val_dim + d]) * shared_k[k];
|
|
4582
|
+
}
|
|
4545
4583
|
}
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4584
|
+
shared_partial[d_local * K_SPLITS + k_split] = kv_dot;
|
|
4585
|
+
workgroupBarrier();
|
|
4586
|
+
if (k_split == 0u) {
|
|
4587
|
+
var acc: f32 = 0.0;
|
|
4588
|
+
for (var j: u32 = 0u; j < K_SPLITS; j = j + 1u) {
|
|
4589
|
+
acc += shared_partial[d_local * K_SPLITS + j];
|
|
4590
|
+
}
|
|
4591
|
+
shared_kvmem[d_local] = acc;
|
|
4592
|
+
}
|
|
4593
|
+
workgroupBarrier();
|
|
4550
4594
|
|
|
4551
|
-
// ──
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
let idx = state_base + k * params.val_dim + d;
|
|
4558
|
-
let s = f32(ssm_state[idx]) * decay + shared_k[k] * delta_val;
|
|
4559
|
-
ssm_state[idx] = f16(s);
|
|
4560
|
-
out_val += s * shared_q[k];
|
|
4595
|
+
// ── 3. Delta rule (each of the d's 8 threads recomputes — cheap) ──
|
|
4596
|
+
var delta_val: f32 = 0.0;
|
|
4597
|
+
if (d_ok) {
|
|
4598
|
+
let v_val = qkv_conv[qkv_base + v_off + d];
|
|
4599
|
+
let kv_mem = shared_kvmem[d_local] * decay;
|
|
4600
|
+
delta_val = (v_val - kv_mem) * beta;
|
|
4561
4601
|
}
|
|
4562
|
-
output[t * out_stride + h * params.val_dim + d] = out_val * scale;
|
|
4563
4602
|
|
|
4564
|
-
|
|
4603
|
+
// ── 4+5. Fused decay + rank-1 update + output, k split 8 ways ──
|
|
4604
|
+
var out_dot: f32 = 0.0;
|
|
4605
|
+
if (d_ok) {
|
|
4606
|
+
for (var k: u32 = k_begin; k < k_end; k = k + 1u) {
|
|
4607
|
+
let idx = state_base + k * params.val_dim + d;
|
|
4608
|
+
let s = f32(ssm_state[idx]) * decay + shared_k[k] * delta_val;
|
|
4609
|
+
ssm_state[idx] = f16(s);
|
|
4610
|
+
out_dot += s * shared_q[k];
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4613
|
+
shared_partial[d_local * K_SPLITS + k_split] = out_dot;
|
|
4614
|
+
workgroupBarrier();
|
|
4615
|
+
if (k_split == 0u && d_ok) {
|
|
4616
|
+
var acc: f32 = 0.0;
|
|
4617
|
+
for (var j: u32 = 0u; j < K_SPLITS; j = j + 1u) {
|
|
4618
|
+
acc += shared_partial[d_local * K_SPLITS + j];
|
|
4619
|
+
}
|
|
4620
|
+
output[t * out_stride + h * params.val_dim + d] = acc * scale;
|
|
4621
|
+
}
|
|
4622
|
+
workgroupBarrier(); // sync before next timestep reuses shared arrays
|
|
4565
4623
|
}
|
|
4566
4624
|
}
|
|
4567
4625
|
`;
|
|
@@ -6165,7 +6223,7 @@ const SWIGLU_MATVEC_INT4_SPEC = {
|
|
|
6165
6223
|
getDispatchSize(op) {
|
|
6166
6224
|
const N = op.attributes.N;
|
|
6167
6225
|
return [
|
|
6168
|
-
cdiv(N,
|
|
6226
|
+
cdiv(N, 16),
|
|
6169
6227
|
1,
|
|
6170
6228
|
1
|
|
6171
6229
|
];
|
|
@@ -6200,7 +6258,7 @@ const DUAL_MATVEC_INT4_SPEC = {
|
|
|
6200
6258
|
getDispatchSize(op) {
|
|
6201
6259
|
const N = op.attributes.N;
|
|
6202
6260
|
return [
|
|
6203
|
-
cdiv(N,
|
|
6261
|
+
cdiv(N, 16),
|
|
6204
6262
|
1,
|
|
6205
6263
|
1
|
|
6206
6264
|
];
|
|
@@ -7008,7 +7066,14 @@ const mambaSSMSpec = {
|
|
|
7008
7066
|
};
|
|
7009
7067
|
const MAMBA_SSM_F16_SPEC = {
|
|
7010
7068
|
...mambaSSMSpec,
|
|
7011
|
-
shaderCode: WGSL_MAMBA_SSM_F16
|
|
7069
|
+
shaderCode: WGSL_MAMBA_SSM_F16,
|
|
7070
|
+
getDispatchSize(op) {
|
|
7071
|
+
return [
|
|
7072
|
+
op.attributes.num_heads * 8,
|
|
7073
|
+
1,
|
|
7074
|
+
1
|
|
7075
|
+
];
|
|
7076
|
+
}
|
|
7012
7077
|
};
|
|
7013
7078
|
const kvCacheAppendSpec = {
|
|
7014
7079
|
shaderCode: WGSL_KV_CACHE_APPEND,
|
|
@@ -8908,7 +8973,39 @@ var Executor = class Executor {
|
|
|
8908
8973
|
}
|
|
8909
8974
|
const encoder = this.ctx.device.createCommandEncoder({ label: "decode_step" });
|
|
8910
8975
|
if (tokenId === null) encoder.copyBufferToBuffer(this.argmaxResultBuffer, 0, this.inputIdsBuffer, 0, 4);
|
|
8911
|
-
const
|
|
8976
|
+
const g = globalThis;
|
|
8977
|
+
if (process.env?.GERBIL_TS_TOTAL != null) {
|
|
8978
|
+
g.__tsTotal ??= {
|
|
8979
|
+
ns: 0,
|
|
8980
|
+
steps: 0,
|
|
8981
|
+
seq: 0,
|
|
8982
|
+
inFlight: false
|
|
8983
|
+
};
|
|
8984
|
+
g.__tsTotal.seq++;
|
|
8985
|
+
}
|
|
8986
|
+
const tsTotal = this.ctx.hasTimestamp && typeof process !== "undefined" && process.env?.GERBIL_TS_TOTAL != null && g.__tsTotal.seq % 8 === 0 && !g.__tsTotal.inFlight;
|
|
8987
|
+
if (tsTotal && !this.querySet) {
|
|
8988
|
+
this.querySet = this.ctx.device.createQuerySet({
|
|
8989
|
+
type: "timestamp",
|
|
8990
|
+
count: 2
|
|
8991
|
+
});
|
|
8992
|
+
this.queryResolveBuf = this.ctx.device.createBuffer({
|
|
8993
|
+
size: 16,
|
|
8994
|
+
usage: 516
|
|
8995
|
+
});
|
|
8996
|
+
this.queryReadbackBuf = this.ctx.device.createBuffer({
|
|
8997
|
+
size: 16,
|
|
8998
|
+
usage: 9
|
|
8999
|
+
});
|
|
9000
|
+
}
|
|
9001
|
+
const pass = encoder.beginComputePass(tsTotal ? {
|
|
9002
|
+
label: "decode_pass",
|
|
9003
|
+
timestampWrites: {
|
|
9004
|
+
querySet: this.querySet,
|
|
9005
|
+
beginningOfPassWriteIndex: 0,
|
|
9006
|
+
endOfPassWriteIndex: 1
|
|
9007
|
+
}
|
|
9008
|
+
} : { label: "decode_pass" });
|
|
8912
9009
|
for (let i = 0; i < this.decodeEntries.length; i++) {
|
|
8913
9010
|
const entry = this.decodeEntries[i];
|
|
8914
9011
|
pass.setPipeline(entry.pipeline);
|
|
@@ -8922,7 +9019,27 @@ var Executor = class Executor {
|
|
|
8922
9019
|
}
|
|
8923
9020
|
pass.end();
|
|
8924
9021
|
encoder.copyBufferToBuffer(this.argmaxResultBuffer, 0, this.decodeReadbacks[slot], 0, 4);
|
|
9022
|
+
if (tsTotal) {
|
|
9023
|
+
encoder.resolveQuerySet(this.querySet, 0, 2, this.queryResolveBuf, 0);
|
|
9024
|
+
encoder.copyBufferToBuffer(this.queryResolveBuf, 0, this.queryReadbackBuf, 0, 16);
|
|
9025
|
+
}
|
|
8925
9026
|
this.ctx.device.queue.submit([encoder.finish()]);
|
|
9027
|
+
if (tsTotal) {
|
|
9028
|
+
const rb = this.queryReadbackBuf;
|
|
9029
|
+
const acc = g.__tsTotal;
|
|
9030
|
+
acc.inFlight = true;
|
|
9031
|
+
(async () => {
|
|
9032
|
+
try {
|
|
9033
|
+
await rb.mapAsync(MAP_MODE_READ$1, 0, 16);
|
|
9034
|
+
const ts = new BigUint64Array(rb.getMappedRange(0, 16).slice(0));
|
|
9035
|
+
rb.unmap();
|
|
9036
|
+
acc.ns += Number(ts[1] - ts[0]);
|
|
9037
|
+
acc.steps += 1;
|
|
9038
|
+
} catch {} finally {
|
|
9039
|
+
acc.inFlight = false;
|
|
9040
|
+
}
|
|
9041
|
+
})();
|
|
9042
|
+
}
|
|
8926
9043
|
this.seqPos += 1;
|
|
8927
9044
|
}
|
|
8928
9045
|
/** Read back the token produced by the pipelined step that used `slot`. */
|
|
@@ -10013,6 +10130,47 @@ function repackMLX(mlx) {
|
|
|
10013
10130
|
zeros
|
|
10014
10131
|
};
|
|
10015
10132
|
}
|
|
10133
|
+
/**
|
|
10134
|
+
* Dequantize an MLX affine-quantized tensor of arbitrary bit width to f32.
|
|
10135
|
+
*
|
|
10136
|
+
* MLX packs the unsigned integer codes as a CONTIGUOUS little-endian bitstream
|
|
10137
|
+
* (verified against ml-explore/mlx `extract_bits`): code `i` occupies bits
|
|
10138
|
+
* `[i*bits, i*bits+bits)` of the per-row byte stream, straddling byte/word
|
|
10139
|
+
* boundaries when `bits` does not divide 8 evenly. Power-of-two bit widths
|
|
10140
|
+
* (4/8) divide evenly so codes never straddle; 6-bit packs 4 codes per 3 bytes.
|
|
10141
|
+
*
|
|
10142
|
+
* Dequant (affine mode): `w = scale * q + bias`, with one (scale, bias) pair per
|
|
10143
|
+
* group of `groupSize` codes along K (the last axis), groups laid out row-major.
|
|
10144
|
+
*
|
|
10145
|
+
* The weight buffer is provided as a Uint32Array (how the store holds it); we
|
|
10146
|
+
* read it as a flat little-endian byte view so the bitstream is contiguous
|
|
10147
|
+
* across the whole row regardless of the 4-byte word boundaries.
|
|
10148
|
+
*
|
|
10149
|
+
* Returns a flat Float32Array of shape [N, K] in row-major order — directly
|
|
10150
|
+
* consumable by `quantizeInt4` for repacking into Gerbil's 4-bit kernels.
|
|
10151
|
+
*/
|
|
10152
|
+
function dequantizeMLX(mlx) {
|
|
10153
|
+
const { weight, scales: mlxScales, biases: mlxBiases, N, K, groupSize, bits } = mlx;
|
|
10154
|
+
const groupsPerRow = Math.ceil(K / groupSize);
|
|
10155
|
+
const mask = (1 << bits) - 1;
|
|
10156
|
+
const bytes = new Uint8Array(weight.buffer, weight.byteOffset, weight.byteLength);
|
|
10157
|
+
const bytesPerRow = Math.ceil(K * bits / 8);
|
|
10158
|
+
const out = new Float32Array(N * K);
|
|
10159
|
+
for (let row = 0; row < N; row++) {
|
|
10160
|
+
const rowByteBase = row * bytesPerRow;
|
|
10161
|
+
const rowGroupBase = row * groupsPerRow;
|
|
10162
|
+
const rowOutBase = row * K;
|
|
10163
|
+
for (let col = 0; col < K; col++) {
|
|
10164
|
+
const bitPos = col * bits;
|
|
10165
|
+
const byteIdx = rowByteBase + (bitPos >> 3);
|
|
10166
|
+
const bitOff = bitPos & 7;
|
|
10167
|
+
const q = (bytes[byteIdx] | bytes[byteIdx + 1] << 8 | bytes[byteIdx + 2] << 16) >>> bitOff & mask;
|
|
10168
|
+
const g = rowGroupBase + Math.floor(col / groupSize);
|
|
10169
|
+
out[rowOutBase + col] = mlxScales[g] * q + mlxBiases[g];
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
return out;
|
|
10173
|
+
}
|
|
10016
10174
|
|
|
10017
10175
|
//#endregion
|
|
10018
10176
|
//#region src/gpu/opfs-cache.ts
|
|
@@ -10479,6 +10637,19 @@ const UNICODE_TO_BYTE = /* @__PURE__ */ new Map();
|
|
|
10479
10637
|
}
|
|
10480
10638
|
/** SentencePiece metaspace marker (U+2581, "▁") used by T5/Unigram tokenizers. */
|
|
10481
10639
|
const METASPACE = "▁";
|
|
10640
|
+
/**
|
|
10641
|
+
* Matches the Qwen3.5-style empty-think prefill that a chat template emits after
|
|
10642
|
+
* `add_generation_prompt` (e.g. `{{- '<think>\n\n</think>\n\n' }}`). Used to
|
|
10643
|
+
* decide whether to inject the empty think block — LFM2.5 templates reference
|
|
10644
|
+
* `<think>` only to re-render prior assistant `.thinking` content and must NOT
|
|
10645
|
+
* be matched, so we look for the empty `<think></think>` pair specifically.
|
|
10646
|
+
*
|
|
10647
|
+
* The gap between the tags must tolerate BOTH real whitespace and the LITERAL
|
|
10648
|
+
* backslash-escape text (`\n`, `\r`, `\t`) that survives in the raw Jinja string
|
|
10649
|
+
* source — Qwen3.5 ships the prefill as the two-character `\n` sequences, not
|
|
10650
|
+
* actual newlines, so a plain `\s*` would miss it and drop Qwen's think block.
|
|
10651
|
+
*/
|
|
10652
|
+
const EMPTY_THINK_PREFILL = /<think>(?:\s|\\[nrt])*<\/think>/;
|
|
10482
10653
|
var Tokenizer = class Tokenizer {
|
|
10483
10654
|
vocab;
|
|
10484
10655
|
vocabReverse;
|
|
@@ -10742,7 +10913,7 @@ var Tokenizer = class Tokenizer {
|
|
|
10742
10913
|
for (const msg of messages) parts.push(`<|im_start|>${msg.role}\n${msg.content}<|im_end|>\n`);
|
|
10743
10914
|
if (addGenPrompt) {
|
|
10744
10915
|
parts.push(`<|im_start|>assistant\n`);
|
|
10745
|
-
if (template ?
|
|
10916
|
+
if (template ? EMPTY_THINK_PREFILL.test(template) : this.addedTokens.has("<think>")) parts.push(`<think>\n\n</think>\n\n`);
|
|
10746
10917
|
}
|
|
10747
10918
|
return parts.join("");
|
|
10748
10919
|
}
|
|
@@ -12322,6 +12493,12 @@ async function loadModel(options) {
|
|
|
12322
12493
|
if (isMLX) {
|
|
12323
12494
|
onProgress?.(96, 100, "Repacking MLX weights...");
|
|
12324
12495
|
const mlxGS = quantConfig?.group_size ?? 64;
|
|
12496
|
+
const mlxDefaultBits = quantConfig?.bits ?? 4;
|
|
12497
|
+
const bitsForBase = (baseName) => {
|
|
12498
|
+
if (!quantConfig) return mlxDefaultBits;
|
|
12499
|
+
for (const [key, val] of Object.entries(quantConfig)) if (val && typeof val === "object" && typeof val.bits === "number" && (key === baseName || key.endsWith(`.${baseName}`))) return val.bits;
|
|
12500
|
+
return mlxDefaultBits;
|
|
12501
|
+
};
|
|
12325
12502
|
for (const node of graph.nodes) {
|
|
12326
12503
|
if (node.opType !== "MatMulInt4" && node.opType !== "EmbeddingInt4") continue;
|
|
12327
12504
|
let N, K;
|
|
@@ -12341,26 +12518,54 @@ async function loadModel(options) {
|
|
|
12341
12518
|
const mlxScales = await store.get(`${baseName}.scales`);
|
|
12342
12519
|
const mlxBiases = await store.get(`${baseName}.biases`);
|
|
12343
12520
|
if (!mlxWeight || !mlxScales || !mlxBiases) continue;
|
|
12344
|
-
const
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12521
|
+
const weightData = mlxWeight.data instanceof Uint32Array ? mlxWeight.data : new Uint32Array(mlxWeight.data.buffer, mlxWeight.data.byteOffset, mlxWeight.data.byteLength / 4);
|
|
12522
|
+
const scalesData = mlxScales.data instanceof Float32Array ? mlxScales.data : new Float32Array(mlxScales.data.buffer, mlxScales.data.byteOffset, mlxScales.data.byteLength / 4);
|
|
12523
|
+
const biasesData = mlxBiases.data instanceof Float32Array ? mlxBiases.data : new Float32Array(mlxBiases.data.buffer, mlxBiases.data.byteOffset, mlxBiases.data.byteLength / 4);
|
|
12524
|
+
const srcBits = bitsForBase(baseName);
|
|
12525
|
+
if (srcBits === 4) {
|
|
12526
|
+
const repacked = repackMLX({
|
|
12527
|
+
weight: weightData,
|
|
12528
|
+
scales: scalesData,
|
|
12529
|
+
biases: biasesData,
|
|
12530
|
+
N,
|
|
12531
|
+
K,
|
|
12532
|
+
groupSize: mlxGS
|
|
12533
|
+
});
|
|
12534
|
+
await store.set(qTensorName, {
|
|
12535
|
+
data: repacked.packed,
|
|
12536
|
+
shape: [repacked.packed.length]
|
|
12537
|
+
});
|
|
12538
|
+
await store.set(scalesTensorName, {
|
|
12539
|
+
data: repacked.scales,
|
|
12540
|
+
shape: [repacked.scales.length]
|
|
12541
|
+
});
|
|
12542
|
+
await store.set(zerosTensorName, {
|
|
12543
|
+
data: repacked.zeros,
|
|
12544
|
+
shape: [repacked.zeros.length]
|
|
12545
|
+
});
|
|
12546
|
+
} else {
|
|
12547
|
+
const { packed, scales, zeros } = quantizeInt4(dequantizeMLX({
|
|
12548
|
+
weight: weightData,
|
|
12549
|
+
scales: scalesData,
|
|
12550
|
+
biases: biasesData,
|
|
12551
|
+
N,
|
|
12552
|
+
K,
|
|
12553
|
+
groupSize: mlxGS,
|
|
12554
|
+
bits: srcBits
|
|
12555
|
+
}), mlxGS);
|
|
12556
|
+
await store.set(qTensorName, {
|
|
12557
|
+
data: packed,
|
|
12558
|
+
shape: [packed.length]
|
|
12559
|
+
});
|
|
12560
|
+
await store.set(scalesTensorName, {
|
|
12561
|
+
data: scales,
|
|
12562
|
+
shape: [scales.length]
|
|
12563
|
+
});
|
|
12564
|
+
await store.set(zerosTensorName, {
|
|
12565
|
+
data: zeros,
|
|
12566
|
+
shape: [zeros.length]
|
|
12567
|
+
});
|
|
12568
|
+
}
|
|
12364
12569
|
await store.delete(sourceName);
|
|
12365
12570
|
await store.delete(`${baseName}.scales`);
|
|
12366
12571
|
await store.delete(`${baseName}.biases`);
|
|
@@ -13220,4 +13425,4 @@ function selectGraphWeights(graph, weights) {
|
|
|
13220
13425
|
|
|
13221
13426
|
//#endregion
|
|
13222
13427
|
export { verifyGPU as S, createStorageBuffer as _, loadMoonshine as a, getOrCreatePipeline as b, quantizeBackboneInt4 as c, Tokenizer as d, Executor as f, createBindGroup as g, clearPipelineCache as h, loadModel as i, quantizeKaniBackbone as l, MATMUL_BIAS_F16C_SPEC as m, MoonshineEncoderExecutor as n, loadOuteTTS as o, KERNEL_REGISTRY as p, loadKaniTTS as r, loadParlerTTS as s, MoonshineSTT as t, remapPrunedToken as u, createUniformBuffer as v, initGPU as x, destroyBuffers as y };
|
|
13223
|
-
//# sourceMappingURL=moonshine-stt-
|
|
13428
|
+
//# sourceMappingURL=moonshine-stt-bExSnd2o.mjs.map
|