@tryhamster/gerbil 1.0.8 → 1.0.9
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/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-9sGHvqkj.mjs +4 -0
- package/dist/{gerbil-D9fzoBGM.mjs → gerbil-CWg6xm9N.mjs} +2 -2
- package/dist/{gerbil-D9fzoBGM.mjs.map → gerbil-CWg6xm9N.mjs.map} +1 -1
- package/dist/gpu/index.mjs +2 -2
- package/dist/{gpu-oLuWWd5G.mjs → gpu-D4lQhTy0.mjs} +2 -2
- package/dist/{gpu-oLuWWd5G.mjs.map → gpu-D4lQhTy0.mjs.map} +1 -1
- package/dist/index-CGYIAChm.d.mts.map +1 -1
- package/dist/index-Dgmb2kE3.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-Cobm_wmI.mjs → mcp-CYp2qO9G.mjs} +3 -3
- package/dist/{mcp-Cobm_wmI.mjs.map → mcp-CYp2qO9G.mjs.map} +1 -1
- package/dist/{moonshine-stt-C2PR8fM4.mjs → moonshine-stt--Wauoxwa.mjs} +24 -3
- package/dist/{moonshine-stt-C2PR8fM4.mjs.map → moonshine-stt--Wauoxwa.mjs.map} +1 -1
- package/dist/moonshine-stt-DHrcX9mv.mjs +4 -0
- package/dist/{one-liner-rqFVBbNs.mjs → one-liner-CdFRpqJz.mjs} +2 -2
- package/dist/{one-liner-rqFVBbNs.mjs.map → one-liner-CdFRpqJz.mjs.map} +1 -1
- package/dist/{repl-BJVyb3Qf.mjs → repl-DmzIMwop.mjs} +3 -3
- package/dist/skills/index.d.mts +2 -2
- package/dist/skills/index.mjs +3 -3
- package/dist/{skills-c8rCxj2n.mjs → skills-C7fENinY.mjs} +2 -2
- package/dist/{skills-c8rCxj2n.mjs.map → skills-C7fENinY.mjs.map} +1 -1
- package/docs/kernel-research-queue.md +83 -57
- package/docs/research/autoresearch-portable.md +29 -0
- package/package.json +2 -2
- package/dist/gerbil-BOsuusm3.mjs +0 -4
- package/dist/moonshine-stt-D0EXyr4g.mjs +0 -4
|
@@ -1,59 +1,85 @@
|
|
|
1
|
-
# Kernel optimization research queue —
|
|
2
|
-
|
|
3
|
-
Source
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
1
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
# Kernel optimization research queue — data-backed from the Gemma-4 challenge corpus
|
|
2
|
+
|
|
3
|
+
Source of truth: `scripts/research/out/gemma-results.jsonl` (532 experiments harvested
|
|
4
|
+
from the HF `gemma-challenge` bucket; `harvest-gemma-bucket.mjs` re-runs it). 241
|
|
5
|
+
legit rows (ppl 1.5–2.31). Analyzed by a multi-agent workflow that separated
|
|
6
|
+
WebGPU-portable wins from vLLM/CUDA server noise.
|
|
7
|
+
|
|
8
|
+
**Headline reframe:** the 412-TPS leaderboard top is largely **server-only** —
|
|
9
|
+
its biggest delta is `feopt2` (orjson + HTTP/JSON serialization; no browser
|
|
10
|
+
analog) on a trained vLLM speculative drafter. Stripping serving noise, the
|
|
11
|
+
portable wins attack Gerbil's two confirmed bottlenecks exactly: **dispatch-bound
|
|
12
|
+
decode** and the **270 MB vocab OOM**. IGNORE the 412/506/511 headlines as porting
|
|
13
|
+
targets (server serialization + FA3 + ppl spent past Gerbil's 2.31 guardrail).
|
|
14
|
+
|
|
15
|
+
## THE CONVERGENCE (do these first — they fix the iOS OOM *and* boost TPS)
|
|
16
|
+
|
|
17
|
+
**#1 · vocabprune (lm_head row-prune + logits scatter)** — directly-portable, gemma4.
|
|
18
|
+
Prune the LM head 262144 → 32k–128k emittable rows, run the INT4 GEMV/argmax over
|
|
19
|
+
the small head, scatter logits back to full vocab (−inf complement) before sampling.
|
|
20
|
+
*Corpus proof:* `braiam-fable onegraph-pck04-vocabprune` 262144→32768 = **+21.3 TPS
|
|
21
|
+
(311→332) AND ppl improved 2.0266→2.0091**; `dixie pck04b 16k` verify bytes
|
|
22
|
+
**~335MB→~21MB/step**. (16k fails MMLU-Pro 0.596; 128k clears 0.688 → keep ~128k
|
|
23
|
+
for a general assistant; still halves the head.) Pure load-time data transform,
|
|
24
|
+
**no new WGSL**: slice lm_head q/scales/zeros to keep-rows, set `config.vocab_size`
|
|
25
|
+
(argmax `executor.ts:1016` + matmul_int4 N already read it), add scatter-to-full.
|
|
26
|
+
*Test:* vocab ∈ {full, 131072, 32768} × {decode TPS, resident MB, ppl, MMLU-Pro/GSM8K} on M-series + iPad.
|
|
27
|
+
|
|
28
|
+
**#2 · Extend the prune to embed_tokens + the Gemma-4 PLE table** — directly-portable, gemma4.
|
|
29
|
+
NOT in the corpus (the competition ran on servers with no load-time memory limit;
|
|
30
|
+
they only pruned the head for *speed*). **Gerbil's OOM is at model LOAD**, and the
|
|
31
|
+
Gemma-4 `embed_tokens_per_layer` (PLE) table is **~1.17 GB at 4-bit — the single
|
|
32
|
+
largest resident tensor** (`model-loader.ts:87, ~1916`). Apply the same keep-set
|
|
33
|
+
row-slice to `embed_tokens` + the PLE table so the *resident* weight actually
|
|
34
|
+
shrinks. **Highest-leverage iOS-OOM action.** *Test:* peak resident MB at load with
|
|
35
|
+
embed/PLE pruned to {full,131072,32768} on iPad; confirm no OOM at the risky tier.
|
|
36
|
+
|
|
37
|
+
**#4 · Untie + INT4 the lm_head** — directly-portable, gemma4. Prerequisite for #1
|
|
38
|
+
(a tied head can't be row-pruned independently). `model-loader.ts:1844-1847`
|
|
39
|
+
currently does the tied fallback (lm_head→embed_tokens). Untie + `quantizeInt4`
|
|
40
|
+
(`quantize.ts:32`, DEFAULT_GROUP_SIZE=128 already matches the corpus g128 sweet spot).
|
|
41
|
+
*Corpus proof:* `foffee int4-lmhead` **118.3 TPS / ppl 2.0067 — 2.68× over bf16**
|
|
42
|
+
(kills the ~1.34GB bf16 head read/step); `senpai int4_g128_lmhead` 126.4 / 2.0057,
|
|
43
|
+
MMLU-Pro 0.668 / GSM8K 0.850.
|
|
44
|
+
|
|
45
|
+
## Whole-engine, portable (after the OOM convergence)
|
|
46
|
+
|
|
47
|
+
**#3 · onegraph-analog (fewer submits, no per-token readback on WebKit)** —
|
|
48
|
+
maps-to-webgpu-analog. Gerbil already built the Dawn version: `forwardArgmax`
|
|
49
|
+
(`executor.ts:971-1024`, argmax stays on GPU), `submitGreedyDecodeStep`
|
|
50
|
+
(`executor.ts:1109`, PIPELINE_DEPTH=2, submits without awaiting). **Port that
|
|
51
|
+
no-readback shape to the Safari/iOS path**; raise `webkitGroupSize` toward
|
|
52
|
+
llama.cpp's ~64/CB; no host-JS branch in the hot loop (the `lffn` trap: a host
|
|
53
|
+
`os.path.exists` in the graph cost 420→368 TPS). *Test:* sweep `?group=N` ∈ {1,8,32,64} for correctness + TPS on iPad.
|
|
54
|
+
|
|
55
|
+
**#5 · More decode-op fusion** — directly-portable. Gerbil already fuses
|
|
56
|
+
(`fuseDualMatVecDecode`/`fuseDualKVCacheAppend`/`fuseGatedOProj`/`fuseDualRMSNorm`,
|
|
57
|
+
`executor.ts:507-517`). Next: fuse final RMSNorm→lm_head, and argmax into the
|
|
58
|
+
lm_head tail. On WebKit each removed dispatch = a removed submit+drain. *Test:*
|
|
59
|
+
diff `[executor] decode: N dispatches/token` + parity per fusion.
|
|
60
|
+
|
|
61
|
+
**#6 · W4A16 QAT checkpoint** — directly-portable, gemma4. QAT int4 is a quality
|
|
62
|
+
GAIN, not a cost: stock bf16 44.0 / 2.302 → W4A16 QAT **~95.6 / 2.0056** (ppl-guard,
|
|
63
|
+
steve, speed-demon-ne, infinityoptimizer all reproduce). **PREFERRED:** requant
|
|
64
|
+
`google/gemma-4-E4B-it-qat-q4_0-unquantized` through the **existing** `quantizeInt4`
|
|
65
|
+
(g128) — zero new loader code, reuses the safetensors path. **ALT:** add a
|
|
66
|
+
compressed-tensors/pack-quantized adapter like `repackGPTQ` (`gptq-adapter.ts:41`)
|
|
67
|
+
to consume the official `…-qat-w4a16-ct` directly (`model-loader.ts:1074` only knows
|
|
68
|
+
`quant_method=='gptq'` today). *Test:* current post-hoc int4 vs QAT-requant int4 at
|
|
69
|
+
identical g128: ppl + MMLU-Pro/GSM8K (expect QAT lower ppl), TPS unchanged.
|
|
70
|
+
|
|
71
|
+
**#7 · splitkv (KV layout f16/packed/head-split)** — maps-to-webgpu-analog.
|
|
72
|
+
`deja-vu splitkv-honest-16k` 377.8 / 2.002 (best ppl-2.00 run) but n=1, terse body.
|
|
73
|
+
`executor.ts allocateKVCacheBuffers ~1652` + `DualKVCacheAppend ~1936` + `softmax.wgsl`.
|
|
74
|
+
|
|
75
|
+
**#8 · Speculative decoding** — DEFER until #1–#3 land. Biggest raw multiplier
|
|
76
|
+
(~2–3.5×) but needs a **second model in memory** (fights the OOM #1/#2 just relieved)
|
|
77
|
+
and a batched verify that depends on the #3 onegraph-analog (per-token submit+drain
|
|
78
|
+
eats the acceptance win). No draft/verify infra exists in `src/gpu` today. Add
|
|
79
|
+
relaxed/typical acceptance (eps=0.5, +~6%) only as an OPT-IN sampler flag (it changes
|
|
80
|
+
emitted tokens; off by default for an honest on-device assistant).
|
|
56
81
|
|
|
57
82
|
## Sequence
|
|
58
|
-
|
|
59
|
-
|
|
83
|
+
1 → 4 → 2 (the OOM convergence — load-time data transforms, no new WGSL, fixes iOS
|
|
84
|
+
OOM + boosts TPS) → 6 (QAT requant, parallel) → 3 (WebKit onegraph-analog) → 5
|
|
85
|
+
(fusion) → 7 (KV) → 8 (spec decode, last). Each gated on-device (ppl + MMLU-Pro/GSM8K).
|
|
@@ -902,3 +902,32 @@ From Karpathy:
|
|
|
902
902
|
- [trevin-creator/autoresearch-mlx](https://github.com/trevin-creator/autoresearch-mlx) — Apple Silicon port
|
|
903
903
|
- [DeepWiki: autoresearch](https://deepwiki.com/karpathy/autoresearch) — detailed system documentation
|
|
904
904
|
- [DeepWiki: autoresearch-mlx](https://deepwiki.com/trevin-creator/autoresearch-mlx) — MLX port documentation
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
## Gerbil application: lever taxonomy + dual-track gating (from the Gemma-4 corpus, 2026-06-21)
|
|
909
|
+
|
|
910
|
+
We mined a 532-experiment Gemma-4 optimization competition (`scripts/research/out/gemma-results.jsonl`, harvested by `harvest-gemma-bucket.mjs`; analysis in `docs/kernel-research-queue.md`). It validated the loop above AND taught us how to point Gerbil's own autoresearch. Five methodology learnings:
|
|
911
|
+
|
|
912
|
+
### 1. The metric is TPS *under a quality guardrail* — never raw TPS
|
|
913
|
+
The competition maximized decode TPS gated by perplexity ≤ ~2.31 (and downstream MMLU-Pro / GSM8K / GPQA at the extremes). Raw TPS gets gamed instantly (we found rows at `tps=1.79e308`, `1000000`, `ppl=0`). **Gerbil's autoresearch metric must be `TPS subject to ppl ≤ guard AND eval-suite ≥ floor`.** A speedup that moves ppl past the guard or fails MMLU-Pro is a REVERT, not a keep. (E.g. vocabprune to 16k rows hit 330 TPS but failed MMLU-Pro 0.596; 128k cleared 0.688 — only the 128k variant is a "keep".)
|
|
914
|
+
|
|
915
|
+
### 2. Device-class gating — a win on one class can CRASH another
|
|
916
|
+
The same kernel change has three regimes: **server/Dawn** (no memory limit, batching), **iPad WebKit** (tolerates `webkitGroupSize` up to ~128 → ~3.4× decode), **iPhone WebKit** (group>1 HARD-CRASHES the GPU process — the "third device class"). An experiment is only "kept" once validated on the **target device class**. Autoresearch must run with a device-class tag and never promote a change that regresses/crashes a class it's meant to support. (This is why the decided "Production submit strategy" must be a *crash-surviving auto-probe*, not a global default.)
|
|
917
|
+
|
|
918
|
+
### 3. Two tracks — same engine, different lever sets
|
|
919
|
+
Gerbil runs both **client WebGPU (browser, iOS/desktop)** and **server (Node + Dawn)**. The corpus's biggest headline wins were **server-only** (vLLM serving infra: HTTP/JSON serialization `feopt2`, continuous batching, FA3 CUDA tiling) — irrelevant to a single-user browser but **directly relevant to Gerbil-on-server**. So run autoresearch as TWO tracks with different `program.md` constraints: WebGPU-mobile (dispatch-bound + memory-tight) and server (batching, larger models, spec-decode with a small draft). Don't discard server wins — route them to the server track.
|
|
920
|
+
|
|
921
|
+
### 4. Filter portable-from-infra
|
|
922
|
+
Most corpus "improvements" were serving/infrastructure, not engine. Before queueing an experiment, classify it: directly-portable (a WGSL kernel / decode-loop change), maps-to-WebGPU-analog (e.g. CUDA-graph → fewer `queue.submit()`s; the `onegraph` family → Gerbil's `forwardArgmax`/PIPELINE_DEPTH path), or infra-only (skip for the mobile track). Only the first two belong in the WebGPU autoresearch loop.
|
|
923
|
+
|
|
924
|
+
### 5. Per-model AND whole-engine levers
|
|
925
|
+
Some levers are family-specific (Gemma-4's PLE table; a model's QAT checkpoint; vocab size); most are whole-engine (dispatch/launch reduction, op fusion, KV layout, int4 packing group-size). Run autoresearch **per-model** to catch arch-specific wins (e.g. Gemma PLE pruning) AND **overall** on a shared kernel set. Note Gerbil already captures several corpus levers (int4-*tied* head, CPU-streamed PLE, extensive decode fusion, the `forwardArgmax` Dawn path) — so the baseline is higher than the competition's; target the *unshipped* levers (the `webkitGroupSize` auto-probe, vocab prune, QAT requant) not the already-done ones.
|
|
926
|
+
|
|
927
|
+
### The lever taxonomy to seed Gerbil's `program.md`
|
|
928
|
+
Ranked, with bottleneck attacked (full detail + corpus evidence + file:line in `docs/kernel-research-queue.md`):
|
|
929
|
+
- **Launch/dispatch reduction** (whole-engine; mobile decode is dispatch-bound): the `webkitGroupSize` crash-surviving auto-probe (decided in paper §19, never shipped — default still 1), more op fusion, no host-JS in the hot loop.
|
|
930
|
+
- **Vocab/memory** (per-model, large-vocab; fixes iOS load OOM): prune lm_head/embed/PLE to a freq keepset + logits scatter; relevant to Qwen3.5 (248K vocab) too, not just Gemma.
|
|
931
|
+
- **Quantization** (per-checkpoint): QAT int4 (quality *gain*), int4 packing group-size sweet spot (g128), mixed 2/4-bit.
|
|
932
|
+
- **KV** (whole-engine): f16/packed/head-split layout.
|
|
933
|
+
- **Speculative decoding** (server track first): small draft + batched verify; ~2–3.5× but needs a 2nd model in memory (fights mobile OOM) → server/large-model regime.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tryhamster/gerbil",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Local LLM inference for Node.js. GPU-accelerated. Zero config. Works standalone or with Vercel AI SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -216,6 +216,6 @@
|
|
|
216
216
|
"test:watch": "vitest",
|
|
217
217
|
"changeset": "changeset",
|
|
218
218
|
"version": "changeset version",
|
|
219
|
-
"release": "
|
|
219
|
+
"release": "changeset publish"
|
|
220
220
|
}
|
|
221
221
|
}
|
package/dist/gerbil-BOsuusm3.mjs
DELETED