mlx-bun 0.0.10 → 0.0.12
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 +107 -32
- package/THIRD_PARTY_LICENSES.md +10 -0
- package/docs/archive/mlx-bun-lab-report.html +275 -0
- package/docs/archive/wwdc-mlx-bun.html +848 -0
- package/docs/design/audio-input-plan.md +356 -0
- package/docs/design/batching-perf-path.md +58 -35
- package/docs/design/batching-v2-plan.md +23 -9
- package/docs/design/bucketing-stage.md +2 -1
- package/docs/design/colibri-glm52-port.md +1479 -0
- package/docs/design/compat-cli-surface-design.md +4 -3
- package/docs/design/decode-speed-program.md +172 -0
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +371 -0
- package/docs/design/dspark-speculative-decoding.md +167 -5
- package/docs/design/faithful-l1-consolidation.md +310 -0
- package/docs/design/generic-model-support.md +8 -5
- package/docs/design/grammar-spec-batching-integration.md +301 -0
- package/docs/design/minicpm5-decode-megakernel.md +16 -11
- package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
- package/docs/design/omlx-adoption-map.md +14 -6
- package/docs/design/orpo-training.md +34 -30
- package/docs/design/paged-kv-cache.md +214 -0
- package/docs/design/parallel-slots.md +82 -49
- package/docs/design/parity-tier-dag.md +43 -33
- package/docs/design/pre-colibri-stabilization.md +329 -0
- package/docs/design/repo-cleanup-plan.md +189 -0
- package/docs/design/runtime-isolation.md +19 -3
- package/docs/design/segmented-backward-training.md +3 -2
- package/docs/design/ssd-kv-cold-tier.md +130 -0
- package/docs/design/structured-output.md +484 -0
- package/docs/design/the-dreaming-master-plan.md +2 -3
- package/docs/design/turboquant-kv.md +235 -0
- package/docs/design/unified-engine-frontier-plan.md +774 -0
- package/docs/design/web-chat-beat-matrix.md +315 -0
- package/docs/design/web-chat-redesign.md +1112 -0
- package/docs/investigations/colibri-oracle-pin.md +1284 -0
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/indexshare-performance-spike.md +357 -0
- package/docs/investigations/lab-build-journal.md +2 -2
- package/docs/investigations/openwiki-evaluation.md +249 -0
- package/docs/planning/IDEAS.md +14 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -3
- package/docs/planning/chat-ui-vision-memory-first.md +199 -0
- package/docs/planning/chat-ui-vision.md +50 -0
- package/docs/planning/memory-docs-and-dag-plan.md +15 -6
- package/docs/planning/release-notes-v0.0.11.md +239 -0
- package/docs/planning/release-notes-v0.0.12.md +80 -0
- package/docs/reference/cli.md +63 -18
- package/docs/reference/distribution.md +37 -6
- package/docs/reference/embedding.md +40 -16
- package/docs/reference/features-matrix.md +99 -0
- package/docs/reference/library-api.md +69 -20
- package/docs/reference/memory.md +26 -6
- package/docs/reference/models.md +60 -3
- package/docs/reference/orpo-quickstart.md +3 -4
- package/docs/reference/server-api.md +717 -24
- package/docs/reference/server-config.md +265 -129
- package/docs/reference/training.md +24 -16
- package/package.json +5 -3
- package/src/anthropic.ts +67 -44
- package/src/audio/conformer.ts +647 -0
- package/src/audio/decode.ts +133 -0
- package/src/audio/features.ts +202 -0
- package/src/audio/transcode.ts +67 -0
- package/src/chat-template.ts +155 -10
- package/src/cli.ts +483 -113
- package/src/config.ts +116 -24
- package/src/diffusion/diffusion-generate.ts +14 -8
- package/src/download.ts +143 -12
- package/src/eval/README.md +7 -6
- package/src/eval/ifeval.ts +63 -120
- package/src/eval/kl.ts +59 -3
- package/src/eval/quality-db.ts +2 -2
- package/src/eval/runner.ts +17 -8
- package/src/eval/tasks/ifeval.ts +167 -31
- package/src/expert-io.ts +391 -0
- package/src/expert-offload.ts +15 -2
- package/src/expert-residency.ts +1134 -0
- package/src/expert-usage.ts +415 -0
- package/src/flags.ts +13 -0
- package/src/generate.ts +438 -35
- package/src/grammar.ts +585 -0
- package/src/hf-push.ts +1 -1
- package/src/hub-rest.ts +242 -0
- package/src/index.ts +14 -2
- package/src/jobs/runner.ts +37 -18
- package/src/kv-store.ts +586 -93
- package/src/lora.ts +85 -14
- package/src/md-modules.d.ts +42 -0
- package/src/media-fetch.ts +426 -0
- package/src/memory/rest.ts +245 -0
- package/src/memory/vault.ts +74 -0
- package/src/mlx/array.ts +149 -19
- package/src/mlx/autograd.ts +53 -16
- package/src/mlx/checkpoint.ts +46 -13
- package/src/mlx/custom-vjp.ts +83 -35
- package/src/mlx/ffi.ts +27 -3
- package/src/mlx/metal-kernel.ts +7 -4
- package/src/mlx/ops.ts +153 -23
- package/src/mlx/turboquant-ops.ts +831 -0
- package/src/mlx/turboquant-tables.ts +237 -0
- package/src/model/batched-mask.ts +62 -1
- package/src/model/batched-quant.ts +206 -0
- package/src/model/batched-rotating-quant.ts +346 -0
- package/src/model/batched-rotating.ts +46 -1
- package/src/model/compiled-decode.ts +4 -15
- package/src/model/factory.ts +103 -6
- package/src/model/gemma4-base.ts +395 -39
- package/src/model/gemma4.ts +122 -33
- package/src/model/generated/gemma4-12b.ts +9 -13
- package/src/model/generated/gemma4-26b.ts +10 -5
- package/src/model/generated/gemma4-e4b.ts +14 -9
- package/src/model/glm52-atlas.ts +511 -0
- package/src/model/glm52-cache.ts +706 -0
- package/src/model/glm52-config.ts +262 -0
- package/src/model/glm52-container.ts +305 -0
- package/src/model/glm52-coupling.ts +388 -0
- package/src/model/glm52-dsa.ts +602 -0
- package/src/model/glm52-expert-layout.ts +253 -0
- package/src/model/glm52-layout.ts +152 -0
- package/src/model/glm52-memory.ts +473 -0
- package/src/model/glm52-mla.ts +786 -0
- package/src/model/glm52-moe.ts +223 -0
- package/src/model/glm52-pilot.ts +537 -0
- package/src/model/glm52-reference.ts +445 -0
- package/src/model/glm52-residency.ts +557 -0
- package/src/model/glm52-resident-weights.ts +135 -0
- package/src/model/glm52-streamed-experts.ts +453 -0
- package/src/model/glm52-streamed-metal.ts +610 -0
- package/src/model/glm52-weights.ts +503 -0
- package/src/model/glm52.ts +1153 -0
- package/src/model/minicpm5.ts +58 -102
- package/src/model/paged-kv.ts +253 -0
- package/src/model/qwen3-delta.ts +76 -15
- package/src/model/qwen3-moe.ts +404 -0
- package/src/model/qwen3.ts +9 -8
- package/src/model/qwen3_5.ts +88 -23
- package/src/model/support.ts +19 -1
- package/src/model/universal/dense.ts +40 -5
- package/src/model/universal/rope.ts +36 -21
- package/src/native/expert_io.c +523 -0
- package/src/native-pack.ts +6 -4
- package/src/pi-web.ts +1299 -82
- package/src/preflight.ts +27 -8
- package/src/prompt-cache.ts +293 -33
- package/src/quantize/quantizer.ts +16 -1
- package/src/registry.ts +57 -2
- package/src/responses.ts +62 -49
- package/src/serve/batch-scheduler.ts +1050 -78
- package/src/serve/generation-gateway.ts +252 -24
- package/src/serve/isolate.ts +417 -0
- package/src/serve/lane-registry.ts +44 -0
- package/src/serve/session-search.ts +326 -0
- package/src/server.ts +1701 -175
- package/src/spec/assistant-source.ts +150 -0
- package/src/spec/deepspec-source.ts +143 -0
- package/src/spec/dflash-source.ts +124 -0
- package/src/spec/dspark/ab-stats.ts +136 -0
- package/src/spec/dspark/calibration.ts +112 -0
- package/src/spec/dspark/deepspec-module.ts +801 -0
- package/src/spec/dspark/generate-dflash.ts +72 -20
- package/src/spec/dspark/loader.ts +23 -0
- package/src/spec/dspark/module-dflash.ts +278 -36
- package/src/spec/dspark/quantize-drafter.ts +91 -0
- package/src/spec/generate.ts +59 -25
- package/src/spec/glm52-mtp-source.ts +392 -0
- package/src/spec/ngram-source.ts +132 -0
- package/src/spec/serve-loop.ts +617 -0
- package/src/spec/source.ts +118 -0
- package/src/spec/two-model.ts +171 -0
- package/src/ssd-cache.ts +111 -35
- package/src/tokenizer.ts +288 -2
- package/src/tool-approvals.ts +131 -0
- package/src/tool-call.ts +438 -22
- package/src/train/flash-cce.ts +2 -2
- package/src/train/job.ts +0 -12
- package/src/train/lora-params.ts +17 -6
- package/src/train/trainer.ts +60 -30
- package/src/vision/prompt.ts +217 -48
- package/src/web/app.html +1197 -1791
- package/src/web/app.js +5694 -0
- package/src/web/icon.svg +13 -0
- package/src/web/manifest.webmanifest +24 -0
- package/src/web/src/adapters-panel.ts +288 -0
- package/src/web/src/api.ts +57 -0
- package/src/web/src/assistant.ts +485 -0
- package/src/web/src/chat.ts +1050 -0
- package/src/web/src/composer.ts +959 -0
- package/src/web/src/dataset.ts +132 -0
- package/src/web/src/finetune.ts +267 -0
- package/src/web/src/hub.ts +428 -0
- package/src/web/src/main.ts +98 -0
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +572 -0
- package/src/web/src/model-picker.ts +159 -0
- package/src/web/src/palette.ts +346 -0
- package/src/web/src/protocol.ts +62 -0
- package/src/web/src/quantize.ts +167 -0
- package/src/web/src/rag.ts +274 -0
- package/src/web/src/sessions.ts +469 -0
- package/src/web/src/shell.ts +804 -0
- package/src/web/src/status.ts +300 -0
- package/src/web/src/ui-catalog.ts +92 -0
- package/src/web/sw.js +71 -0
- package/src/web/vendor/README.md +61 -0
- package/src/web/vendor/hljs-LICENSE +29 -0
- package/src/web/vendor/hljs-theme.css +59 -0
- package/src/web/vendor/hljs.js +26 -0
- package/src/web-tools.ts +54 -2
- package/src/weights.ts +82 -19
- package/src/model/fused-decode-kernel.ts +0 -312
- package/src/model/fused-geglu-kernel.ts +0 -198
- package/src/model/fused-mlp-kernel.ts +0 -169
- package/src/model/fused-swiglu-kernel.ts +0 -240
- package/src/model/steel-linear-kernel.ts +0 -96
- package/src/status-page.html +0 -497
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
// Measurement-only GLM-5.2 PILOT predictor.
|
|
2
|
+
//
|
|
3
|
+
// Faithful to direct Colibri's first-stage policy: after layer L attention,
|
|
4
|
+
// normalize that raw residual with layer L+1's post-attention norm and apply
|
|
5
|
+
// layer L+1's router. This module records prediction quality and available
|
|
6
|
+
// lead time only. It never touches residency or submits expert I/O.
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
summarizeExpertLatencies,
|
|
10
|
+
type ExpertHintTelemetry,
|
|
11
|
+
type ExpertLatencySummary,
|
|
12
|
+
type ExpertRouteLike,
|
|
13
|
+
} from "../expert-residency";
|
|
14
|
+
import { MlxArray } from "../mlx/array";
|
|
15
|
+
import * as ops from "../mlx/ops";
|
|
16
|
+
import type { Glm52Config } from "./glm52-config";
|
|
17
|
+
import { rmsNormF32Mlx } from "./glm52-mla";
|
|
18
|
+
import { routeGlm52MoeF32 } from "./glm52-moe";
|
|
19
|
+
|
|
20
|
+
export const GLM52_PILOT_MAX_ROWS = 8;
|
|
21
|
+
|
|
22
|
+
export interface Glm52PilotWeightSource {
|
|
23
|
+
tensor(name: string): MlxArray;
|
|
24
|
+
linear(
|
|
25
|
+
input: MlxArray,
|
|
26
|
+
name: string,
|
|
27
|
+
outputRows: number,
|
|
28
|
+
inputColumns: number,
|
|
29
|
+
): MlxArray;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Glm52PilotLayerTelemetry {
|
|
33
|
+
readonly layer: number;
|
|
34
|
+
readonly calls: number;
|
|
35
|
+
readonly rows: number;
|
|
36
|
+
readonly predictedSelections: number;
|
|
37
|
+
readonly actualSelections: number;
|
|
38
|
+
readonly matchedSelections: number;
|
|
39
|
+
readonly exactRows: number;
|
|
40
|
+
readonly precision: number;
|
|
41
|
+
readonly recall: number;
|
|
42
|
+
readonly exactRowRate: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface Glm52PilotHintSink {
|
|
46
|
+
hintExperts(layer: number, expertIds: readonly number[]): void;
|
|
47
|
+
drainHintTelemetry(): ExpertHintTelemetry;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Glm52PilotTelemetry {
|
|
51
|
+
readonly mode: "measure-only" | "hint-only";
|
|
52
|
+
readonly maxRows: number;
|
|
53
|
+
readonly hintK: number;
|
|
54
|
+
readonly predictionCalls: number;
|
|
55
|
+
readonly observedCalls: number;
|
|
56
|
+
readonly rows: number;
|
|
57
|
+
readonly predictedSelections: number;
|
|
58
|
+
readonly actualSelections: number;
|
|
59
|
+
readonly matchedSelections: number;
|
|
60
|
+
readonly exactRows: number;
|
|
61
|
+
readonly precision: number;
|
|
62
|
+
readonly recall: number;
|
|
63
|
+
readonly exactRowRate: number;
|
|
64
|
+
/** Set-overlap hit rate for each predicted rank, useful for PILOT_K. */
|
|
65
|
+
readonly rankHitRate: readonly number[];
|
|
66
|
+
readonly skippedWideCalls: number;
|
|
67
|
+
readonly skippedWideRows: number;
|
|
68
|
+
readonly abandonedPredictions: number;
|
|
69
|
+
readonly predictionLatency: ExpertLatencySummary;
|
|
70
|
+
/** Time from prediction completion until the target router is observed. */
|
|
71
|
+
readonly leadTime: ExpertLatencySummary;
|
|
72
|
+
readonly layers: readonly Glm52PilotLayerTelemetry[];
|
|
73
|
+
readonly hints: ExpertHintTelemetry | null;
|
|
74
|
+
/** Colibri's shared-expert-corrected predictor, scored independently. */
|
|
75
|
+
readonly twoStep: Glm52PilotVariantTelemetry | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface Glm52PilotVariantTelemetry {
|
|
79
|
+
readonly predictionCalls: number;
|
|
80
|
+
readonly observedCalls: number;
|
|
81
|
+
readonly rows: number;
|
|
82
|
+
readonly predictedSelections: number;
|
|
83
|
+
readonly actualSelections: number;
|
|
84
|
+
readonly matchedSelections: number;
|
|
85
|
+
readonly exactRows: number;
|
|
86
|
+
readonly precision: number;
|
|
87
|
+
readonly recall: number;
|
|
88
|
+
readonly exactRowRate: number;
|
|
89
|
+
readonly rankHitRate: readonly number[];
|
|
90
|
+
readonly predictionLatency: ExpertLatencySummary;
|
|
91
|
+
readonly leadTime: ExpertLatencySummary;
|
|
92
|
+
readonly layers: readonly Glm52PilotLayerTelemetry[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface PendingPrediction {
|
|
96
|
+
readonly rows: readonly (readonly number[])[];
|
|
97
|
+
readonly completedAt: number;
|
|
98
|
+
readonly twoStep: {
|
|
99
|
+
readonly rows: readonly (readonly number[])[];
|
|
100
|
+
readonly completedAt: number;
|
|
101
|
+
} | null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface MutablePilotCounts {
|
|
105
|
+
calls: number;
|
|
106
|
+
rows: number;
|
|
107
|
+
predictedSelections: number;
|
|
108
|
+
actualSelections: number;
|
|
109
|
+
matchedSelections: number;
|
|
110
|
+
exactRows: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function emptyCounts(): MutablePilotCounts {
|
|
114
|
+
return {
|
|
115
|
+
calls: 0,
|
|
116
|
+
rows: 0,
|
|
117
|
+
predictedSelections: 0,
|
|
118
|
+
actualSelections: 0,
|
|
119
|
+
matchedSelections: 0,
|
|
120
|
+
exactRows: 0,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function ratio(numerator: number, denominator: number): number {
|
|
125
|
+
return denominator === 0 ? 0 : numerator / denominator;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function publicCounts(
|
|
129
|
+
layer: number,
|
|
130
|
+
counts: MutablePilotCounts,
|
|
131
|
+
): Glm52PilotLayerTelemetry {
|
|
132
|
+
return {
|
|
133
|
+
layer,
|
|
134
|
+
...counts,
|
|
135
|
+
precision: ratio(counts.matchedSelections, counts.predictedSelections),
|
|
136
|
+
recall: ratio(counts.matchedSelections, counts.actualSelections),
|
|
137
|
+
exactRowRate: ratio(counts.exactRows, counts.rows),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function pilotSwiglu(
|
|
142
|
+
source: Glm52PilotWeightSource,
|
|
143
|
+
input: MlxArray,
|
|
144
|
+
prefix: string,
|
|
145
|
+
intermediate: number,
|
|
146
|
+
hidden: number,
|
|
147
|
+
): MlxArray {
|
|
148
|
+
const gate = source.linear(
|
|
149
|
+
input,
|
|
150
|
+
`${prefix}.gate_proj.weight`,
|
|
151
|
+
intermediate,
|
|
152
|
+
hidden,
|
|
153
|
+
);
|
|
154
|
+
const up = source.linear(
|
|
155
|
+
input,
|
|
156
|
+
`${prefix}.up_proj.weight`,
|
|
157
|
+
intermediate,
|
|
158
|
+
hidden,
|
|
159
|
+
);
|
|
160
|
+
const activated = ops.silu(gate);
|
|
161
|
+
const product = ops.mul(activated, up);
|
|
162
|
+
gate.dispose();
|
|
163
|
+
up.dispose();
|
|
164
|
+
activated.dispose();
|
|
165
|
+
const output = source.linear(
|
|
166
|
+
product,
|
|
167
|
+
`${prefix}.down_proj.weight`,
|
|
168
|
+
hidden,
|
|
169
|
+
intermediate,
|
|
170
|
+
);
|
|
171
|
+
product.dispose();
|
|
172
|
+
return output;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export class Glm52PilotTracker {
|
|
176
|
+
readonly config: Glm52Config;
|
|
177
|
+
readonly weights: Glm52PilotWeightSource;
|
|
178
|
+
readonly maxRows: number;
|
|
179
|
+
readonly hintK: number;
|
|
180
|
+
readonly twoStepEnabled: boolean;
|
|
181
|
+
#now: () => number;
|
|
182
|
+
#hintSink: Glm52PilotHintSink | null;
|
|
183
|
+
#pending = new Map<number, PendingPrediction>();
|
|
184
|
+
#counts = emptyCounts();
|
|
185
|
+
#layers = new Map<number, MutablePilotCounts>();
|
|
186
|
+
#rankMatches: number[];
|
|
187
|
+
#predictionMs: number[] = [];
|
|
188
|
+
#leadMs: number[] = [];
|
|
189
|
+
#predictionCalls = 0;
|
|
190
|
+
#observedCalls = 0;
|
|
191
|
+
#skippedWideCalls = 0;
|
|
192
|
+
#skippedWideRows = 0;
|
|
193
|
+
#twoCounts = emptyCounts();
|
|
194
|
+
#twoLayers = new Map<number, MutablePilotCounts>();
|
|
195
|
+
#twoRankMatches: number[];
|
|
196
|
+
#twoPredictionMs: number[] = [];
|
|
197
|
+
#twoLeadMs: number[] = [];
|
|
198
|
+
#twoPredictionCalls = 0;
|
|
199
|
+
#twoObservedCalls = 0;
|
|
200
|
+
|
|
201
|
+
constructor(options: {
|
|
202
|
+
config: Glm52Config;
|
|
203
|
+
weights: Glm52PilotWeightSource;
|
|
204
|
+
maxRows?: number;
|
|
205
|
+
now?: () => number;
|
|
206
|
+
hintK?: number;
|
|
207
|
+
hintSink?: Glm52PilotHintSink;
|
|
208
|
+
twoStep?: boolean;
|
|
209
|
+
}) {
|
|
210
|
+
this.config = options.config;
|
|
211
|
+
this.weights = options.weights;
|
|
212
|
+
this.maxRows = options.maxRows ?? GLM52_PILOT_MAX_ROWS;
|
|
213
|
+
if (!Number.isSafeInteger(this.maxRows) || this.maxRows < 1)
|
|
214
|
+
throw new RangeError("GLM PILOT maxRows must be a positive safe integer");
|
|
215
|
+
this.hintK = options.hintK ?? 0;
|
|
216
|
+
if (!Number.isSafeInteger(this.hintK) || this.hintK < 0 ||
|
|
217
|
+
this.hintK > this.config.numExpertsPerToken) {
|
|
218
|
+
throw new RangeError(
|
|
219
|
+
`GLM PILOT hintK must be in 0..${this.config.numExpertsPerToken}`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if ((this.hintK > 0) !== (options.hintSink !== undefined))
|
|
223
|
+
throw new Error("GLM PILOT hintK and hintSink must be enabled together");
|
|
224
|
+
this.twoStepEnabled = options.twoStep === true;
|
|
225
|
+
if (this.twoStepEnabled && this.hintK > 0) {
|
|
226
|
+
throw new Error(
|
|
227
|
+
"GLM PILOT two-step measurement cannot submit baseline-only hints",
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
if (this.twoStepEnabled && this.config.numSharedExperts < 1)
|
|
231
|
+
throw new Error("GLM PILOT two-step measurement requires a shared expert");
|
|
232
|
+
this.#now = options.now ?? (() => performance.now());
|
|
233
|
+
this.#hintSink = options.hintSink ?? null;
|
|
234
|
+
this.#rankMatches = Array(this.config.numExpertsPerToken).fill(0);
|
|
235
|
+
this.#twoRankMatches = Array(this.config.numExpertsPerToken).fill(0);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#predictRows(
|
|
239
|
+
residual: MlxArray,
|
|
240
|
+
targetLayer: number,
|
|
241
|
+
rowCount: number,
|
|
242
|
+
): readonly (readonly number[])[] {
|
|
243
|
+
const prefix = `model.layers.${targetLayer}`;
|
|
244
|
+
const normalized = rmsNormF32Mlx(
|
|
245
|
+
residual,
|
|
246
|
+
this.weights.tensor(`${prefix}.post_attention_layernorm.weight`),
|
|
247
|
+
this.config.rmsNormEps,
|
|
248
|
+
);
|
|
249
|
+
const routerTranspose = ops.transposeAxes(
|
|
250
|
+
this.weights.tensor(`${prefix}.mlp.gate.weight`),
|
|
251
|
+
[1, 0],
|
|
252
|
+
);
|
|
253
|
+
let logits: MlxArray | null = null;
|
|
254
|
+
try {
|
|
255
|
+
logits = ops.matmul(normalized, routerTranspose);
|
|
256
|
+
const host = logits.toFloat32();
|
|
257
|
+
const correctionBias = this.weights
|
|
258
|
+
.tensor(`${prefix}.mlp.gate.e_score_correction_bias`)
|
|
259
|
+
.toFloat32();
|
|
260
|
+
const predicted: number[][] = [];
|
|
261
|
+
for (let row = 0; row < rowCount; row++) {
|
|
262
|
+
const begin = row * this.config.numRoutedExperts;
|
|
263
|
+
const route = routeGlm52MoeF32(
|
|
264
|
+
host.subarray(begin, begin + this.config.numRoutedExperts),
|
|
265
|
+
correctionBias,
|
|
266
|
+
{
|
|
267
|
+
topK: this.config.numExpertsPerToken,
|
|
268
|
+
normalize: this.config.normTopkProb,
|
|
269
|
+
routedScale: this.config.routedScalingFactor,
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
predicted.push(Array.from(route.indices));
|
|
273
|
+
}
|
|
274
|
+
return Object.freeze(predicted.map((row) => Object.freeze(row)));
|
|
275
|
+
} finally {
|
|
276
|
+
logits?.dispose();
|
|
277
|
+
routerTranspose.dispose();
|
|
278
|
+
normalized.dispose();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
#predictTwoStep(
|
|
283
|
+
sourceLayer: number,
|
|
284
|
+
residual: MlxArray,
|
|
285
|
+
rowCount: number,
|
|
286
|
+
): readonly (readonly number[])[] {
|
|
287
|
+
const sourcePrefix = `model.layers.${sourceLayer}`;
|
|
288
|
+
const normalized = rmsNormF32Mlx(
|
|
289
|
+
residual,
|
|
290
|
+
this.weights.tensor(
|
|
291
|
+
`${sourcePrefix}.post_attention_layernorm.weight`,
|
|
292
|
+
),
|
|
293
|
+
this.config.rmsNormEps,
|
|
294
|
+
);
|
|
295
|
+
const sharedIntermediate =
|
|
296
|
+
this.config.moeIntermediateSize * this.config.numSharedExperts;
|
|
297
|
+
const shared = pilotSwiglu(
|
|
298
|
+
this.weights,
|
|
299
|
+
normalized,
|
|
300
|
+
`${sourcePrefix}.mlp.shared_experts`,
|
|
301
|
+
sharedIntermediate,
|
|
302
|
+
this.config.hiddenSize,
|
|
303
|
+
);
|
|
304
|
+
const corrected = ops.add(residual, shared);
|
|
305
|
+
try {
|
|
306
|
+
return this.#predictRows(corrected, sourceLayer + 1, rowCount);
|
|
307
|
+
} finally {
|
|
308
|
+
corrected.dispose();
|
|
309
|
+
shared.dispose();
|
|
310
|
+
normalized.dispose();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Predict layer L+1 from layer L's raw post-attention residual. */
|
|
315
|
+
predictNext(sourceLayer: number, residual: MlxArray): void {
|
|
316
|
+
const targetLayer = sourceLayer + 1;
|
|
317
|
+
if (targetLayer < this.config.firstKDenseReplace ||
|
|
318
|
+
targetLayer >= this.config.numHiddenLayers) return;
|
|
319
|
+
const [batch, tokens, hidden] = residual.shape;
|
|
320
|
+
if (residual.shape.length !== 3 || hidden !== this.config.hiddenSize) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`GLM PILOT requires [B,T,${this.config.hiddenSize}] residual input`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
const rowCount = batch! * tokens!;
|
|
326
|
+
if (rowCount > this.maxRows) {
|
|
327
|
+
this.#skippedWideCalls++;
|
|
328
|
+
this.#skippedWideRows += rowCount;
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (this.#pending.has(targetLayer)) {
|
|
332
|
+
throw new Error(
|
|
333
|
+
`GLM PILOT already has a pending prediction for layer ${targetLayer}`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const started = this.#now();
|
|
338
|
+
const predicted = this.#predictRows(residual, targetLayer, rowCount);
|
|
339
|
+
{
|
|
340
|
+
if (this.#hintSink) {
|
|
341
|
+
const hinted: number[] = [];
|
|
342
|
+
const seen = new Set<number>();
|
|
343
|
+
for (const row of predicted) {
|
|
344
|
+
for (const expertId of row.slice(0, this.hintK)) {
|
|
345
|
+
if (seen.has(expertId)) continue;
|
|
346
|
+
seen.add(expertId);
|
|
347
|
+
hinted.push(expertId);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
this.#hintSink.hintExperts(targetLayer, hinted);
|
|
351
|
+
}
|
|
352
|
+
const completedAt = this.#now();
|
|
353
|
+
let twoStep: PendingPrediction["twoStep"] = null;
|
|
354
|
+
// The first sparse target is preceded by a dense layer and therefore
|
|
355
|
+
// has no shared_experts block to apply as Colibri's second step.
|
|
356
|
+
if (this.twoStepEnabled &&
|
|
357
|
+
sourceLayer >= this.config.firstKDenseReplace) {
|
|
358
|
+
const twoStarted = this.#now();
|
|
359
|
+
const rows = this.#predictTwoStep(sourceLayer, residual, rowCount);
|
|
360
|
+
const twoCompletedAt = this.#now();
|
|
361
|
+
twoStep = { rows, completedAt: twoCompletedAt };
|
|
362
|
+
this.#twoPredictionCalls++;
|
|
363
|
+
this.#twoPredictionMs.push(twoCompletedAt - twoStarted);
|
|
364
|
+
}
|
|
365
|
+
this.#pending.set(targetLayer, {
|
|
366
|
+
rows: predicted,
|
|
367
|
+
completedAt,
|
|
368
|
+
twoStep,
|
|
369
|
+
});
|
|
370
|
+
this.#predictionCalls++;
|
|
371
|
+
this.#predictionMs.push(completedAt - started);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
#scorePrediction(
|
|
376
|
+
layer: number,
|
|
377
|
+
predictedRows: readonly (readonly number[])[],
|
|
378
|
+
routes: readonly ExpertRouteLike[],
|
|
379
|
+
counts: MutablePilotCounts,
|
|
380
|
+
layers: Map<number, MutablePilotCounts>,
|
|
381
|
+
rankMatches: number[],
|
|
382
|
+
): void {
|
|
383
|
+
let layerCounts = layers.get(layer);
|
|
384
|
+
if (!layerCounts) {
|
|
385
|
+
layerCounts = emptyCounts();
|
|
386
|
+
layers.set(layer, layerCounts);
|
|
387
|
+
}
|
|
388
|
+
counts.calls++;
|
|
389
|
+
layerCounts.calls++;
|
|
390
|
+
for (let row = 0; row < routes.length; row++) {
|
|
391
|
+
const predicted = predictedRows[row]!;
|
|
392
|
+
const actual = Array.from(routes[row]!.indices, Number);
|
|
393
|
+
const actualSet = new Set(actual);
|
|
394
|
+
let matched = 0;
|
|
395
|
+
for (let rank = 0; rank < predicted.length; rank++) {
|
|
396
|
+
if (!actualSet.has(predicted[rank]!)) continue;
|
|
397
|
+
matched++;
|
|
398
|
+
if (rank < rankMatches.length) rankMatches[rank]!++;
|
|
399
|
+
}
|
|
400
|
+
const exact = predicted.length === actual.length &&
|
|
401
|
+
matched === actual.length;
|
|
402
|
+
for (const target of [counts, layerCounts]) {
|
|
403
|
+
target.rows++;
|
|
404
|
+
target.predictedSelections += predicted.length;
|
|
405
|
+
target.actualSelections += actual.length;
|
|
406
|
+
target.matchedSelections += matched;
|
|
407
|
+
if (exact) target.exactRows++;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** Compare a pending prediction with the real layer router output. */
|
|
413
|
+
observeActual(layer: number, routes: readonly ExpertRouteLike[]): void {
|
|
414
|
+
const pending = this.#pending.get(layer);
|
|
415
|
+
if (!pending) return;
|
|
416
|
+
this.#pending.delete(layer);
|
|
417
|
+
if (pending.rows.length !== routes.length) {
|
|
418
|
+
throw new Error(
|
|
419
|
+
`GLM PILOT layer ${layer} predicted ${pending.rows.length} rows, ` +
|
|
420
|
+
`observed ${routes.length}`,
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
this.#observedCalls++;
|
|
424
|
+
const observedAt = this.#now();
|
|
425
|
+
this.#leadMs.push(Math.max(0, observedAt - pending.completedAt));
|
|
426
|
+
this.#scorePrediction(
|
|
427
|
+
layer,
|
|
428
|
+
pending.rows,
|
|
429
|
+
routes,
|
|
430
|
+
this.#counts,
|
|
431
|
+
this.#layers,
|
|
432
|
+
this.#rankMatches,
|
|
433
|
+
);
|
|
434
|
+
if (pending.twoStep) {
|
|
435
|
+
this.#twoObservedCalls++;
|
|
436
|
+
this.#twoLeadMs.push(
|
|
437
|
+
Math.max(0, observedAt - pending.twoStep.completedAt),
|
|
438
|
+
);
|
|
439
|
+
this.#scorePrediction(
|
|
440
|
+
layer,
|
|
441
|
+
pending.twoStep.rows,
|
|
442
|
+
routes,
|
|
443
|
+
this.#twoCounts,
|
|
444
|
+
this.#twoLayers,
|
|
445
|
+
this.#twoRankMatches,
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** Turn-safe snapshot. Draining also discards predictions left by failure. */
|
|
451
|
+
drainTelemetry(): Glm52PilotTelemetry {
|
|
452
|
+
const abandonedPredictions = this.#pending.size;
|
|
453
|
+
const observedRows = this.#counts.rows;
|
|
454
|
+
const telemetry: Glm52PilotTelemetry = {
|
|
455
|
+
mode: this.#hintSink ? "hint-only" : "measure-only",
|
|
456
|
+
maxRows: this.maxRows,
|
|
457
|
+
hintK: this.hintK,
|
|
458
|
+
predictionCalls: this.#predictionCalls,
|
|
459
|
+
observedCalls: this.#observedCalls,
|
|
460
|
+
rows: observedRows,
|
|
461
|
+
predictedSelections: this.#counts.predictedSelections,
|
|
462
|
+
actualSelections: this.#counts.actualSelections,
|
|
463
|
+
matchedSelections: this.#counts.matchedSelections,
|
|
464
|
+
exactRows: this.#counts.exactRows,
|
|
465
|
+
precision: ratio(
|
|
466
|
+
this.#counts.matchedSelections,
|
|
467
|
+
this.#counts.predictedSelections,
|
|
468
|
+
),
|
|
469
|
+
recall: ratio(
|
|
470
|
+
this.#counts.matchedSelections,
|
|
471
|
+
this.#counts.actualSelections,
|
|
472
|
+
),
|
|
473
|
+
exactRowRate: ratio(this.#counts.exactRows, observedRows),
|
|
474
|
+
rankHitRate: Object.freeze(this.#rankMatches.map((matches) =>
|
|
475
|
+
ratio(matches, observedRows))),
|
|
476
|
+
skippedWideCalls: this.#skippedWideCalls,
|
|
477
|
+
skippedWideRows: this.#skippedWideRows,
|
|
478
|
+
abandonedPredictions,
|
|
479
|
+
predictionLatency: summarizeExpertLatencies(this.#predictionMs),
|
|
480
|
+
leadTime: summarizeExpertLatencies(this.#leadMs),
|
|
481
|
+
layers: Object.freeze([...this.#layers.entries()]
|
|
482
|
+
.sort(([left], [right]) => left - right)
|
|
483
|
+
.map(([layer, counts]) => publicCounts(layer, counts))),
|
|
484
|
+
hints: this.#hintSink?.drainHintTelemetry() ?? null,
|
|
485
|
+
twoStep: this.twoStepEnabled
|
|
486
|
+
? {
|
|
487
|
+
predictionCalls: this.#twoPredictionCalls,
|
|
488
|
+
observedCalls: this.#twoObservedCalls,
|
|
489
|
+
rows: this.#twoCounts.rows,
|
|
490
|
+
predictedSelections: this.#twoCounts.predictedSelections,
|
|
491
|
+
actualSelections: this.#twoCounts.actualSelections,
|
|
492
|
+
matchedSelections: this.#twoCounts.matchedSelections,
|
|
493
|
+
exactRows: this.#twoCounts.exactRows,
|
|
494
|
+
precision: ratio(
|
|
495
|
+
this.#twoCounts.matchedSelections,
|
|
496
|
+
this.#twoCounts.predictedSelections,
|
|
497
|
+
),
|
|
498
|
+
recall: ratio(
|
|
499
|
+
this.#twoCounts.matchedSelections,
|
|
500
|
+
this.#twoCounts.actualSelections,
|
|
501
|
+
),
|
|
502
|
+
exactRowRate: ratio(
|
|
503
|
+
this.#twoCounts.exactRows,
|
|
504
|
+
this.#twoCounts.rows,
|
|
505
|
+
),
|
|
506
|
+
rankHitRate: Object.freeze(this.#twoRankMatches.map((matches) =>
|
|
507
|
+
ratio(matches, this.#twoCounts.rows))),
|
|
508
|
+
predictionLatency: summarizeExpertLatencies(
|
|
509
|
+
this.#twoPredictionMs,
|
|
510
|
+
),
|
|
511
|
+
leadTime: summarizeExpertLatencies(this.#twoLeadMs),
|
|
512
|
+
layers: Object.freeze([...this.#twoLayers.entries()]
|
|
513
|
+
.sort(([left], [right]) => left - right)
|
|
514
|
+
.map(([layer, counts]) => publicCounts(layer, counts))),
|
|
515
|
+
}
|
|
516
|
+
: null,
|
|
517
|
+
};
|
|
518
|
+
this.#pending.clear();
|
|
519
|
+
this.#counts = emptyCounts();
|
|
520
|
+
this.#layers.clear();
|
|
521
|
+
this.#rankMatches = Array(this.config.numExpertsPerToken).fill(0);
|
|
522
|
+
this.#predictionMs = [];
|
|
523
|
+
this.#leadMs = [];
|
|
524
|
+
this.#predictionCalls = 0;
|
|
525
|
+
this.#observedCalls = 0;
|
|
526
|
+
this.#skippedWideCalls = 0;
|
|
527
|
+
this.#skippedWideRows = 0;
|
|
528
|
+
this.#twoCounts = emptyCounts();
|
|
529
|
+
this.#twoLayers.clear();
|
|
530
|
+
this.#twoRankMatches = Array(this.config.numExpertsPerToken).fill(0);
|
|
531
|
+
this.#twoPredictionMs = [];
|
|
532
|
+
this.#twoLeadMs = [];
|
|
533
|
+
this.#twoPredictionCalls = 0;
|
|
534
|
+
this.#twoObservedCalls = 0;
|
|
535
|
+
return telemetry;
|
|
536
|
+
}
|
|
537
|
+
}
|