@tryhamster/gerbil 1.1.2 → 1.2.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/README.md +18 -16
- package/dist/{architectures-wan0swXu.mjs → architectures-Ol7yUmKf.mjs} +128 -68
- package/dist/architectures-Ol7yUmKf.mjs.map +1 -0
- package/dist/cli.mjs +8 -8
- package/dist/cli.mjs.map +1 -1
- package/dist/{defaults-9komdrbY.mjs → defaults-bJcmOaRG.mjs} +2 -2
- package/dist/defaults-bJcmOaRG.mjs.map +1 -0
- 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.d.mts +2 -2
- package/dist/frameworks/next.mjs +1 -1
- package/dist/frameworks/trpc.mjs +1 -1
- package/dist/gerbil-BjGA5L2E.mjs +4 -0
- package/dist/{gerbil-DZbWbIm2.d.mts → gerbil-CCVOEU-J.d.mts} +2 -2
- package/dist/{gerbil-DZbWbIm2.d.mts.map → gerbil-CCVOEU-J.d.mts.map} +1 -1
- package/dist/{gerbil-CQspp8fS.mjs → gerbil-Cv7rXGOV.mjs} +2 -2
- package/dist/{gerbil-CQspp8fS.mjs.map → gerbil-Cv7rXGOV.mjs.map} +1 -1
- package/dist/gpu/hooks.d.mts +27 -10
- package/dist/gpu/hooks.d.mts.map +1 -1
- package/dist/gpu/hooks.mjs +19 -12
- package/dist/gpu/hooks.mjs.map +1 -1
- package/dist/gpu/index.d.mts +2 -2
- package/dist/gpu/index.mjs +5 -5
- package/dist/{gpu-BYCQ5aTI.mjs → gpu-BWLMlkVW.mjs} +78 -21
- package/dist/gpu-BWLMlkVW.mjs.map +1 -0
- package/dist/{index-CKszv3lt.d.mts → index-CSLqgNu-.d.mts} +212 -133
- package/dist/index-CSLqgNu-.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +6 -6
- 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.d.mts +2 -2
- package/dist/integrations/mcp.mjs +4 -4
- package/dist/{mcp-CszII8GJ.mjs → mcp-C0yKaH39.mjs} +3 -3
- package/dist/{mcp-CszII8GJ.mjs.map → mcp-C0yKaH39.mjs.map} +1 -1
- package/dist/{moonshine-stt-DDUm5WfP.mjs → moonshine-stt-C4GKK-h5.mjs} +45 -5
- package/dist/{moonshine-stt-DDUm5WfP.mjs.map → moonshine-stt-C4GKK-h5.mjs.map} +1 -1
- package/dist/moonshine-stt-zJ9YEi1X.mjs +4 -0
- package/dist/{one-liner-DVche8Eg.mjs → one-liner-DfJh2O0X.mjs} +2 -2
- package/dist/{one-liner-DVche8Eg.mjs.map → one-liner-DfJh2O0X.mjs.map} +1 -1
- package/dist/repl-DTSxHD6t.mjs +9 -0
- package/dist/skills/index.d.mts +2 -2
- package/dist/skills/index.d.mts.map +1 -1
- package/dist/skills/index.mjs +3 -3
- package/dist/{skills-BQI-VSn2.mjs → skills-B5cDRVJ1.mjs} +2 -2
- package/dist/{skills-BQI-VSn2.mjs.map → skills-B5cDRVJ1.mjs.map} +1 -1
- package/package.json +1 -2
- package/dist/architectures-wan0swXu.mjs.map +0 -1
- package/dist/defaults-9komdrbY.mjs.map +0 -1
- package/dist/gerbil-tHnYb9nZ.mjs +0 -4
- package/dist/gpu-BYCQ5aTI.mjs.map +0 -1
- package/dist/index-CKszv3lt.d.mts.map +0 -1
- package/dist/moonshine-stt-BtR-KiSP.mjs +0 -4
- package/dist/repl-BYJA2U7t.mjs +0 -9
- package/docs/PROJECT-STATE.md +0 -321
- package/docs/adding-a-model-family.md +0 -280
- package/docs/ai-sdk.md +0 -205
- package/docs/architecture/README.md +0 -84
- package/docs/architecture/caching.md +0 -227
- package/docs/architecture/inference.md +0 -176
- package/docs/architecture/overview.md +0 -189
- package/docs/architecture/streaming.md +0 -261
- package/docs/architecture/webgpu.md +0 -213
- package/docs/browser.md +0 -762
- package/docs/cli.md +0 -155
- package/docs/embeddings.md +0 -156
- package/docs/frameworks.md +0 -90
- package/docs/gerbil-site-native-migration.md +0 -217
- package/docs/gpu-engine/architectures.md +0 -398
- package/docs/gpu-engine/ir.md +0 -372
- package/docs/gpu-engine/kernels.md +0 -718
- package/docs/gpu-engine/paper.html +0 -1759
- package/docs/gpu-engine/paper.md +0 -2109
- package/docs/gpu-engine/safetensors.md +0 -312
- package/docs/gpu-engine/tokenizer.md +0 -302
- package/docs/kernel-research-queue.md +0 -85
- package/docs/mcp-client.md +0 -224
- package/docs/mcp.md +0 -109
- package/docs/memory-rag.md +0 -91
- package/docs/memory.md +0 -301
- package/docs/metal-safari-intel.md +0 -190
- package/docs/mobile-failure-diagnosis.md +0 -124
- package/docs/mobile.md +0 -99
- package/docs/observability.md +0 -230
- package/docs/onnx-removal-plan.md +0 -339
- package/docs/repl.md +0 -473
- package/docs/research/autoresearch-portable.md +0 -933
- package/docs/research/dispatch-reduction-hivemind.md +0 -84
- package/docs/research/ios-safari-model-caching.md +0 -117
- package/docs/research/mobile-webgpu-speed-fusion.md +0 -135
- package/docs/research/native-stt-model-selection.md +0 -49
- package/docs/research/native-tts-model-selection.md +0 -90
- package/docs/research/native-vs-chromium-decision.md +0 -152
- package/docs/research/nemotron-mamba2-inference.md +0 -910
- package/docs/research/qwen35-multimodal.md +0 -293
- package/docs/research/qwen36-gemma4-targets.md +0 -337
- package/docs/research/sota-embedding-models.md +0 -179
- package/docs/research/sota-mobile-models-2026.md +0 -263
- package/docs/research/sota-modality-models.md +0 -202
- package/docs/research/tps-baselines.md +0 -71
- package/docs/research/webgpu-m4-reference.md +0 -104
- package/docs/site-update-plan.md +0 -155
- package/docs/skills.md +0 -261
- package/docs/structured-output.md +0 -123
- package/docs/stt.md +0 -111
- package/docs/tools.md +0 -304
- package/docs/tts.md +0 -147
- package/docs/vision.md +0 -158
package/README.md
CHANGED
|
@@ -123,12 +123,12 @@ For a copy-pasteable version see [`examples/benchmark.ts`](./examples/benchmark.
|
|
|
123
123
|
|
|
124
124
|
## React Quickstart
|
|
125
125
|
|
|
126
|
-
`useEngine` (from `@tryhamster/gerbil/
|
|
126
|
+
`useEngine` (from `@tryhamster/gerbil/hooks`) owns the full engine lifecycle —
|
|
127
127
|
load, unload, hot-swap on config change, and reference-counted sharing so multiple
|
|
128
128
|
components never upload the same weights to the GPU twice.
|
|
129
129
|
|
|
130
130
|
```tsx
|
|
131
|
-
import { useEngine } from "@tryhamster/gerbil/
|
|
131
|
+
import { useEngine } from "@tryhamster/gerbil/hooks";
|
|
132
132
|
|
|
133
133
|
function Chat() {
|
|
134
134
|
const { complete, completion, isLoading, isGenerating, tps } = useEngine({
|
|
@@ -156,7 +156,7 @@ and `dispose`. Pass `enableVision: true` or `embedding: true` to load those moda
|
|
|
156
156
|
until the engine is ready — and keep it warm across navigation (no GPU re-upload):
|
|
157
157
|
|
|
158
158
|
```tsx
|
|
159
|
-
import { GerbilGate } from "@tryhamster/gerbil/
|
|
159
|
+
import { GerbilGate } from "@tryhamster/gerbil/hooks";
|
|
160
160
|
|
|
161
161
|
<GerbilGate
|
|
162
162
|
model="mlx-community/Qwen3.5-0.8B-4bit"
|
|
@@ -199,10 +199,10 @@ const engine = await WebGPUEngine.create({ repo: "mlx-community/Qwen3.5-0.8B-4bi
|
|
|
199
199
|
await engine.generateObject("…", { schema: { required: ["title"] } });
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
-
In React, use `useObject` (from `@tryhamster/gerbil/
|
|
202
|
+
In React, use `useObject` (from `@tryhamster/gerbil/hooks`):
|
|
203
203
|
|
|
204
204
|
```tsx
|
|
205
|
-
import { useObject } from "@tryhamster/gerbil/
|
|
205
|
+
import { useObject } from "@tryhamster/gerbil/hooks";
|
|
206
206
|
|
|
207
207
|
const { generate, object, isGenerating } = useObject<{ city: string }>();
|
|
208
208
|
await generate("Extract the city from: I live in Paris", {
|
|
@@ -322,17 +322,19 @@ const skill = useSkill("my-skill");
|
|
|
322
322
|
|
|
323
323
|
## Tools & Agents
|
|
324
324
|
|
|
325
|
-
Gerbil supports tool calling with Qwen3 models for agentic workflows
|
|
325
|
+
Gerbil supports tool calling with Qwen3 models for agentic workflows. A tool is a
|
|
326
|
+
plain object (`AgentTool`) — give it a `name`, `description`, optional `parameters`,
|
|
327
|
+
and an `execute` function:
|
|
326
328
|
|
|
327
329
|
```typescript
|
|
328
|
-
import {
|
|
330
|
+
import type { AgentTool } from "@tryhamster/gerbil/gpu";
|
|
329
331
|
|
|
330
|
-
const weatherTool =
|
|
332
|
+
const weatherTool: AgentTool = {
|
|
331
333
|
name: "get_weather",
|
|
332
334
|
description: "Get weather for a city",
|
|
333
|
-
parameters:
|
|
334
|
-
execute:
|
|
335
|
-
}
|
|
335
|
+
parameters: { city: "string" },
|
|
336
|
+
execute: ({ city }) => `Weather in ${city}: 72°F, sunny`,
|
|
337
|
+
};
|
|
336
338
|
```
|
|
337
339
|
|
|
338
340
|
**Agentic loop, on-device.** `engine.generateWithTools` (and the `useAgent` React hook)
|
|
@@ -340,7 +342,7 @@ run the whole loop — generate → call a tool → feed the result back → rep
|
|
|
340
342
|
step trace for UIs:
|
|
341
343
|
|
|
342
344
|
```tsx
|
|
343
|
-
import { useAgent } from "@tryhamster/gerbil/
|
|
345
|
+
import { useAgent } from "@tryhamster/gerbil/hooks";
|
|
344
346
|
|
|
345
347
|
const { run, steps, answer, isRunning } = useAgent({
|
|
346
348
|
model: "mlx-community/Qwen3.5-0.8B-4bit",
|
|
@@ -377,7 +379,7 @@ Inline autocomplete — `engine.autocomplete(prefix)` and the debounced `useAuto
|
|
|
377
379
|
hook return a brief single-line continuation (low-latency defaults + cleanup):
|
|
378
380
|
|
|
379
381
|
```tsx
|
|
380
|
-
import { useAutocomplete } from "@tryhamster/gerbil/
|
|
382
|
+
import { useAutocomplete } from "@tryhamster/gerbil/hooks";
|
|
381
383
|
|
|
382
384
|
const { suggestion, onInput, accept, dismiss } = useAutocomplete({
|
|
383
385
|
model: "mlx-community/Qwen3.5-0.8B-4bit",
|
|
@@ -418,10 +420,10 @@ gerbil update # Update to latest version
|
|
|
418
420
|
## Browser Usage
|
|
419
421
|
|
|
420
422
|
Run LLMs directly in the browser with WebGPU — no server required. The React hooks
|
|
421
|
-
live at `@tryhamster/gerbil/
|
|
423
|
+
live at `@tryhamster/gerbil/hooks` and run pure WebGPU compute:
|
|
422
424
|
|
|
423
425
|
```tsx
|
|
424
|
-
import { useChat } from "@tryhamster/gerbil/
|
|
426
|
+
import { useChat } from "@tryhamster/gerbil/hooks";
|
|
425
427
|
|
|
426
428
|
function Chat() {
|
|
427
429
|
const { messages, send, isLoading, isGenerating } = useChat();
|
|
@@ -454,7 +456,7 @@ function Chat() {
|
|
|
454
456
|
| **LangChain** | `@tryhamster/gerbil/langchain` | [📖 LangChain](https://gerbilsdk.com/docs/frameworks/langchain) |
|
|
455
457
|
| **MCP Server** | `npx @tryhamster/gerbil serve --mcp` | [📖 MCP](https://gerbilsdk.com/docs/mcp) |
|
|
456
458
|
|
|
457
|
-
**Native engine:** `import { WebGPUEngine } from "@tryhamster/gerbil/gpu"` (or `useEngine` from `@tryhamster/gerbil/
|
|
459
|
+
**Native engine:** `import { WebGPUEngine } from "@tryhamster/gerbil/gpu"` (or `useEngine` from `@tryhamster/gerbil/hooks` for React) is the primary surface for text, vision, embeddings, and speech.
|
|
458
460
|
|
|
459
461
|
## Supported Models
|
|
460
462
|
|
|
@@ -148,6 +148,66 @@ function createDefaultHFKeyMapper() {
|
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/gpu/quantize.ts
|
|
153
|
+
/**
|
|
154
|
+
* On-the-fly INT4 quantization for WebGPU inference.
|
|
155
|
+
*
|
|
156
|
+
* Converts F32 weight matrices to 4-bit unsigned integers with per-group
|
|
157
|
+
* scale/zero-point parameters. Matches the dequantization formula in the
|
|
158
|
+
* MatMulInt4 WGSL kernel:
|
|
159
|
+
*
|
|
160
|
+
* dequant_val = (raw_nibble - zero) * scale
|
|
161
|
+
*
|
|
162
|
+
* Packing: 8 × 4-bit values per u32, little-nibble-first order.
|
|
163
|
+
* Grouping: contiguous elements in row-major (K × N) layout.
|
|
164
|
+
*/
|
|
165
|
+
const DEFAULT_GROUP_SIZE = 128;
|
|
166
|
+
/**
|
|
167
|
+
* Quantize a flat F32 weight array to INT4.
|
|
168
|
+
*
|
|
169
|
+
* @param data - Source F32 weight data (row-major, K × N elements)
|
|
170
|
+
* @param groupSize - Number of elements per quantization group (default 128)
|
|
171
|
+
* @returns Packed INT4 data with per-group scales and zeros
|
|
172
|
+
*/
|
|
173
|
+
function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
|
|
174
|
+
const totalElements = data.length;
|
|
175
|
+
const numGroups = Math.ceil(totalElements / groupSize);
|
|
176
|
+
const packedSize = Math.ceil(totalElements / 8);
|
|
177
|
+
const packed = new Uint32Array(packedSize);
|
|
178
|
+
const scales = new Float32Array(numGroups);
|
|
179
|
+
const zeros = new Float32Array(numGroups);
|
|
180
|
+
for (let g = 0; g < numGroups; g++) {
|
|
181
|
+
const start = g * groupSize;
|
|
182
|
+
const end = Math.min(start + groupSize, totalElements);
|
|
183
|
+
let min = data[start];
|
|
184
|
+
let max = data[start];
|
|
185
|
+
for (let i = start + 1; i < end; i++) {
|
|
186
|
+
const v = data[i];
|
|
187
|
+
if (v < min) min = v;
|
|
188
|
+
if (v > max) max = v;
|
|
189
|
+
}
|
|
190
|
+
const range = max - min;
|
|
191
|
+
const scale = range > 0 ? range / 15 : 1;
|
|
192
|
+
const zero = range > 0 ? -min / scale : 0;
|
|
193
|
+
scales[g] = scale;
|
|
194
|
+
zeros[g] = zero;
|
|
195
|
+
const invRange = range > 0 ? 15 / range : 0;
|
|
196
|
+
for (let i = start; i < end; i++) {
|
|
197
|
+
const q = Math.round((data[i] - min) * invRange);
|
|
198
|
+
const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
|
|
199
|
+
const packedIdx = i >>> 3;
|
|
200
|
+
const nibblePos = i & 7;
|
|
201
|
+
packed[packedIdx] |= clamped << nibblePos * 4;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
packed,
|
|
206
|
+
scales,
|
|
207
|
+
zeros
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
151
211
|
//#endregion
|
|
152
212
|
//#region src/gpu/architectures/kani_tts.ts
|
|
153
213
|
const KANI_TOKENISER_LENGTH = 64400;
|
|
@@ -195,19 +255,23 @@ const NANOCODEC_BASE_CHANNELS = 864;
|
|
|
195
255
|
const NANOCODEC_INPUT_DIM = 16;
|
|
196
256
|
function parseKaniConfig(rawConfig) {
|
|
197
257
|
const textVocabSize = rawConfig.text_vocab_size ?? KANI_TOKENISER_LENGTH;
|
|
258
|
+
const useLearnableRope = rawConfig.use_learnable_rope ?? false;
|
|
259
|
+
const archList = rawConfig.architectures ?? [];
|
|
260
|
+
const isKaniTTS2 = useLearnableRope || rawConfig.tokens_per_frame != null || rawConfig.audio_step != null || archList.includes("KaniTTS2ForCausalLM");
|
|
198
261
|
return {
|
|
199
262
|
textVocabSize,
|
|
200
263
|
vocabSize: rawConfig.vocab_size,
|
|
201
264
|
tokensPerFrame: rawConfig.tokens_per_frame ?? KANI_TOKENS_PER_FRAME,
|
|
202
265
|
audioStep: rawConfig.audio_step ?? 1,
|
|
203
|
-
useLearnableRope
|
|
266
|
+
useLearnableRope,
|
|
204
267
|
alphaMin: rawConfig.alpha_min ?? .1,
|
|
205
268
|
alphaMax: rawConfig.alpha_max ?? 2,
|
|
206
269
|
speakerEmbDim: rawConfig.speaker_emb_dim ?? 128,
|
|
207
270
|
audioTokensStart: textVocabSize + 10,
|
|
208
271
|
startOfSpeech: textVocabSize + 1,
|
|
209
272
|
endOfSpeech: textVocabSize + 2,
|
|
210
|
-
codebookSize: KANI_CODEBOOK_SIZE
|
|
273
|
+
codebookSize: KANI_CODEBOOK_SIZE,
|
|
274
|
+
frameLevelPositions: isKaniTTS2
|
|
211
275
|
};
|
|
212
276
|
}
|
|
213
277
|
/**
|
|
@@ -249,6 +313,10 @@ function kaniAttentionLayerIndices(rawConfig) {
|
|
|
249
313
|
*/
|
|
250
314
|
function computeKaniPositions(tokenIds, cfg = parseKaniConfig({})) {
|
|
251
315
|
const pos = new Float32Array(tokenIds.length);
|
|
316
|
+
if (!cfg.frameLevelPositions) {
|
|
317
|
+
for (let t = 0; t < tokenIds.length; t++) pos[t] = t;
|
|
318
|
+
return pos;
|
|
319
|
+
}
|
|
252
320
|
let textCount = 0;
|
|
253
321
|
let audioTokenCount = 0;
|
|
254
322
|
for (let t = 0; t < tokenIds.length; t++) {
|
|
@@ -652,15 +720,25 @@ function computeKaniFfnDim(rawConfig) {
|
|
|
652
720
|
return ff;
|
|
653
721
|
}
|
|
654
722
|
/**
|
|
655
|
-
* Generate the
|
|
723
|
+
* Generate the KaniTTS codec-LM backbone graph (LFM2-350M body, full-vocab logits,
|
|
656
724
|
* per-layer learnable MRoPE). Mirrors generateLfm2Graph block-for-block; the only
|
|
657
725
|
* difference is that each attention layer rotates Q/K with the MRoPE op fed a
|
|
658
726
|
* per-layer host cos/sin table instead of the position-counter RoPE op.
|
|
659
727
|
*
|
|
660
|
-
*
|
|
728
|
+
* dtype:
|
|
729
|
+
* • undefined / "f32" — full precision (the checkpoint is bf16/f32 → f32).
|
|
730
|
+
* • "q4" — weight-only group-wise INT4 (W4A16) for the LFM2 linear projections
|
|
731
|
+
* (q/k/v/o, gate/up/down, short-conv in/out_proj) via MatMulInt4. The tied
|
|
732
|
+
* embedding + LM head stay at f32 on purpose: decoder-LM heads are the most
|
|
733
|
+
* quantization-sensitive part of a codec-LM and the embed table is the single
|
|
734
|
+
* buffer shared by both, so quantizing it would degrade audio quality for no
|
|
735
|
+
* load-size win that the int4 projections do not already capture. Backbone
|
|
736
|
+
* drops from ~1.5 GB (f32) to ~0.37 GB. The NanoCodec decoder is a separate
|
|
737
|
+
* graph and always runs f32.
|
|
661
738
|
*/
|
|
662
|
-
function generateKaniTtsGraph(rawConfig, dtype,
|
|
663
|
-
|
|
739
|
+
function generateKaniTtsGraph(rawConfig, dtype, groupSize, kvDtype) {
|
|
740
|
+
const useQ4 = dtype === "q4";
|
|
741
|
+
const groupSz = groupSize ?? DEFAULT_GROUP_SIZE;
|
|
664
742
|
const hidden_size = rawConfig.hidden_size;
|
|
665
743
|
const num_layers = rawConfig.num_hidden_layers;
|
|
666
744
|
const num_heads = rawConfig.num_attention_heads;
|
|
@@ -711,6 +789,48 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
|
|
|
711
789
|
executionOrder.push(node.id);
|
|
712
790
|
};
|
|
713
791
|
const addLinear = (id, activationInput, weightName, weightShape, outputName, K, N) => {
|
|
792
|
+
if (useQ4) {
|
|
793
|
+
const wQ = `${weightName}.q`;
|
|
794
|
+
const wScales = `${weightName}.scales`;
|
|
795
|
+
const wZeros = `${weightName}.zeros`;
|
|
796
|
+
const totalElements = K * N;
|
|
797
|
+
addTensor({
|
|
798
|
+
name: wQ,
|
|
799
|
+
shape: [Math.ceil(totalElements / 8)],
|
|
800
|
+
dtype: "u32",
|
|
801
|
+
storage: "constant"
|
|
802
|
+
});
|
|
803
|
+
addTensor({
|
|
804
|
+
name: wScales,
|
|
805
|
+
shape: [Math.ceil(totalElements / groupSz)],
|
|
806
|
+
dtype: "f32",
|
|
807
|
+
storage: "constant"
|
|
808
|
+
});
|
|
809
|
+
addTensor({
|
|
810
|
+
name: wZeros,
|
|
811
|
+
shape: [Math.ceil(totalElements / groupSz)],
|
|
812
|
+
dtype: "f32",
|
|
813
|
+
storage: "constant"
|
|
814
|
+
});
|
|
815
|
+
addNode({
|
|
816
|
+
id,
|
|
817
|
+
opType: "MatMulInt4",
|
|
818
|
+
inputs: [
|
|
819
|
+
activationInput,
|
|
820
|
+
wQ,
|
|
821
|
+
wScales,
|
|
822
|
+
wZeros
|
|
823
|
+
],
|
|
824
|
+
outputs: [outputName],
|
|
825
|
+
attributes: {
|
|
826
|
+
M_tensor: activationInput,
|
|
827
|
+
K,
|
|
828
|
+
N,
|
|
829
|
+
group_size: groupSz
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
714
834
|
addTensor({
|
|
715
835
|
name: weightName,
|
|
716
836
|
shape: weightShape,
|
|
@@ -1239,66 +1359,6 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
|
|
|
1239
1359
|
};
|
|
1240
1360
|
}
|
|
1241
1361
|
|
|
1242
|
-
//#endregion
|
|
1243
|
-
//#region src/gpu/quantize.ts
|
|
1244
|
-
/**
|
|
1245
|
-
* On-the-fly INT4 quantization for WebGPU inference.
|
|
1246
|
-
*
|
|
1247
|
-
* Converts F32 weight matrices to 4-bit unsigned integers with per-group
|
|
1248
|
-
* scale/zero-point parameters. Matches the dequantization formula in the
|
|
1249
|
-
* MatMulInt4 WGSL kernel:
|
|
1250
|
-
*
|
|
1251
|
-
* dequant_val = (raw_nibble - zero) * scale
|
|
1252
|
-
*
|
|
1253
|
-
* Packing: 8 × 4-bit values per u32, little-nibble-first order.
|
|
1254
|
-
* Grouping: contiguous elements in row-major (K × N) layout.
|
|
1255
|
-
*/
|
|
1256
|
-
const DEFAULT_GROUP_SIZE = 128;
|
|
1257
|
-
/**
|
|
1258
|
-
* Quantize a flat F32 weight array to INT4.
|
|
1259
|
-
*
|
|
1260
|
-
* @param data - Source F32 weight data (row-major, K × N elements)
|
|
1261
|
-
* @param groupSize - Number of elements per quantization group (default 128)
|
|
1262
|
-
* @returns Packed INT4 data with per-group scales and zeros
|
|
1263
|
-
*/
|
|
1264
|
-
function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
|
|
1265
|
-
const totalElements = data.length;
|
|
1266
|
-
const numGroups = Math.ceil(totalElements / groupSize);
|
|
1267
|
-
const packedSize = Math.ceil(totalElements / 8);
|
|
1268
|
-
const packed = new Uint32Array(packedSize);
|
|
1269
|
-
const scales = new Float32Array(numGroups);
|
|
1270
|
-
const zeros = new Float32Array(numGroups);
|
|
1271
|
-
for (let g = 0; g < numGroups; g++) {
|
|
1272
|
-
const start = g * groupSize;
|
|
1273
|
-
const end = Math.min(start + groupSize, totalElements);
|
|
1274
|
-
let min = data[start];
|
|
1275
|
-
let max = data[start];
|
|
1276
|
-
for (let i = start + 1; i < end; i++) {
|
|
1277
|
-
const v = data[i];
|
|
1278
|
-
if (v < min) min = v;
|
|
1279
|
-
if (v > max) max = v;
|
|
1280
|
-
}
|
|
1281
|
-
const range = max - min;
|
|
1282
|
-
const scale = range > 0 ? range / 15 : 1;
|
|
1283
|
-
const zero = range > 0 ? -min / scale : 0;
|
|
1284
|
-
scales[g] = scale;
|
|
1285
|
-
zeros[g] = zero;
|
|
1286
|
-
const invRange = range > 0 ? 15 / range : 0;
|
|
1287
|
-
for (let i = start; i < end; i++) {
|
|
1288
|
-
const q = Math.round((data[i] - min) * invRange);
|
|
1289
|
-
const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
|
|
1290
|
-
const packedIdx = i >>> 3;
|
|
1291
|
-
const nibblePos = i & 7;
|
|
1292
|
-
packed[packedIdx] |= clamped << nibblePos * 4;
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
return {
|
|
1296
|
-
packed,
|
|
1297
|
-
scales,
|
|
1298
|
-
zeros
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
1362
|
//#endregion
|
|
1303
1363
|
//#region src/gpu/architectures/gemma3_encoder.ts
|
|
1304
1364
|
function generateGemma3EncoderGraph(rawConfig, dtype, groupSizeOverride, _kvDtype, _embedding) {
|
|
@@ -6059,5 +6119,5 @@ function isArchitectureSupported(name) {
|
|
|
6059
6119
|
}
|
|
6060
6120
|
|
|
6061
6121
|
//#endregion
|
|
6062
|
-
export {
|
|
6063
|
-
//# sourceMappingURL=architectures-
|
|
6122
|
+
export { quantizeInt4 as C, createDefaultHFKeyMapper as D, GEMMA4_VIS_KEYS as E, DEFAULT_GROUP_SIZE as S, DTYPE_BYTES as T, kaniCosTensor as _, generateMoonshineEncoderGraph as a, nanoCodecWeightMap as b, KANI_END_OF_HUMAN as c, buildKaniLayerCosSin as d, computeKaniPositions as f, kaniAttentionLayerIndices as g, generateNanoCodecDecoderGraph as h, generateMoonshineDecoderGraph as i, KANI_START_OF_HUMAN as l, generateKaniTtsGraph as m, isArchitectureSupported as n, moonshineEncoderFrames as o, foldNanoCodecWeightNorm as p, MOONSHINE_REMAINING_WORK as r, parseMoonshineConfig as s, generateGraph as t, audioTokensToCodes as u, kaniLayerAlpha as v, CANONICAL_KEYS as w, parseKaniConfig as x, kaniSinTensor as y };
|
|
6123
|
+
//# sourceMappingURL=architectures-Ol7yUmKf.mjs.map
|