@seanhogg/builderforce-memory-engine 2026.7.12 → 2026.9.27
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 +14 -0
- package/dist/bench/adaptation.d.ts +57 -0
- package/dist/bench/adaptation.d.ts.map +1 -0
- package/dist/bench/adaptation.js +167 -0
- package/dist/bench/adaptation.js.map +1 -0
- package/dist/bench/harness.d.ts +2 -0
- package/dist/bench/harness.d.ts.map +1 -1
- package/dist/bench/harness.js +1 -1
- package/dist/bench/harness.js.map +1 -1
- package/dist/bench/index.d.ts +5 -3
- package/dist/bench/index.d.ts.map +1 -1
- package/dist/bench/index.js +4 -2
- package/dist/bench/index.js.map +1 -1
- package/dist/bench/types.d.ts +88 -0
- package/dist/bench/types.d.ts.map +1 -1
- package/dist/evermind/adapt.d.ts +40 -0
- package/dist/evermind/adapt.d.ts.map +1 -0
- package/dist/evermind/adapt.js +25 -0
- package/dist/evermind/adapt.js.map +1 -0
- package/dist/evermind/delta_wire.d.ts +43 -0
- package/dist/evermind/delta_wire.d.ts.map +1 -0
- package/dist/evermind/delta_wire.js +94 -0
- package/dist/evermind/delta_wire.js.map +1 -0
- package/dist/evermind/eval.d.ts +31 -0
- package/dist/evermind/eval.d.ts.map +1 -0
- package/dist/evermind/eval.js +36 -0
- package/dist/evermind/eval.js.map +1 -0
- package/dist/evermind/index.d.ts +16 -0
- package/dist/evermind/index.d.ts.map +1 -0
- package/dist/evermind/index.js +11 -0
- package/dist/evermind/index.js.map +1 -0
- package/dist/evermind/merge.d.ts +21 -0
- package/dist/evermind/merge.d.ts.map +1 -0
- package/dist/evermind/merge.js +79 -0
- package/dist/evermind/merge.js.map +1 -0
- package/dist/{moe/moe_package.d.ts → evermind/package.d.ts} +55 -5
- package/dist/evermind/package.d.ts.map +1 -0
- package/dist/{moe/moe_package.js → evermind/package.js} +118 -19
- package/dist/evermind/package.js.map +1 -0
- package/dist/import/foreign/adapter.d.ts +59 -0
- package/dist/import/foreign/adapter.d.ts.map +1 -0
- package/dist/import/foreign/adapter.js +76 -0
- package/dist/import/foreign/adapter.js.map +1 -0
- package/dist/import/foreign/apply.d.ts +23 -0
- package/dist/import/foreign/apply.d.ts.map +1 -0
- package/dist/import/foreign/apply.js +43 -0
- package/dist/import/foreign/apply.js.map +1 -0
- package/dist/import/foreign/codestral_mamba.d.ts +57 -0
- package/dist/import/foreign/codestral_mamba.d.ts.map +1 -0
- package/dist/import/foreign/codestral_mamba.js +174 -0
- package/dist/import/foreign/codestral_mamba.js.map +1 -0
- package/dist/import/foreign/falcon_mamba.d.ts +51 -0
- package/dist/import/foreign/falcon_mamba.d.ts.map +1 -0
- package/dist/import/foreign/falcon_mamba.js +131 -0
- package/dist/import/foreign/falcon_mamba.js.map +1 -0
- package/dist/import/foreign/index.d.ts +21 -0
- package/dist/import/foreign/index.d.ts.map +1 -0
- package/dist/import/foreign/index.js +18 -0
- package/dist/import/foreign/index.js.map +1 -0
- package/dist/import/foreign/plan.d.ts +122 -0
- package/dist/import/foreign/plan.d.ts.map +1 -0
- package/dist/import/foreign/plan.js +171 -0
- package/dist/import/foreign/plan.js.map +1 -0
- package/dist/import/foreign/registry.d.ts +35 -0
- package/dist/import/foreign/registry.d.ts.map +1 -0
- package/dist/import/foreign/registry.js +89 -0
- package/dist/import/foreign/registry.js.map +1 -0
- package/dist/import/index.d.ts +7 -0
- package/dist/import/index.d.ts.map +1 -1
- package/dist/import/index.js +7 -0
- package/dist/import/index.js.map +1 -1
- package/dist/index.d.ts +29 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -9
- package/dist/index.js.map +1 -1
- package/dist/kernels/selective_scan.d.ts.map +1 -1
- package/dist/kernels/selective_scan.js +15 -9
- package/dist/kernels/selective_scan.js.map +1 -1
- package/dist/kernels/slice.d.ts +26 -0
- package/dist/kernels/slice.d.ts.map +1 -0
- package/dist/kernels/slice.js +52 -0
- package/dist/kernels/slice.js.map +1 -0
- package/dist/kernels/weight_update.d.ts.map +1 -1
- package/dist/kernels/weight_update.js +30 -4
- package/dist/kernels/weight_update.js.map +1 -1
- package/dist/lm/evermind_lm.d.ts +180 -4
- package/dist/lm/evermind_lm.d.ts.map +1 -1
- package/dist/lm/evermind_lm.js +433 -116
- package/dist/lm/evermind_lm.js.map +1 -1
- package/dist/lm/index.d.ts +8 -2
- package/dist/lm/index.d.ts.map +1 -1
- package/dist/lm/index.js +6 -1
- package/dist/lm/index.js.map +1 -1
- package/dist/lm/text_embedder.d.ts +55 -0
- package/dist/lm/text_embedder.d.ts.map +1 -0
- package/dist/lm/text_embedder.js +62 -0
- package/dist/lm/text_embedder.js.map +1 -0
- package/dist/model/attention_block.d.ts.map +1 -1
- package/dist/model/attention_block.js +9 -5
- package/dist/model/attention_block.js.map +1 -1
- package/dist/model/mamba1_block.d.ts.map +1 -1
- package/dist/model/mamba1_block.js +28 -12
- package/dist/model/mamba1_block.js.map +1 -1
- package/dist/model/mamba2_block.d.ts.map +1 -1
- package/dist/model/mamba2_block.js +14 -9
- package/dist/model/mamba2_block.js.map +1 -1
- package/dist/model/mamba3_block.d.ts.map +1 -1
- package/dist/model/mamba3_block.js +14 -9
- package/dist/model/mamba3_block.js.map +1 -1
- package/dist/moe/index.d.ts +0 -2
- package/dist/moe/index.d.ts.map +1 -1
- package/dist/moe/index.js +0 -1
- package/dist/moe/index.js.map +1 -1
- package/dist/optim/adamw.d.ts +58 -1
- package/dist/optim/adamw.d.ts.map +1 -1
- package/dist/optim/adamw.js +69 -4
- package/dist/optim/adamw.js.map +1 -1
- package/dist/tokenizer/bpe.d.ts +28 -0
- package/dist/tokenizer/bpe.d.ts.map +1 -1
- package/dist/tokenizer/bpe.js +47 -0
- package/dist/tokenizer/bpe.js.map +1 -1
- package/dist/training/cpu_ops.d.ts +44 -0
- package/dist/training/cpu_ops.d.ts.map +1 -0
- package/dist/training/cpu_ops.js +111 -0
- package/dist/training/cpu_ops.js.map +1 -0
- package/dist/training/lora.d.ts +153 -0
- package/dist/training/lora.d.ts.map +1 -0
- package/dist/training/lora.js +324 -0
- package/dist/training/lora.js.map +1 -0
- package/dist/training/mamba1_cpu.d.ts +109 -0
- package/dist/training/mamba1_cpu.d.ts.map +1 -0
- package/dist/training/mamba1_cpu.js +316 -0
- package/dist/training/mamba1_cpu.js.map +1 -0
- package/dist/training/mixed_precision.d.ts +67 -0
- package/dist/training/mixed_precision.d.ts.map +1 -0
- package/dist/training/mixed_precision.js +101 -0
- package/dist/training/mixed_precision.js.map +1 -0
- package/dist/training/model_cpu.d.ts +100 -0
- package/dist/training/model_cpu.d.ts.map +1 -0
- package/dist/training/model_cpu.js +252 -0
- package/dist/training/model_cpu.js.map +1 -0
- package/dist/training/trainer.d.ts +156 -16
- package/dist/training/trainer.d.ts.map +1 -1
- package/dist/training/trainer.js +327 -101
- package/dist/training/trainer.js.map +1 -1
- package/dist/utils/base64.d.ts +12 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +27 -0
- package/dist/utils/base64.js.map +1 -0
- package/package.json +3 -1
- package/src/bench/adaptation.ts +180 -0
- package/src/bench/harness.ts +1 -1
- package/src/bench/index.ts +13 -2
- package/src/bench/types.ts +93 -0
- package/src/evermind/adapt.ts +61 -0
- package/src/evermind/delta_wire.ts +114 -0
- package/src/evermind/eval.ts +62 -0
- package/src/evermind/index.ts +33 -0
- package/src/evermind/merge.ts +106 -0
- package/src/{moe/moe_package.ts → evermind/package.ts} +148 -17
- package/src/import/foreign/adapter.ts +106 -0
- package/src/import/foreign/apply.ts +54 -0
- package/src/import/foreign/codestral_mamba.ts +224 -0
- package/src/import/foreign/falcon_mamba.ts +173 -0
- package/src/import/foreign/index.ts +37 -0
- package/src/import/foreign/plan.ts +294 -0
- package/src/import/foreign/registry.ts +126 -0
- package/src/import/index.ts +30 -0
- package/src/index.ts +104 -13
- package/src/kernels/selective_scan.ts +15 -9
- package/src/kernels/slice.ts +64 -0
- package/src/kernels/weight_update.ts +30 -4
- package/src/lm/evermind_lm.ts +470 -116
- package/src/lm/index.ts +12 -2
- package/src/lm/text_embedder.ts +84 -0
- package/src/model/attention_block.ts +9 -5
- package/src/model/mamba1_block.ts +28 -12
- package/src/model/mamba2_block.ts +14 -9
- package/src/model/mamba3_block.ts +14 -9
- package/src/moe/index.ts +0 -9
- package/src/optim/adamw.ts +115 -7
- package/src/tokenizer/bpe.ts +55 -0
- package/src/training/cpu_ops.ts +127 -0
- package/src/training/lora.ts +365 -0
- package/src/training/mamba1_cpu.ts +421 -0
- package/src/training/mixed_precision.ts +119 -0
- package/src/training/model_cpu.ts +360 -0
- package/src/training/trainer.ts +397 -154
- package/src/utils/base64.ts +28 -0
- package/dist/model/mamba_block.d.ts +0 -64
- package/dist/model/mamba_block.d.ts.map +0 -1
- package/dist/model/mamba_block.js +0 -303
- package/dist/model/mamba_block.js.map +0 -1
- package/dist/moe/moe_package.d.ts.map +0 -1
- package/dist/moe/moe_package.js.map +0 -1
- package/src/model/mamba_block.ts +0 -401
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* import/foreign/plan.ts — the ONE executor for a foreign-checkpoint weight port.
|
|
3
|
+
*
|
|
4
|
+
* A port is expressed declaratively: every target parameter of this engine's
|
|
5
|
+
* {@link HybridMambaModel} gets exactly one {@link PortRule} saying which source
|
|
6
|
+
* tensor feeds it and how the bytes are reshaped. Architecture adapters
|
|
7
|
+
* (`falcon_mamba.ts`, `codestral_mamba.ts`) only *describe* their rules — the
|
|
8
|
+
* matching, validation and transform logic lives here once, so a new
|
|
9
|
+
* architecture never re-implements it.
|
|
10
|
+
*
|
|
11
|
+
* The contract that makes a port trustworthy: NOTHING is silently dropped.
|
|
12
|
+
* • a target with no source in the checkpoint is a `fill` rule and is reported
|
|
13
|
+
* in {@link PortedCheckpoint.synthesisedTargets};
|
|
14
|
+
* • a source tensor no rule consumed is reported in
|
|
15
|
+
* {@link PortedCheckpoint.unmappedSources};
|
|
16
|
+
* • a source tensor only PARTLY consumed (e.g. Mamba-2's gate rows, which this
|
|
17
|
+
* engine's block has no branch for) is declared as a {@link PortDiscard};
|
|
18
|
+
* • a shape that doesn't line up throws, naming the tensor and both shapes.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { NamedTensor } from "../../export/tensors.js";
|
|
22
|
+
|
|
23
|
+
// ── Transform operations ─────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* How one source tensor becomes one target buffer.
|
|
27
|
+
*
|
|
28
|
+
* • `copy` — element-for-element; source and target shapes must
|
|
29
|
+
* agree once size-1 axes are squeezed out. Linear
|
|
30
|
+
* weights need no transpose: HF stores
|
|
31
|
+
* `[out_features, in_features]` row-major and this
|
|
32
|
+
* engine's LINEAR_FORWARD_WGSL reads `W` as `(N, K)`
|
|
33
|
+
* = `[out, in]` row-major — the same layout.
|
|
34
|
+
* • `convTaps` — a depthwise conv kernel `[C, 1, K]` (PyTorch
|
|
35
|
+
* `nn.Conv1d(groups=C)`) → `[C, K]` with the taps
|
|
36
|
+
* REVERSED. PyTorch pads left by `K-1` and cross-
|
|
37
|
+
* correlates: `y[t] = Σ_j w[j]·x[t + j - (K-1)]`,
|
|
38
|
+
* while conv1d.ts computes
|
|
39
|
+
* `y[t] = Σ_k w[k]·x[t - k]`. Substituting
|
|
40
|
+
* `k = K-1-j` shows the two agree only when the tap
|
|
41
|
+
* axis is reversed.
|
|
42
|
+
* • `rowSlice` — keep rows `[start, start+count)` of a rank-2
|
|
43
|
+
* source. Used for Mamba-2's fused `in_proj`.
|
|
44
|
+
* • `fill` — no source: fill the target with a constant.
|
|
45
|
+
* • `negExpToSoftplusInv` — `A_log` convention change. HF Mamba-2 uses
|
|
46
|
+
* `A = -exp(A_log)`; this engine's SSD kernel uses
|
|
47
|
+
* `A = -softplus(A_log)`. Re-express the same `A`:
|
|
48
|
+
* `target = softplus⁻¹(exp(source))`.
|
|
49
|
+
*/
|
|
50
|
+
export type PortOp =
|
|
51
|
+
| { kind: "copy" }
|
|
52
|
+
| { kind: "convTaps" }
|
|
53
|
+
| { kind: "rowSlice"; start: number; count: number }
|
|
54
|
+
| { kind: "fill"; value: number }
|
|
55
|
+
| { kind: "negExpToSoftplusInv" };
|
|
56
|
+
|
|
57
|
+
// ── Rules & plans ────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
/** How ONE target parameter of this engine is produced. */
|
|
60
|
+
export interface PortRule {
|
|
61
|
+
/** Target parameter name, exactly as `HybridMambaModel.parameters()` names it. */
|
|
62
|
+
target: string;
|
|
63
|
+
/** Expected target shape (row-major), for validation and reporting. */
|
|
64
|
+
shape: number[];
|
|
65
|
+
/**
|
|
66
|
+
* Candidate source tensor names, in preference order — the first one present
|
|
67
|
+
* in the checkpoint is used. Empty means the target is synthesised (`fill`),
|
|
68
|
+
* because this architecture has no such tensor.
|
|
69
|
+
*/
|
|
70
|
+
from: string[];
|
|
71
|
+
op: PortOp;
|
|
72
|
+
/** Why this isn't a plain copy / why there is no source. Required for `fill`. */
|
|
73
|
+
note?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A source tensor deliberately consumed only in part. */
|
|
77
|
+
export interface PortDiscard {
|
|
78
|
+
source: string;
|
|
79
|
+
/** How many source elements are left behind. */
|
|
80
|
+
elements: number;
|
|
81
|
+
reason: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The complete, architecture-specific description of a port. */
|
|
85
|
+
export interface PortPlan {
|
|
86
|
+
/** Adapter id, e.g. `falcon_mamba`. */
|
|
87
|
+
adapter: string;
|
|
88
|
+
rules: PortRule[];
|
|
89
|
+
discards: PortDiscard[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** A target that no source tensor feeds, and the constant used instead. */
|
|
93
|
+
export interface SynthesisedTarget {
|
|
94
|
+
target: string;
|
|
95
|
+
value: number;
|
|
96
|
+
reason: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The result of running a {@link PortPlan} over a checkpoint's tensors. */
|
|
100
|
+
export interface PortedTensors {
|
|
101
|
+
adapter: string;
|
|
102
|
+
/** Target parameter name → buffer, sized exactly as the model expects. */
|
|
103
|
+
weights: Map<string, Float32Array>;
|
|
104
|
+
/** Checkpoint tensors that no rule consumed (e.g. an untied `lm_head.weight`). */
|
|
105
|
+
unmappedSources: string[];
|
|
106
|
+
/** Targets this architecture has no tensor for. */
|
|
107
|
+
synthesisedTargets: SynthesisedTarget[];
|
|
108
|
+
/** Source tensors consumed only in part. */
|
|
109
|
+
discardedSources: PortDiscard[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── Source-name normalisation ────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Mistral publishes the same Mamba-2 weights twice: the HF conversion
|
|
116
|
+
* (`backbone.…`) and its native `consolidated.safetensors`, whose names carry a
|
|
117
|
+
* `model.` prefix. Strip it so one rule table serves both. The
|
|
118
|
+
* `embedding`/`embeddings` spelling difference is handled by the rules' `from`
|
|
119
|
+
* alternatives, not here.
|
|
120
|
+
*/
|
|
121
|
+
export function normaliseSourceName(name: string): string {
|
|
122
|
+
return name.startsWith("model.") ? name.slice("model.".length) : name;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Execution ────────────────────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
/** Product of a shape's dimensions (`[]` ⇒ 1). */
|
|
128
|
+
function numel(shape: readonly number[]): number {
|
|
129
|
+
return shape.reduce((n, d) => n * d, 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Shape with size-1 axes removed — `[C, 1, K]` and `[C, K]` compare equal. */
|
|
133
|
+
function squeeze(shape: readonly number[]): number[] {
|
|
134
|
+
const kept = shape.filter((d) => d !== 1);
|
|
135
|
+
return kept.length > 0 ? kept : [1];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sameShape(a: readonly number[], b: readonly number[]): boolean {
|
|
139
|
+
return a.length === b.length && a.every((d, i) => d === b[i]);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* `softplus⁻¹(y) = log(e^y − 1)`, evaluated so it neither overflows nor loses the
|
|
144
|
+
* small-`y` tail. Above ~30 `log(expm1(y))` and `y` agree to well inside f32
|
|
145
|
+
* precision, and `expm1` would have overflowed; below it, `expm1` keeps the
|
|
146
|
+
* precision `exp(y) - 1` would have thrown away.
|
|
147
|
+
*/
|
|
148
|
+
function softplusInverse(y: number): number {
|
|
149
|
+
if (!(y > 0)) {
|
|
150
|
+
throw new Error(`import/foreign: softplus⁻¹ needs a positive input, got ${y}`);
|
|
151
|
+
}
|
|
152
|
+
if (y > 30) return y;
|
|
153
|
+
return Math.log(Math.expm1(y));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Run one rule, returning the target buffer. Throws on any shape disagreement. */
|
|
157
|
+
function applyRule(rule: PortRule, source: NamedTensor | null): Float32Array {
|
|
158
|
+
const want = numel(rule.shape);
|
|
159
|
+
|
|
160
|
+
if (rule.op.kind === "fill") {
|
|
161
|
+
return new Float32Array(want).fill(rule.op.value);
|
|
162
|
+
}
|
|
163
|
+
if (!source) {
|
|
164
|
+
// Unreachable via executePortPlan (which checks first) — kept so a direct
|
|
165
|
+
// caller gets a real message rather than a null dereference.
|
|
166
|
+
throw new Error(`import/foreign: rule for "${rule.target}" has no source tensor`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const where = `"${source.name}" → "${rule.target}"`;
|
|
170
|
+
|
|
171
|
+
switch (rule.op.kind) {
|
|
172
|
+
case "copy":
|
|
173
|
+
case "negExpToSoftplusInv": {
|
|
174
|
+
if (!sameShape(squeeze(source.shape), squeeze(rule.shape))) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`import/foreign: ${where} shape mismatch — checkpoint has [${source.shape.join(", ")}], ` +
|
|
177
|
+
`this model expects [${rule.shape.join(", ")}]`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
if (source.data.length !== want) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`import/foreign: ${where} has ${source.data.length} elements, expected ${want}`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (rule.op.kind === "copy") return Float32Array.from(source.data);
|
|
186
|
+
const out = new Float32Array(want);
|
|
187
|
+
for (let i = 0; i < want; i++) out[i] = softplusInverse(Math.exp(source.data[i]!));
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case "convTaps": {
|
|
192
|
+
const [channels, kernel] = squeeze(rule.shape) as [number, number];
|
|
193
|
+
const src = squeeze(source.shape);
|
|
194
|
+
if (!sameShape(src, [channels, kernel])) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`import/foreign: ${where} depthwise conv shape mismatch — checkpoint has ` +
|
|
197
|
+
`[${source.shape.join(", ")}], this model expects [${rule.shape.join(", ")}] ` +
|
|
198
|
+
`(a [channels, 1, kernel] PyTorch kernel squeezes to [channels, kernel])`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const out = new Float32Array(want);
|
|
202
|
+
for (let c = 0; c < channels; c++) {
|
|
203
|
+
for (let k = 0; k < kernel; k++) {
|
|
204
|
+
// Reverse the tap axis — see PortOp.convTaps.
|
|
205
|
+
out[c * kernel + k] = source.data[c * kernel + (kernel - 1 - k)]!;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
case "rowSlice": {
|
|
212
|
+
if (source.shape.length !== 2) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`import/foreign: ${where} rowSlice needs a rank-2 source, got ` +
|
|
215
|
+
`[${source.shape.join(", ")}]`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const [rows, cols] = source.shape as [number, number];
|
|
219
|
+
const { start, count } = rule.op;
|
|
220
|
+
if (start < 0 || start + count > rows) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`import/foreign: ${where} rowSlice [${start}, ${start + count}) is outside the ` +
|
|
223
|
+
`checkpoint tensor's ${rows} rows — the source layout is not what this adapter expects`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
if (!sameShape(squeeze(rule.shape), squeeze([count, cols]))) {
|
|
227
|
+
throw new Error(
|
|
228
|
+
`import/foreign: ${where} rowSlice yields [${count}, ${cols}] but this model expects ` +
|
|
229
|
+
`[${rule.shape.join(", ")}]`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
return Float32Array.from(source.data.subarray(start * cols, (start + count) * cols));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Execute a plan against a checkpoint's tensors. Every rule must resolve; the
|
|
239
|
+
* first failure throws naming the offending tensor. Sources no rule touched are
|
|
240
|
+
* returned rather than ignored.
|
|
241
|
+
*/
|
|
242
|
+
export function executePortPlan(plan: PortPlan, tensors: NamedTensor[]): PortedTensors {
|
|
243
|
+
const byName = new Map<string, NamedTensor>();
|
|
244
|
+
for (const t of tensors) {
|
|
245
|
+
const name = normaliseSourceName(t.name);
|
|
246
|
+
byName.set(name, { ...t, name });
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const weights = new Map<string, Float32Array>();
|
|
250
|
+
const synthesisedTargets: SynthesisedTarget[] = [];
|
|
251
|
+
const consumed = new Set<string>();
|
|
252
|
+
|
|
253
|
+
for (const rule of plan.rules) {
|
|
254
|
+
if (weights.has(rule.target)) {
|
|
255
|
+
throw new Error(`import/foreign: plan "${plan.adapter}" defines "${rule.target}" twice`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (rule.from.length === 0) {
|
|
259
|
+
if (rule.op.kind !== "fill") {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`import/foreign: rule for "${rule.target}" names no source but is not a fill rule`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
weights.set(rule.target, applyRule(rule, null));
|
|
265
|
+
synthesisedTargets.push({
|
|
266
|
+
target: rule.target,
|
|
267
|
+
value: rule.op.value,
|
|
268
|
+
reason: rule.note ?? "this architecture has no corresponding tensor",
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const source = rule.from.map((n) => byName.get(n)).find((t): t is NamedTensor => t != null);
|
|
274
|
+
if (!source) {
|
|
275
|
+
throw new Error(
|
|
276
|
+
`import/foreign: checkpoint is missing "${rule.from[0]}" (needed for "${rule.target}", ` +
|
|
277
|
+
`expected shape [${rule.shape.join(", ")}])` +
|
|
278
|
+
(rule.from.length > 1 ? `; also tried ${rule.from.slice(1).map((n) => `"${n}"`).join(", ")}` : ""),
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
consumed.add(source.name);
|
|
282
|
+
weights.set(rule.target, applyRule(rule, source));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const unmappedSources = [...byName.keys()].filter((n) => !consumed.has(n)).sort();
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
adapter: plan.adapter,
|
|
289
|
+
weights,
|
|
290
|
+
unmappedSources,
|
|
291
|
+
synthesisedTargets,
|
|
292
|
+
discardedSources: plan.discards,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* import/foreign/registry.ts — config-driven adapter selection and the public
|
|
3
|
+
* port entry points.
|
|
4
|
+
*
|
|
5
|
+
* Given a checkpoint's `config.json`, pick the adapter by `model_type` /
|
|
6
|
+
* `architectures` and run its plan. An architecture nobody claims fails loudly
|
|
7
|
+
* with the list of what IS supported — and, for a transformer checkpoint, says
|
|
8
|
+
* why no map could ever exist for it.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { NamedTensor } from "../../export/tensors.js";
|
|
12
|
+
import type { HybridMambaModelConfig } from "../../model/mamba_model.js";
|
|
13
|
+
import { safetensorsToTensors } from "../safetensors.js";
|
|
14
|
+
import { executePortPlan, type PortDiscard, type PortedTensors, type SynthesisedTarget } from "./plan.js";
|
|
15
|
+
import { falconMambaAdapter } from "./falcon_mamba.js";
|
|
16
|
+
import { codestralMambaAdapter } from "./codestral_mamba.js";
|
|
17
|
+
import type { ForeignConfig, ForeignMambaAdapter } from "./adapter.js";
|
|
18
|
+
|
|
19
|
+
/** Every foreign SSM architecture this engine can warm-start from. */
|
|
20
|
+
export const FOREIGN_MAMBA_ADAPTERS: readonly ForeignMambaAdapter[] = [
|
|
21
|
+
falconMambaAdapter,
|
|
22
|
+
codestralMambaAdapter,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/** A completed port: the model to build, its weights, and what didn't line up. */
|
|
26
|
+
export interface PortedCheckpoint extends PortedTensors {
|
|
27
|
+
/** Construct a `HybridMambaModel` with this to receive {@link PortedTensors.weights}. */
|
|
28
|
+
modelConfig: HybridMambaModelConfig;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type { PortDiscard, SynthesisedTarget };
|
|
32
|
+
|
|
33
|
+
// ── Detection ────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
function architecturesOf(config: ForeignConfig): string[] {
|
|
36
|
+
const raw = config["architectures"];
|
|
37
|
+
return Array.isArray(raw) ? raw.filter((a): a is string => typeof a === "string") : [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function modelTypeOf(config: ForeignConfig): string | undefined {
|
|
41
|
+
const raw = config["model_type"];
|
|
42
|
+
return typeof raw === "string" ? raw : undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A checkpoint is a transformer when any declared architecture carries an
|
|
47
|
+
* attention-stack marker. Recognised only to give a better error: attention
|
|
48
|
+
* weights (Q/K/V/O, positional embeddings, per-token KV cache) have no
|
|
49
|
+
* counterpart in a state-space mixer, so no rename or reshape can port them.
|
|
50
|
+
*/
|
|
51
|
+
function looksLikeTransformer(architectures: string[], modelType: string | undefined): boolean {
|
|
52
|
+
const haystack = [...architectures, modelType ?? ""].join(" ").toLowerCase();
|
|
53
|
+
if (haystack.includes("mamba") || haystack.includes("ssm")) return false;
|
|
54
|
+
return /llama|mistral|qwen|gpt|phi|gemma|falcon(?!_?mamba)|starcoder|deepseek|olmo|attention|forcausallm/.test(
|
|
55
|
+
haystack,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function supportedList(): string {
|
|
60
|
+
return FOREIGN_MAMBA_ADAPTERS.map(
|
|
61
|
+
(a) => `${a.label} — architectures ${a.architectures.join(" / ")}, model_type ${a.modelTypes.join(" / ")}`,
|
|
62
|
+
).join("; ");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The adapter that claims this checkpoint. Throws — never guesses — when no
|
|
67
|
+
* adapter matches, because a wrong map produces a model that loads and then
|
|
68
|
+
* generates noise.
|
|
69
|
+
*/
|
|
70
|
+
export function foreignMambaAdapterFor(config: ForeignConfig): ForeignMambaAdapter {
|
|
71
|
+
const architectures = architecturesOf(config);
|
|
72
|
+
const modelType = modelTypeOf(config);
|
|
73
|
+
|
|
74
|
+
const byArch = FOREIGN_MAMBA_ADAPTERS.find((a) =>
|
|
75
|
+
architectures.some((name) => a.architectures.includes(name)),
|
|
76
|
+
);
|
|
77
|
+
if (byArch) return byArch;
|
|
78
|
+
|
|
79
|
+
const byType = modelType
|
|
80
|
+
? FOREIGN_MAMBA_ADAPTERS.find((a) => a.modelTypes.includes(modelType))
|
|
81
|
+
: undefined;
|
|
82
|
+
if (byType) return byType;
|
|
83
|
+
|
|
84
|
+
const seen =
|
|
85
|
+
architectures.length > 0
|
|
86
|
+
? `architectures [${architectures.join(", ")}]`
|
|
87
|
+
: modelType
|
|
88
|
+
? `model_type "${modelType}"`
|
|
89
|
+
: "a config declaring neither `architectures` nor `model_type`";
|
|
90
|
+
|
|
91
|
+
if (looksLikeTransformer(architectures, modelType)) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`import/foreign: ${seen} is a TRANSFORMER checkpoint — its attention weights ` +
|
|
94
|
+
`(q/k/v/o projections, positional embeddings) have no counterpart in a state-space ` +
|
|
95
|
+
`mixer, so no weight port can exist for it at any tensor naming. Transformer coders ` +
|
|
96
|
+
`(IQuest, NousCoder, Maincoder and the like) can only be brought across by ` +
|
|
97
|
+
`DISTILLATION — train this engine's SSM against the transformer's outputs. ` +
|
|
98
|
+
`Weight porting is supported only for: ${supportedList()}.`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
throw new Error(
|
|
103
|
+
`import/foreign: unsupported checkpoint — ${seen}. Supported: ${supportedList()}. ` +
|
|
104
|
+
`A transformer checkpoint cannot be weight-ported at all; distillation is the only route.`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ── Porting ──────────────────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Port a foreign checkpoint's tensors onto this engine's parameters. The result
|
|
112
|
+
* is device-free — {@link applyPortedWeights} uploads it into a live model.
|
|
113
|
+
*/
|
|
114
|
+
export function portForeignMamba(config: ForeignConfig, tensors: NamedTensor[]): PortedCheckpoint {
|
|
115
|
+
const adapter = foreignMambaAdapterFor(config);
|
|
116
|
+
const { modelConfig, plan } = adapter.describe(config);
|
|
117
|
+
return { ...executePortPlan(plan, tensors), modelConfig };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Convenience: port straight from a `.safetensors` buffer. */
|
|
121
|
+
export function portForeignMambaSafetensors(
|
|
122
|
+
config: ForeignConfig,
|
|
123
|
+
bytes: Uint8Array,
|
|
124
|
+
): PortedCheckpoint {
|
|
125
|
+
return portForeignMamba(config, safetensorsToTensors(bytes));
|
|
126
|
+
}
|
package/src/import/index.ts
CHANGED
|
@@ -4,8 +4,38 @@
|
|
|
4
4
|
* The inverse of {@link ../export}: read a `.safetensors` checkpoint back into a
|
|
5
5
|
* live {@link ../lm/evermind_lm.EvermindLM}. Round-trips Evermind's own exports,
|
|
6
6
|
* and warm-starts a foreign SSM checkpoint via a `rename` map.
|
|
7
|
+
*
|
|
8
|
+
* `./foreign` is the same seam for checkpoints that were never ours: published
|
|
9
|
+
* Mamba-1/Mamba-2 models, whose tensor names, layouts and `A_log`/conv
|
|
10
|
+
* conventions are reconciled onto `HybridMambaModel`'s parameters by a
|
|
11
|
+
* config-selected adapter.
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
14
|
export { safetensorsToTensors } from "./safetensors.js";
|
|
10
15
|
export { importEvermind, importEvermindTensors, inferArchFromTensors } from "./evermind.js";
|
|
11
16
|
export type { ImportOptions } from "./evermind.js";
|
|
17
|
+
|
|
18
|
+
// ── Foreign checkpoints (Falcon-Mamba / Codestral-Mamba → HybridMambaModel) ────
|
|
19
|
+
export {
|
|
20
|
+
FOREIGN_MAMBA_ADAPTERS,
|
|
21
|
+
foreignMambaAdapterFor,
|
|
22
|
+
portForeignMamba,
|
|
23
|
+
portForeignMambaSafetensors,
|
|
24
|
+
applyPortedWeights,
|
|
25
|
+
executePortPlan,
|
|
26
|
+
normaliseSourceName,
|
|
27
|
+
falconMambaAdapter,
|
|
28
|
+
codestralMambaAdapter,
|
|
29
|
+
} from "./foreign/index.js";
|
|
30
|
+
export type {
|
|
31
|
+
ForeignConfig,
|
|
32
|
+
ForeignMambaAdapter,
|
|
33
|
+
PortTarget,
|
|
34
|
+
PortDiscard,
|
|
35
|
+
PortOp,
|
|
36
|
+
PortPlan,
|
|
37
|
+
PortRule,
|
|
38
|
+
PortedCheckpoint,
|
|
39
|
+
PortedTensors,
|
|
40
|
+
SynthesisedTarget,
|
|
41
|
+
} from "./foreign/index.js";
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* @seanhogg/builderforce-memory-engine – entry point
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
// ── Model classes ─────────────────────────────────────────────────────────────
|
|
@@ -22,7 +22,6 @@ export {
|
|
|
22
22
|
DEFAULT_MOE_CONFIG,
|
|
23
23
|
DEFAULT_MOE_SEED,
|
|
24
24
|
MoETrainer,
|
|
25
|
-
EvermindModelPackage,
|
|
26
25
|
} from './moe/index.js';
|
|
27
26
|
export type {
|
|
28
27
|
MoEConfig,
|
|
@@ -31,23 +30,82 @@ export type {
|
|
|
31
30
|
MoESample,
|
|
32
31
|
MoETrainOptions,
|
|
33
32
|
MoEEpochResult,
|
|
33
|
+
} from './moe/index.js';
|
|
34
|
+
|
|
35
|
+
// ── Evermind (the .evermind artifact + the shared learning pipeline) ───────────
|
|
36
|
+
export {
|
|
37
|
+
EvermindModelPackage,
|
|
38
|
+
adaptAndDiff,
|
|
39
|
+
EVERMIND_ADAPT_MAX_CHARS,
|
|
40
|
+
EVERMIND_ADAPT_WINDOW_TOKENS,
|
|
41
|
+
parseDeltaLearnPayload,
|
|
42
|
+
buildDeltaLearnPayload,
|
|
43
|
+
decodeDeltaPayload,
|
|
44
|
+
deltaUnusableReason,
|
|
45
|
+
MAX_DELTA_B64_CHARS,
|
|
46
|
+
DELTA_LABEL_MAX_CHARS,
|
|
47
|
+
mergeCheckpointDiffs,
|
|
48
|
+
meanEvalLoss,
|
|
49
|
+
sequenceLoss,
|
|
50
|
+
EVAL_MAX_TOKENS,
|
|
51
|
+
} from './evermind/index.js';
|
|
52
|
+
export type {
|
|
34
53
|
EvermindModelManifest,
|
|
35
54
|
EvermindModelCard,
|
|
36
55
|
EvermindModelType,
|
|
37
56
|
EvermindModality,
|
|
38
57
|
PackageMeta,
|
|
39
58
|
ValidationResult,
|
|
40
|
-
|
|
59
|
+
AdaptResult,
|
|
60
|
+
AdaptOptions,
|
|
61
|
+
AdaptTokenizer,
|
|
62
|
+
DeltaLearnPayload,
|
|
63
|
+
DeltaParseResult,
|
|
64
|
+
MergeResult,
|
|
65
|
+
EvalExample,
|
|
66
|
+
EvalTokenizer,
|
|
67
|
+
} from './evermind/index.js';
|
|
41
68
|
|
|
42
69
|
// ── EvermindLM (the generative model) + AdamW ──────────────────────────────────
|
|
43
|
-
export { EvermindLM, EvermindLMTrainer, DEFAULT_LM_CONFIG, DEFAULT_LM_SEED } from './lm/index.js';
|
|
44
|
-
|
|
45
|
-
export {
|
|
46
|
-
export type {
|
|
70
|
+
export { EvermindLM, EvermindLMTrainer, DEFAULT_LM_CONFIG, DEFAULT_LM_SEED, logProbOfToken } from './lm/index.js';
|
|
71
|
+
// CPU text→vector embedder — SSM-embedding recall with no GPU.
|
|
72
|
+
export { EvermindTextEmbedder } from './lm/index.js';
|
|
73
|
+
export type { EvermindLMConfig, LMGenerateOptions, TextCodec, EvermindLMTrainOptions, EvermindLMDecodeState } from './lm/index.js';
|
|
74
|
+
export type { TextEmbedder, EmbedderCodec } from './lm/index.js';
|
|
75
|
+
export { AdamW, adamwUpdateInPlace } from './optim/adamw.js';
|
|
76
|
+
export type { AdamWOptions, OptimTarget, OptimParam, ShardSpec, AdamWKernelStep } from './optim/adamw.js';
|
|
77
|
+
|
|
78
|
+
// PEFT / efficient-training toolkit (LoRA, QLoRA, mixed precision, checkpointing).
|
|
79
|
+
export { LoRAAdapter, EvermindLMLoRA, quantizeBase } from './training/lora.js';
|
|
80
|
+
export type { LoRAConfig, LoRAFitOptions, BaseQuant } from './training/lora.js';
|
|
81
|
+
export { DynamicLossScaler, roundFp16, fp16View } from './training/mixed_precision.js';
|
|
82
|
+
export type { LossScalerOptions } from './training/mixed_precision.js';
|
|
47
83
|
|
|
48
84
|
// ── Training ──────────────────────────────────────────────────────────────────
|
|
49
85
|
|
|
50
|
-
export { MambaTrainer } from './training/trainer.js';
|
|
86
|
+
export { MambaTrainer, cpuDimsFor, buildChunks, buildBatches, WSLA_MAX_DELTA } from './training/trainer.js';
|
|
87
|
+
export type { TrainOptions } from './training/trainer.js';
|
|
88
|
+
// The exact CPU forward + backward the trainer differentiates with. Exported so a
|
|
89
|
+
// host can compute gradients (or gradient-check the model) without a GPU.
|
|
90
|
+
export {
|
|
91
|
+
cpuModelForward, cpuModelLoss, cpuModelBackward,
|
|
92
|
+
zeroCpuModelGrads, toNamedGrads, namedWeights, cpuWeightsFromNamed,
|
|
93
|
+
paramMatrixShape, DEFAULT_LORA_TARGETS, CPU_GRADIENT_LAYER_TYPES,
|
|
94
|
+
} from './training/model_cpu.js';
|
|
95
|
+
export type {
|
|
96
|
+
CpuModelDims, CpuModelWeights, CpuModelGrads, CpuBackwardResult, CpuBackwardOptions, CpuGradientLayerType,
|
|
97
|
+
} from './training/model_cpu.js';
|
|
98
|
+
export {
|
|
99
|
+
mamba1CpuForward, mamba1CpuBackward, zeroMamba1Grads,
|
|
100
|
+
MAMBA1_PARAM_NAMES, A_LOG_CLAMP_LO, A_LOG_CLAMP_HI,
|
|
101
|
+
} from './training/mamba1_cpu.js';
|
|
102
|
+
export type {
|
|
103
|
+
Mamba1CpuWeights, Mamba1CpuDims, Mamba1CpuCache, Mamba1CpuGrads, Mamba1CpuForwardResult,
|
|
104
|
+
} from './training/mamba1_cpu.js';
|
|
105
|
+
export {
|
|
106
|
+
linearForward, linearBackward, rmsNormForward, rmsNormBackward,
|
|
107
|
+
silu, siluGrad, softplus, sigmoid, RMSNORM_EPS,
|
|
108
|
+
} from './training/cpu_ops.js';
|
|
51
109
|
export {
|
|
52
110
|
Tensor,
|
|
53
111
|
backward,
|
|
@@ -62,6 +120,7 @@ export {
|
|
|
62
120
|
// ── Tokenizer ─────────────────────────────────────────────────────────────────
|
|
63
121
|
|
|
64
122
|
export { BPETokenizer } from './tokenizer/bpe.js';
|
|
123
|
+
export type { BPETokenizerSpec } from './tokenizer/bpe.js';
|
|
65
124
|
export type { BPEEncodeOptions, PadSide, HuggingFaceTokenizerSpec, SpecialTokenOverrides } from './tokenizer/bpe.js';
|
|
66
125
|
|
|
67
126
|
// ── Modality codecs (media ⇄ tokens; lets EvermindLM generate video) ────────────
|
|
@@ -123,6 +182,34 @@ export {
|
|
|
123
182
|
} from './import/index.js';
|
|
124
183
|
export type { ImportOptions } from './import/index.js';
|
|
125
184
|
|
|
185
|
+
// ── Foreign weight port (Falcon-Mamba / Codestral-Mamba → HybridMambaModel) ────
|
|
186
|
+
// Transformer checkpoints are NOT portable — distillation is the only route, and
|
|
187
|
+
// `foreignMambaAdapterFor` rejects them saying so.
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
FOREIGN_MAMBA_ADAPTERS,
|
|
191
|
+
foreignMambaAdapterFor,
|
|
192
|
+
portForeignMamba,
|
|
193
|
+
portForeignMambaSafetensors,
|
|
194
|
+
applyPortedWeights,
|
|
195
|
+
executePortPlan,
|
|
196
|
+
normaliseSourceName,
|
|
197
|
+
falconMambaAdapter,
|
|
198
|
+
codestralMambaAdapter,
|
|
199
|
+
} from './import/index.js';
|
|
200
|
+
export type {
|
|
201
|
+
ForeignConfig,
|
|
202
|
+
ForeignMambaAdapter,
|
|
203
|
+
PortTarget,
|
|
204
|
+
PortDiscard,
|
|
205
|
+
PortOp,
|
|
206
|
+
PortPlan,
|
|
207
|
+
PortRule,
|
|
208
|
+
PortedCheckpoint,
|
|
209
|
+
PortedTensors,
|
|
210
|
+
SynthesisedTarget,
|
|
211
|
+
} from './import/index.js';
|
|
212
|
+
|
|
126
213
|
// ── Benchmarking (held-out perplexity / accuracy / throughput + A/B) ──────────
|
|
127
214
|
|
|
128
215
|
export {
|
|
@@ -133,6 +220,10 @@ export {
|
|
|
133
220
|
compareReports,
|
|
134
221
|
corpusToSequences,
|
|
135
222
|
trainAndBenchmark,
|
|
223
|
+
benchmarkAdaptationCost,
|
|
224
|
+
formatAdaptationCostReport,
|
|
225
|
+
tokenWindows,
|
|
226
|
+
adaptationsAfterSkip,
|
|
136
227
|
argmax as benchArgmax,
|
|
137
228
|
topKIndices,
|
|
138
229
|
perplexity,
|
|
@@ -147,6 +238,9 @@ export type {
|
|
|
147
238
|
ComparisonReport,
|
|
148
239
|
TrainAndBenchmarkOptions,
|
|
149
240
|
TrainAndBenchmarkResult,
|
|
241
|
+
AdaptationCostOptions,
|
|
242
|
+
AdaptationCostPoint,
|
|
243
|
+
AdaptationCostReport,
|
|
150
244
|
} from './bench/index.js';
|
|
151
245
|
|
|
152
246
|
// ── Checkpoint integrity (CRC-32 + trailer) ───────────────────────────────────
|
|
@@ -162,6 +256,7 @@ export {
|
|
|
162
256
|
applyCheckpointDiff,
|
|
163
257
|
} from './utils/delta.js';
|
|
164
258
|
export type { RowDelta } from './utils/delta.js';
|
|
259
|
+
export { bytesToBase64, base64ToBytes } from './utils/base64.js';
|
|
165
260
|
|
|
166
261
|
// ── Seeded RNG (reproducible weight init) ─────────────────────────────────────
|
|
167
262
|
|
|
@@ -222,6 +317,7 @@ export { CONV1D_FORWARD_WGSL, CONV1D_BACKWARD_WGSL }
|
|
|
222
317
|
from './kernels/conv1d.js';
|
|
223
318
|
export { LINEAR_FORWARD_WGSL, LINEAR_BACKWARD_WGSL }
|
|
224
319
|
from './kernels/linear_projection.js';
|
|
320
|
+
export { COL_SLICE_WGSL, COL_SLICE_ENTRY, dispatchColumnSlice } from './kernels/slice.js';
|
|
225
321
|
export { WEIGHT_UPDATE_WGSL, GRAD_CLIP_WGSL }
|
|
226
322
|
from './kernels/weight_update.js';
|
|
227
323
|
export { ACTIVATIONS_WGSL, ACTIVATIONS_BACKWARD_WGSL, SOFTMAX_FORWARD_WGSL, SOFTMAX_BACKWARD_WGSL }
|
|
@@ -271,8 +367,3 @@ export type {
|
|
|
271
367
|
} from './limbic/index.js';
|
|
272
368
|
|
|
273
369
|
export { LIMBIC_AFFECT_WGSL } from './kernels/limbic_affect.js';
|
|
274
|
-
|
|
275
|
-
// ── Version ───────────────────────────────────────────────────────────────────
|
|
276
|
-
|
|
277
|
-
export const VERSION = '2.0.0';
|
|
278
|
-
export const DESCRIPTION = 'MambaCode.js: WebGPU-accelerated Mamba-1/2/3 and Hybrid SSM for browser code models';
|
|
@@ -132,21 +132,27 @@ fn forward_scan(
|
|
|
132
132
|
// ---- Kogge-Stone inclusive prefix scan within tile ----
|
|
133
133
|
// Associative operator: (a1, b1) ∘ (a2, b2) = (a1*a2, a1*b2 + b1)
|
|
134
134
|
// This computes cumulative state recurrence in log2(TILE) steps.
|
|
135
|
+
// NOTE the barrier placement. Both barriers MUST sit in uniform control
|
|
136
|
+
// flow — every invocation in the workgroup has to reach them. The earlier
|
|
137
|
+
// version put the first workgroupBarrier() INSIDE the if (lid >= stride)
|
|
138
|
+
// branch, which is a WGSL uniformity violation: shader creation fails on a
|
|
139
|
+
// conformant implementation. Computing into locals first, then writing
|
|
140
|
+
// back after a uniform barrier, is the correct read-then-write split.
|
|
135
141
|
var stride: u32 = 1u;
|
|
136
142
|
loop {
|
|
137
143
|
if (stride >= TILE) { break; }
|
|
144
|
+
var new_a = wg_a[lid];
|
|
145
|
+
var new_bu = wg_bu[lid];
|
|
138
146
|
if (lid >= stride) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
let new_a = prev_a * wg_a[lid];
|
|
144
|
-
let new_bu = prev_a * wg_bu[lid] + prev_bu;
|
|
145
|
-
workgroupBarrier();
|
|
146
|
-
wg_a[lid] = new_a;
|
|
147
|
-
wg_bu[lid] = new_bu;
|
|
147
|
+
// Combine: new_a = prev_a * cur_a (product of A_bars)
|
|
148
|
+
// new_bu = prev_a * cur_bu + prev_bu
|
|
149
|
+
new_a = wg_a[lid - stride] * new_a;
|
|
150
|
+
new_bu = wg_a[lid - stride] * new_bu + wg_bu[lid - stride];
|
|
148
151
|
}
|
|
149
152
|
workgroupBarrier();
|
|
153
|
+
wg_a[lid] = new_a;
|
|
154
|
+
wg_bu[lid] = new_bu;
|
|
155
|
+
workgroupBarrier();
|
|
150
156
|
stride = stride << 1u;
|
|
151
157
|
}
|
|
152
158
|
|