@matchbox-ai/train 0.2.1 → 0.2.2
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/CHANGELOG.md +7 -0
- package/dist/index.js +1 -1
- package/dist/models/sequence/export-parity.d.ts +16 -0
- package/dist/models/sequence/export-parity.d.ts.map +1 -0
- package/dist/models/sequence/fit-sequence.d.ts +4 -1
- package/dist/models/sequence/fit-sequence.d.ts.map +1 -1
- package/dist/models/sequence/run-sequence.d.ts +4 -1
- package/dist/models/sequence/run-sequence.d.ts.map +1 -1
- package/dist/{run-PB_jiKnw.js → run-Y4hS_j62.js} +2 -2
- package/dist/{run-PB_jiKnw.js.map → run-Y4hS_j62.js.map} +1 -1
- package/dist/run.d.ts +4 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/{sequence-DGoGU7kG.js → sequence-CZLL5c0A.js} +37 -8
- package/dist/sequence-CZLL5c0A.js.map +1 -0
- package/dist/train.d.ts +4 -1
- package/dist/train.d.ts.map +1 -1
- package/docs/contributing.md +14 -0
- package/docs/reference/training.md +2 -0
- package/package.json +3 -3
- package/prebuilds/win32-arm64/node.napi.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/dist/sequence-DGoGU7kG.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @matchbox-ai/train
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 833edc6: Verify sequence exports with an explicit 0.0001 absolute confidence tolerance for float32 predictions. Continue rejecting every label disagreement, and now reject differences that cross the model acceptance threshold. Record the measured drift, tolerance, checked token count and acceptance disagreements in exportParity and include diagnostic details when verification fails.
|
|
8
|
+
- @matchbox-ai/core@0.2.2
|
|
9
|
+
|
|
3
10
|
## 0.2.1
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ function tokenClassifier(options = {}) {
|
|
|
20
20
|
/** Runs the same validation, selection, and packaging pipeline as the CLI. */
|
|
21
21
|
async function train(target, options = {}) {
|
|
22
22
|
const { discover } = await import("./project/index.js");
|
|
23
|
-
const { run } = await import("./run-
|
|
23
|
+
const { run } = await import("./run-Y4hS_j62.js");
|
|
24
24
|
return run("train", await discover(target), options.onProgress);
|
|
25
25
|
}
|
|
26
26
|
//#endregion
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type Prediction = {
|
|
2
|
+
label: string;
|
|
3
|
+
confidence: number;
|
|
4
|
+
};
|
|
5
|
+
export declare function sequenceParity(threshold: number): {
|
|
6
|
+
add(native: Prediction, portable: Prediction): void;
|
|
7
|
+
report(): {
|
|
8
|
+
tokens: number;
|
|
9
|
+
maxConfidenceError: number;
|
|
10
|
+
confidenceTolerance: number;
|
|
11
|
+
labelDisagreements: number;
|
|
12
|
+
acceptanceDisagreements: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=export-parity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-parity.d.ts","sourceRoot":"","sources":["../../../src/models/sequence/export-parity.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAKxD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM;IAM5C,GAAG,SAAS,UAAU,YAAY,UAAU;IAgB5C,MAAM;;;;;;;EAkBT"}
|
|
@@ -23,9 +23,12 @@ export declare function fitSequence(examples: readonly DatasetExample<unknown>[]
|
|
|
23
23
|
parameters: number;
|
|
24
24
|
history: number[];
|
|
25
25
|
parity: {
|
|
26
|
-
|
|
26
|
+
tokens: number;
|
|
27
27
|
maxConfidenceError: number;
|
|
28
|
+
confidenceTolerance: number;
|
|
28
29
|
labelDisagreements: number;
|
|
30
|
+
acceptanceDisagreements: number;
|
|
31
|
+
examples: number;
|
|
29
32
|
};
|
|
30
33
|
supervisedTokens: number;
|
|
31
34
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fit-sequence.d.ts","sourceRoot":"","sources":["../../../src/models/sequence/fit-sequence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fit-sequence.d.ts","sourceRoot":"","sources":["../../../src/models/sequence/fit-sequence.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAC5C,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,cAAc,GAAG,eAAe,CAAC,EACjF,MAAM,GAAE,SAAS,MAAM,EAAO,EAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDjD"}
|
|
@@ -40,9 +40,12 @@ export declare function runSequence(command: "train" | "eval", project: Awaited<
|
|
|
40
40
|
supervisedTokens: number;
|
|
41
41
|
loss: number[];
|
|
42
42
|
exportParity: {
|
|
43
|
-
|
|
43
|
+
tokens: number;
|
|
44
44
|
maxConfidenceError: number;
|
|
45
|
+
confidenceTolerance: number;
|
|
45
46
|
labelDisagreements: number;
|
|
47
|
+
acceptanceDisagreements: number;
|
|
48
|
+
examples: number;
|
|
46
49
|
};
|
|
47
50
|
validation: {
|
|
48
51
|
examples: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-sequence.d.ts","sourceRoot":"","sources":["../../../src/models/sequence/run-sequence.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAMzD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,EAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAmG5C,KAAK;YACL,UAAU;YACV,UAAU;YACV,IAAI
|
|
1
|
+
{"version":3,"file":"run-sequence.d.ts","sourceRoot":"","sources":["../../../src/models/sequence/run-sequence.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAMzD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,EAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAmG5C,KAAK;YACL,UAAU;YACV,UAAU;YACV,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsBT"}
|
|
@@ -57,7 +57,7 @@ async function loadProject(path) {
|
|
|
57
57
|
async function run(command, path, progress) {
|
|
58
58
|
const project = await loadProject(path);
|
|
59
59
|
if (project.config.sequence) {
|
|
60
|
-
const { runSequence } = await import("./sequence-
|
|
60
|
+
const { runSequence } = await import("./sequence-CZLL5c0A.js");
|
|
61
61
|
return runSequence(command, project, progress);
|
|
62
62
|
}
|
|
63
63
|
if (command !== "train") throw new Error("Use the eval CLI command to evaluate a saved artifact.");
|
|
@@ -67,4 +67,4 @@ async function run(command, path, progress) {
|
|
|
67
67
|
//#endregion
|
|
68
68
|
export { run };
|
|
69
69
|
|
|
70
|
-
//# sourceMappingURL=run-
|
|
70
|
+
//# sourceMappingURL=run-Y4hS_j62.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-
|
|
1
|
+
{"version":3,"file":"run-Y4hS_j62.js","names":[],"sources":["../src/load-project.ts","../src/run.ts"],"sourcesContent":["import { loadConfig } from \"./project/index.js\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { z } from \"zod\";\nimport { parseDatasets } from \"@matchbox-ai/core\";\nimport type { ParserDefinition } from \"@matchbox-ai/core\";\nexport async function loadProject(path: string) {\n const { config, root } = await loadConfig(path);\n const taskPath = resolve(root, config.task);\n const task: ParserDefinition<z.ZodType> = (await import(pathToFileURL(taskPath).href)).default;\n const sources = await Promise.all(\n [config.train, config.validation, config.eval].map(async (source) => ({\n source,\n text: await readFile(resolve(root, source), \"utf8\"),\n })),\n );\n const training = parseDatasets(task, { formatVersion: 1, train: sources[0]!, eval: sources[1]! });\n const evaluation = parseDatasets(task, {\n formatVersion: 1,\n train: sources[0]!,\n eval: sources[2]!,\n });\n for (const result of [training, evaluation]) {\n if (!result.success) {\n throw new Error(\n result.issues\n .map((issue) => `${issue.source}:${issue.line} ${issue.path.join(\".\")}: ${issue.message}`)\n .join(\"\\n\"),\n );\n }\n }\n if (!training.success || !evaluation.success) {\n throw new Error(\"Invalid datasets.\");\n }\n const groups = [training.data.train, training.data.eval, evaluation.data.eval];\n const seen = new Map<string, number>();\n groups.forEach((group, split) =>\n group.forEach((row) => {\n const key = row.input.trim().toLowerCase();\n if (seen.has(key) && seen.get(key) !== split) {\n throw new Error(`Input overlaps dataset splits: ${row.input}`);\n }\n seen.set(key, split);\n }),\n );\n return {\n root,\n config,\n task,\n taskPath,\n output: resolve(root, config.output),\n sources,\n train: training.data.train,\n validation: training.data.eval,\n evaluation: evaluation.data.eval,\n };\n}\n","import { loadProject } from \"./load-project.js\";\nexport async function run(\n command: \"train\" | \"eval\",\n path: string,\n progress?: (epoch: number, loss: number) => void,\n) {\n const project = await loadProject(path);\n if (project.config.sequence) {\n const { runSequence } = await import(\"./models/sequence/index.js\");\n return runSequence(command, project, progress);\n }\n if (command !== \"train\") {\n throw new Error(\"Use the eval CLI command to evaluate a saved artifact.\");\n }\n const { runRecord } = await import(\"./models/record/index.js\");\n return runRecord(project, progress);\n}\n"],"mappings":";;;;;;;AAOA,eAAsB,YAAY,MAAc;CAC9C,MAAM,EAAE,QAAQ,SAAS,MAAM,WAAW,IAAI;CAC9C,MAAM,WAAW,QAAQ,MAAM,OAAO,IAAI;CAC1C,MAAM,QAAqC,MAAM,OAAO,cAAc,QAAQ,CAAC,CAAC,MAAA,CAAO;CACvF,MAAM,UAAU,MAAM,QAAQ,IAC5B;EAAC,OAAO;EAAO,OAAO;EAAY,OAAO;CAAI,CAAC,CAAC,IAAI,OAAO,YAAY;EACpE;EACA,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,GAAG,MAAM;CACpD,EAAE,CACJ;CACA,MAAM,WAAW,cAAc,MAAM;EAAE,eAAe;EAAG,OAAO,QAAQ;EAAK,MAAM,QAAQ;CAAI,CAAC;CAChG,MAAM,aAAa,cAAc,MAAM;EACrC,eAAe;EACf,OAAO,QAAQ;EACf,MAAM,QAAQ;CAChB,CAAC;CACD,KAAK,MAAM,UAAU,CAAC,UAAU,UAAU,GACxC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MACR,OAAO,OACJ,KAAK,UAAU,GAAG,MAAM,OAAO,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,KAAK,GAAG,EAAE,IAAI,MAAM,SAAS,CAAC,CACzF,KAAK,IAAI,CACd;CAGJ,IAAI,CAAC,SAAS,WAAW,CAAC,WAAW,SACnC,MAAM,IAAI,MAAM,mBAAmB;CAErC,MAAM,SAAS;EAAC,SAAS,KAAK;EAAO,SAAS,KAAK;EAAM,WAAW,KAAK;CAAI;CAC7E,MAAM,uBAAO,IAAI,IAAoB;CACrC,OAAO,SAAS,OAAO,UACrB,MAAM,SAAS,QAAQ;EACrB,MAAM,MAAM,IAAI,MAAM,KAAK,CAAC,CAAC,YAAY;EACzC,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,MAAM,OACrC,MAAM,IAAI,MAAM,kCAAkC,IAAI,OAAO;EAE/D,KAAK,IAAI,KAAK,KAAK;CACrB,CAAC,CACH;CACA,OAAO;EACL;EACA;EACA;EACA;EACA,QAAQ,QAAQ,MAAM,OAAO,MAAM;EACnC;EACA,OAAO,SAAS,KAAK;EACrB,YAAY,SAAS,KAAK;EAC1B,YAAY,WAAW,KAAK;CAC9B;AACF;;;ACxDA,eAAsB,IACpB,SACA,MACA,UACA;CACA,MAAM,UAAU,MAAM,YAAY,IAAI;CACtC,IAAI,QAAQ,OAAO,UAAU;EAC3B,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,OAAO,YAAY,SAAS,SAAS,QAAQ;CAC/C;CACA,IAAI,YAAY,SACd,MAAM,IAAI,MAAM,wDAAwD;CAE1E,MAAM,EAAE,cAAc,MAAM,OAAO;CACnC,OAAO,UAAU,SAAS,QAAQ;AACpC"}
|
package/dist/run.d.ts
CHANGED
|
@@ -39,9 +39,12 @@ export declare function run(command: "train" | "eval", path: string, progress?:
|
|
|
39
39
|
supervisedTokens: number;
|
|
40
40
|
loss: number[];
|
|
41
41
|
exportParity: {
|
|
42
|
-
|
|
42
|
+
tokens: number;
|
|
43
43
|
maxConfidenceError: number;
|
|
44
|
+
confidenceTolerance: number;
|
|
44
45
|
labelDisagreements: number;
|
|
46
|
+
acceptanceDisagreements: number;
|
|
47
|
+
examples: number;
|
|
45
48
|
};
|
|
46
49
|
validation: {
|
|
47
50
|
examples: number;
|
package/dist/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,wBAAsB,GAAG,CACvB,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,wBAAsB,GAAG,CACvB,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAYjD"}
|
|
@@ -19,6 +19,36 @@ function fit(config, inputs, labels, progress) {
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
|
+
//#region src/models/sequence/export-parity.ts
|
|
23
|
+
/** Float32 probability tolerance, independent of the model's acceptance threshold. */
|
|
24
|
+
const confidenceTolerance = 1e-4;
|
|
25
|
+
function sequenceParity(threshold) {
|
|
26
|
+
let tokens = 0;
|
|
27
|
+
let maxConfidenceError = 0;
|
|
28
|
+
let labelDisagreements = 0;
|
|
29
|
+
let acceptanceDisagreements = 0;
|
|
30
|
+
return {
|
|
31
|
+
add(native, portable) {
|
|
32
|
+
if (![native.confidence, portable.confidence].every(Number.isFinite)) throw new Error("Burn export parity received non-finite confidence.");
|
|
33
|
+
tokens++;
|
|
34
|
+
maxConfidenceError = Math.max(maxConfidenceError, Math.abs(native.confidence - portable.confidence));
|
|
35
|
+
if (native.label !== portable.label) labelDisagreements++;
|
|
36
|
+
if (native.confidence >= threshold !== portable.confidence >= threshold) acceptanceDisagreements++;
|
|
37
|
+
},
|
|
38
|
+
report() {
|
|
39
|
+
const report = {
|
|
40
|
+
tokens,
|
|
41
|
+
maxConfidenceError,
|
|
42
|
+
confidenceTolerance,
|
|
43
|
+
labelDisagreements,
|
|
44
|
+
acceptanceDisagreements
|
|
45
|
+
};
|
|
46
|
+
if (labelDisagreements || acceptanceDisagreements || maxConfidenceError > confidenceTolerance) throw new Error(`Burn native and WASM predictions disagree: ${JSON.stringify(report)}`);
|
|
47
|
+
return report;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
22
52
|
//#region src/models/sequence/prepare-supervision.ts
|
|
23
53
|
function prepareSupervision(examples, recipe) {
|
|
24
54
|
const vocabulary = [...new Set(examples.flatMap((row) => tokenize(row.input, recipe.tokenizer).map((token) => token.key)))].sort();
|
|
@@ -91,8 +121,7 @@ async function fitSequence(examples, recipe, metadata, probes = [], progress) {
|
|
|
91
121
|
const model = artifact(result.weights);
|
|
92
122
|
const checked = [...examples.slice(0, 16).map((row) => row.input), ...probes];
|
|
93
123
|
const portable = await tensorPredictor(model);
|
|
94
|
-
|
|
95
|
-
let labelDisagreements = 0;
|
|
124
|
+
const parity = sequenceParity(model.threshold);
|
|
96
125
|
try {
|
|
97
126
|
for (const input of checked) {
|
|
98
127
|
const tokens = tokenize(input, recipe.tokenizer);
|
|
@@ -104,22 +133,22 @@ async function fitSequence(examples, recipe, metadata, probes = [], progress) {
|
|
|
104
133
|
portable.sequence(input).forEach((token, index) => {
|
|
105
134
|
const row = scores.slice(index * recipe.labels.length, (index + 1) * recipe.labels.length);
|
|
106
135
|
const confidence = Math.max(...row);
|
|
107
|
-
|
|
108
|
-
|
|
136
|
+
parity.add({
|
|
137
|
+
label: recipe.labels[row.indexOf(confidence)],
|
|
138
|
+
confidence
|
|
139
|
+
}, token);
|
|
109
140
|
});
|
|
110
141
|
}
|
|
111
142
|
} finally {
|
|
112
143
|
portable.dispose();
|
|
113
144
|
}
|
|
114
|
-
if (labelDisagreements || maxConfidenceError > 1e-5) throw new Error("Burn native and WASM predictions disagree.");
|
|
115
145
|
return {
|
|
116
146
|
model,
|
|
117
147
|
parameters: result.parameters,
|
|
118
148
|
history: result.loss,
|
|
119
149
|
parity: {
|
|
120
150
|
examples: checked.length,
|
|
121
|
-
|
|
122
|
-
labelDisagreements
|
|
151
|
+
...parity.report()
|
|
123
152
|
},
|
|
124
153
|
supervisedTokens: inputs.length
|
|
125
154
|
};
|
|
@@ -216,4 +245,4 @@ async function runSequence(command, project, progress) {
|
|
|
216
245
|
//#endregion
|
|
217
246
|
export { runSequence };
|
|
218
247
|
|
|
219
|
-
//# sourceMappingURL=sequence-
|
|
248
|
+
//# sourceMappingURL=sequence-CZLL5c0A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequence-CZLL5c0A.js","names":["evaluateSequence","evaluate"],"sources":["../src/native/fit.ts","../src/models/sequence/export-parity.ts","../src/models/sequence/prepare-supervision.ts","../src/models/sequence/fit-sequence.ts","../src/models/sequence/run-sequence.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\ninterface NativeResult {\n parameters: number;\n weights: Uint8Array;\n loss: number[];\n}\nconst require = createRequire(import.meta.url);\nexport function predict(\n config: { vocabularySize: number; labelCount: number },\n weights: Uint8Array,\n inputs: number[][],\n): number[] {\n const native = require(\"#native\") as {\n predict(config: string, weights: Buffer, inputs: Int32Array): number[];\n };\n return native.predict(\n JSON.stringify(config),\n Buffer.from(weights),\n Int32Array.from(inputs.flat()),\n );\n}\nexport function fit(\n config: { vocabularySize: number; labelCount: number },\n inputs: number[][],\n labels: number[],\n progress?: (epoch: number, loss: number) => void,\n): Promise<NativeResult> {\n const native = require(\"#native\") as {\n fit(\n config: string,\n inputs: Int32Array,\n labels: Int32Array,\n progress: (error: Error | null, value: number[]) => void,\n ): Promise<NativeResult>;\n };\n return native.fit(\n JSON.stringify(config),\n Int32Array.from(inputs.flat()),\n Int32Array.from(labels),\n (error, value) => {\n if (!error) {\n progress?.(value[0]!, value[1]!);\n }\n },\n );\n}\n","type Prediction = { label: string; confidence: number };\n\n/** Float32 probability tolerance, independent of the model's acceptance threshold. */\nconst confidenceTolerance = 1e-4;\n\nexport function sequenceParity(threshold: number) {\n let tokens = 0;\n let maxConfidenceError = 0;\n let labelDisagreements = 0;\n let acceptanceDisagreements = 0;\n return {\n add(native: Prediction, portable: Prediction) {\n if (![native.confidence, portable.confidence].every(Number.isFinite)) {\n throw new Error(\"Burn export parity received non-finite confidence.\");\n }\n tokens++;\n maxConfidenceError = Math.max(\n maxConfidenceError,\n Math.abs(native.confidence - portable.confidence),\n );\n if (native.label !== portable.label) {\n labelDisagreements++;\n }\n if (native.confidence >= threshold !== portable.confidence >= threshold) {\n acceptanceDisagreements++;\n }\n },\n report() {\n const report = {\n tokens,\n maxConfidenceError,\n confidenceTolerance,\n labelDisagreements,\n acceptanceDisagreements,\n };\n if (\n labelDisagreements ||\n acceptanceDisagreements ||\n maxConfidenceError > confidenceTolerance\n ) {\n throw new Error(`Burn native and WASM predictions disagree: ${JSON.stringify(report)}`);\n }\n return report;\n },\n };\n}\n","import { tokenize, windows } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { SequenceRecipe } from \"./types.js\";\nexport function prepareSupervision(\n examples: readonly DatasetExample<unknown>[],\n recipe: SequenceRecipe,\n) {\n const vocabulary = [\n ...new Set(\n examples.flatMap((row) => tokenize(row.input, recipe.tokenizer).map((token) => token.key)),\n ),\n ].sort();\n const radius = 1;\n const dropout = recipe.tokenDropout ?? 0;\n if (!Number.isFinite(dropout) || dropout < 0 || dropout > 0.5) {\n throw new Error(\"tokenDropout must be between 0 and 0.5.\");\n }\n let maskingSeed = 7043;\n const random = () => {\n maskingSeed = (Math.imul(maskingSeed, 1664525) + 1013904223) >>> 0;\n return maskingSeed / 4294967296;\n };\n const inputs: number[][] = [];\n const labels: number[] = [];\n for (const example of examples) {\n const tokens = tokenize(example.input, recipe.tokenizer);\n const annotations = recipe.annotate(example, tokens);\n if (annotations.length !== tokens.length) {\n throw new Error(`Annotation length mismatch: ${example.input}`);\n }\n windows(tokens, vocabulary, radius).forEach((window, position) => {\n const label = annotations[position];\n if (label === null) {\n return;\n }\n const id = recipe.labels.indexOf(label!);\n if (id < 0) {\n throw new Error(`Unknown annotation ${label}: ${example.input}`);\n }\n inputs.push(window);\n labels.push(id);\n if (dropout > 0) {\n inputs.push(window.map((id) => (id > 1 && random() < dropout ? 1 : id)));\n labels.push(id);\n }\n });\n }\n if (recipe.labels.some((_, id) => !labels.includes(id))) {\n throw new Error(\"Every label needs supervised training examples.\");\n }\n // Mix currency/template blocks deterministically before minibatch optimization.\n maskingSeed = 9187;\n for (let index = inputs.length - 1; index > 0; index--) {\n const other = Math.floor(random() * (index + 1));\n [inputs[index], inputs[other]] = [inputs[other]!, inputs[index]!];\n [labels[index], labels[other]] = [labels[other]!, labels[index]!];\n }\n return { vocabulary, radius, dropout, inputs, labels };\n}\n","import { sequenceParity } from \"./export-parity.js\";\nimport { prepareSupervision } from \"./prepare-supervision.js\";\nimport { fit, predict } from \"../../native/index.js\";\nimport { tensorPredictor, tokenize, windows } from \"@matchbox-ai/core/internal\";\nimport type { SequenceArtifact } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { SequenceRecipe } from \"./types.js\";\nexport async function fitSequence(\n examples: readonly DatasetExample<unknown>[],\n recipe: SequenceRecipe,\n metadata: Pick<SequenceArtifact, \"taskModule\" | \"taskMetadata\" | \"decoderModule\">,\n probes: readonly string[] = [],\n progress?: (epoch: number, loss: number) => void,\n) {\n const { vocabulary, radius, dropout, inputs, labels } = prepareSupervision(examples, recipe);\n const result = await fit(\n { vocabularySize: vocabulary.length + 2, labelCount: recipe.labels.length },\n inputs,\n labels,\n progress,\n );\n const artifact = (weights: Uint8Array): SequenceArtifact => ({\n formatVersion: 3,\n engine: \"burn-0.21\",\n kind: \"sequence-parser\",\n architecture: \"embedding-window-mlp\",\n ...metadata,\n tokenizer: recipe.tokenizer,\n readout: recipe.readout,\n vocabulary,\n labels: [...recipe.labels],\n radius: radius as 1,\n unknownTokens: dropout > 0 ? \"predict\" : \"abstain\",\n threshold: 0.75,\n precision: \"float32\",\n weights: Buffer.from(weights).toString(\"base64\"),\n });\n const model = artifact(result.weights);\n const checked = [...examples.slice(0, 16).map((row) => row.input), ...probes];\n const portable = await tensorPredictor(model);\n const parity = sequenceParity(model.threshold);\n try {\n for (const input of checked) {\n const tokens = tokenize(input, recipe.tokenizer);\n if (!tokens.length) {\n continue;\n }\n const scores = predict(\n { vocabularySize: vocabulary.length + 2, labelCount: recipe.labels.length },\n result.weights,\n windows(tokens, vocabulary, radius),\n );\n portable.sequence(input).forEach((token, index) => {\n const row = scores.slice(index * recipe.labels.length, (index + 1) * recipe.labels.length);\n const confidence = Math.max(...row);\n parity.add({ label: recipe.labels[row.indexOf(confidence)]!, confidence }, token);\n });\n }\n } finally {\n portable.dispose();\n }\n return {\n model,\n parameters: result.parameters,\n history: result.loss,\n parity: { examples: checked.length, ...parity.report() },\n supervisedTokens: inputs.length,\n };\n}\n","import { sameOutput } from \"../../evaluation/same-output.js\";\nimport { z } from \"zod\";\nimport { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createParser } from \"@matchbox-ai/core/runtime\";\nimport { readSequenceArtifact, tokenize } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { MatchboxParser, SequenceDecoder } from \"@matchbox-ai/core/runtime\";\nimport type { loadProject } from \"../../load-project.js\";\nimport { packageModel } from \"../../packaging/package-model.js\";\nimport { fitSequence } from \"./fit-sequence.js\";\nimport { evaluateSequence as evaluate } from \"../../evaluation/evaluate-sequence.js\";\nimport type { SequenceRecipe } from \"./types.js\";\nconst hash = (value: string) => createHash(\"sha256\").update(value).digest(\"hex\");\nexport async function runSequence(\n command: \"train\" | \"eval\",\n project: Awaited<ReturnType<typeof loadProject>>,\n progress?: (epoch: number, loss: number) => void,\n) {\n const { task, config } = project;\n const root = project.root;\n const sequence = config.sequence;\n if (!sequence) {\n throw new Error(\"A sequence pipeline needs both recipe and decoder modules.\");\n }\n const savedArtifact =\n command === \"eval\"\n ? readSequenceArtifact(JSON.parse(await readFile(project.output, \"utf8\")))\n : null;\n const decoderPath = savedArtifact\n ? resolve(dirname(project.output), savedArtifact.decoderModule)\n : resolve(root, sequence.decoder);\n const decode: SequenceDecoder = (await import(pathToFileURL(decoderPath).href)).default;\n const evaluateSequence = (\n parser: MatchboxParser<unknown>,\n examples: readonly DatasetExample<unknown>[],\n ) =>\n evaluate(parser, examples, (value) => task.validateOutput(value).success).finally(() => {\n if (\"dispose\" in parser && typeof parser.dispose === \"function\") {\n parser.dispose();\n }\n });\n const parser = (artifact: unknown) => createParser(artifact, task, decode);\n if (savedArtifact) {\n return { evaluation: await evaluateSequence(parser(savedArtifact), project.evaluation) };\n }\n const recipe: SequenceRecipe = (await import(pathToFileURL(resolve(root, sequence.recipe)).href))\n .default;\n const modulePath = (path: string) => {\n const value = relative(dirname(project.output), path).replaceAll(\"\\\\\", \"/\");\n return value.startsWith(\".\") ? value : `./${value}`;\n };\n const rejections = z\n .array(z.strictObject({ input: z.string(), output: z.null() }))\n .parse(recipe.rejections ?? []);\n const training = [...project.train, ...rejections];\n const heldOut = new Set(\n [...project.validation, ...project.evaluation].map((row) => row.input.trim().toLowerCase()),\n );\n for (const example of training) {\n if (!task.validateInput(example.input).success) {\n throw new Error(`Invalid training input: ${example.input}`);\n }\n if (heldOut.has(example.input.trim().toLowerCase())) {\n throw new Error(`Training input overlaps evaluation: ${example.input}`);\n }\n const tokens = tokenize(example.input, recipe.tokenizer);\n const labels = recipe.annotate(example, tokens);\n const value = decode(\n tokens.map((token, index) => ({ ...token, label: labels[index] ?? \"O\", confidence: 1 })),\n example.input,\n );\n if (!sameOutput(value, example.output)) {\n throw new Error(\n `Training annotations do not decode to the supplied output: ${example.input}`,\n );\n }\n }\n const started = performance.now();\n const fit = await fitSequence(\n training,\n recipe,\n {\n taskMetadata: task.toJSON(),\n taskModule: modulePath(project.taskPath),\n decoderModule: modulePath(resolve(root, sequence.decoder)),\n },\n project.validation.map((row) => row.input),\n progress,\n );\n const validation = await evaluateSequence(parser(fit.model), project.validation);\n const bytes = Buffer.byteLength(JSON.stringify(fit.model));\n if (validation.exactAccuracy < config.minAccuracy || bytes > config.maxBytes) {\n throw new Error(\n `Sequence model failed validation/size requirements (${validation.exactAccuracy}, ${bytes} bytes). ${JSON.stringify(validation.failures.slice(0, 10))}`,\n );\n }\n const challenges = config.challenges\n ? z\n .array(z.strictObject({ input: z.string(), output: z.null() }))\n .min(1)\n .parse(JSON.parse(await readFile(resolve(root, config.challenges), \"utf8\")))\n : null;\n const report = {\n formatVersion: 2,\n architecture: fit.model.architecture,\n backend: \"Burn native CPU\",\n seed: 42,\n artifactSha256: hash(JSON.stringify(fit.model)),\n bytes,\n parameters: fit.parameters,\n datasetSha256: project.sources.map((source) => ({\n source: source.source,\n sha256: hash(source.text),\n })),\n examples: {\n train: project.train.length,\n rejections: recipe.rejections?.length ?? 0,\n validation: project.validation.length,\n eval: project.evaluation.length,\n },\n supervisionSha256: hash(\n JSON.stringify(\n training.map((row) => ({\n ...row,\n labels: recipe.annotate(row, tokenize(row.input, recipe.tokenizer)),\n })),\n ),\n ),\n supervisedTokens: fit.supervisedTokens,\n loss: fit.history,\n exportParity: fit.parity,\n validation,\n evaluation: await evaluateSequence(parser(fit.model), project.evaluation),\n challenges: challenges ? await evaluateSequence(parser(fit.model), challenges) : null,\n trainingMs: performance.now() - started,\n notes:\n \"Float32 weights in a Burn binary record, base64-encoded in the artifact. Validation gates export. Eval labels do not influence selection. Scores are uncalibrated.\",\n };\n await packageModel(project.output, fit.model, report);\n return { report, output: project.output };\n}\n"],"mappings":"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"}
|
package/dist/train.d.ts
CHANGED
|
@@ -42,9 +42,12 @@ export declare function train(target: string, options?: {
|
|
|
42
42
|
supervisedTokens: number;
|
|
43
43
|
loss: number[];
|
|
44
44
|
exportParity: {
|
|
45
|
-
|
|
45
|
+
tokens: number;
|
|
46
46
|
maxConfidenceError: number;
|
|
47
|
+
confidenceTolerance: number;
|
|
47
48
|
labelDisagreements: number;
|
|
49
|
+
acceptanceDisagreements: number;
|
|
50
|
+
examples: number;
|
|
48
51
|
};
|
|
49
52
|
validation: {
|
|
50
53
|
examples: number;
|
package/dist/train.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../src/train.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wBAAsB,KAAK,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO
|
|
1
|
+
{"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../src/train.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wBAAsB,KAAK,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKrE"}
|
package/docs/contributing.md
CHANGED
|
@@ -41,3 +41,17 @@ bun run eval:examples
|
|
|
41
41
|
Generated native binaries, WASM output, Cargo build output and model artifacts are ignored by Git. `Cargo.lock` pins Rust dependencies. `bun run check` includes Rust formatting, Clippy and engine tests.
|
|
42
42
|
|
|
43
43
|
See [native package distribution](native-packages.md) for platform coverage and release verification.
|
|
44
|
+
|
|
45
|
+
## Diagnose sequence exports
|
|
46
|
+
|
|
47
|
+
To inspect native/WASM prediction differences with an installed consumer's binaries, run:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
bun scripts/diagnose-sequence-export.ts \
|
|
51
|
+
/path/to/application \
|
|
52
|
+
/path/to/application/matchbox/task \
|
|
53
|
+
/path/to/dataset \
|
|
54
|
+
.matchbox/export-diagnostic
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The dataset directory must contain `train.jsonl` and `validation.jsonl`. An optional final integer limits training records. The runner refuses an existing output directory and saves weights and fit metadata before comparing predictions. Reports include checked tokens, differing labels and confidence drift without source text. This contributor tool uses framework internals; it does not package an application model. Generated files stay ignored.
|
|
@@ -24,3 +24,5 @@ Report format 2 contains `architecture`, `backend`, `seed`, `bytes`, `parameters
|
|
|
24
24
|
`TrainingConfig` is the optional task configuration type. See [every field and default](configuration.md).
|
|
25
25
|
|
|
26
26
|
Use [evaluate](evaluation.md) to score an existing parser without training it.
|
|
27
|
+
|
|
28
|
+
For sequence models, `exportParity` records the checked token count, maximum absolute confidence difference, a `0.0001` numerical tolerance, label disagreements and acceptance disagreements. Export fails on any label disagreement, any crossing of the model acceptance threshold, or confidence drift above that tolerance. This tolerance does not lower model confidence requirements.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matchbox-ai/train",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"zod": "4.6.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@matchbox-ai/core": "0.2.
|
|
50
|
+
"@matchbox-ai/core": "0.2.2",
|
|
51
51
|
"@types/node": "22.20.2",
|
|
52
52
|
"rolldown": "1.2.8",
|
|
53
53
|
"typescript": "7.0.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@matchbox-ai/core": "0.2.
|
|
56
|
+
"@matchbox-ai/core": "0.2.2"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"bun": ">=1.4.2",
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sequence-DGoGU7kG.js","names":["evaluateSequence","evaluate"],"sources":["../src/native/fit.ts","../src/models/sequence/prepare-supervision.ts","../src/models/sequence/fit-sequence.ts","../src/models/sequence/run-sequence.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\ninterface NativeResult {\n parameters: number;\n weights: Uint8Array;\n loss: number[];\n}\nconst require = createRequire(import.meta.url);\nexport function predict(\n config: { vocabularySize: number; labelCount: number },\n weights: Uint8Array,\n inputs: number[][],\n): number[] {\n const native = require(\"#native\") as {\n predict(config: string, weights: Buffer, inputs: Int32Array): number[];\n };\n return native.predict(\n JSON.stringify(config),\n Buffer.from(weights),\n Int32Array.from(inputs.flat()),\n );\n}\nexport function fit(\n config: { vocabularySize: number; labelCount: number },\n inputs: number[][],\n labels: number[],\n progress?: (epoch: number, loss: number) => void,\n): Promise<NativeResult> {\n const native = require(\"#native\") as {\n fit(\n config: string,\n inputs: Int32Array,\n labels: Int32Array,\n progress: (error: Error | null, value: number[]) => void,\n ): Promise<NativeResult>;\n };\n return native.fit(\n JSON.stringify(config),\n Int32Array.from(inputs.flat()),\n Int32Array.from(labels),\n (error, value) => {\n if (!error) {\n progress?.(value[0]!, value[1]!);\n }\n },\n );\n}\n","import { tokenize, windows } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { SequenceRecipe } from \"./types.js\";\nexport function prepareSupervision(\n examples: readonly DatasetExample<unknown>[],\n recipe: SequenceRecipe,\n) {\n const vocabulary = [\n ...new Set(\n examples.flatMap((row) => tokenize(row.input, recipe.tokenizer).map((token) => token.key)),\n ),\n ].sort();\n const radius = 1;\n const dropout = recipe.tokenDropout ?? 0;\n if (!Number.isFinite(dropout) || dropout < 0 || dropout > 0.5) {\n throw new Error(\"tokenDropout must be between 0 and 0.5.\");\n }\n let maskingSeed = 7043;\n const random = () => {\n maskingSeed = (Math.imul(maskingSeed, 1664525) + 1013904223) >>> 0;\n return maskingSeed / 4294967296;\n };\n const inputs: number[][] = [];\n const labels: number[] = [];\n for (const example of examples) {\n const tokens = tokenize(example.input, recipe.tokenizer);\n const annotations = recipe.annotate(example, tokens);\n if (annotations.length !== tokens.length) {\n throw new Error(`Annotation length mismatch: ${example.input}`);\n }\n windows(tokens, vocabulary, radius).forEach((window, position) => {\n const label = annotations[position];\n if (label === null) {\n return;\n }\n const id = recipe.labels.indexOf(label!);\n if (id < 0) {\n throw new Error(`Unknown annotation ${label}: ${example.input}`);\n }\n inputs.push(window);\n labels.push(id);\n if (dropout > 0) {\n inputs.push(window.map((id) => (id > 1 && random() < dropout ? 1 : id)));\n labels.push(id);\n }\n });\n }\n if (recipe.labels.some((_, id) => !labels.includes(id))) {\n throw new Error(\"Every label needs supervised training examples.\");\n }\n // Mix currency/template blocks deterministically before minibatch optimization.\n maskingSeed = 9187;\n for (let index = inputs.length - 1; index > 0; index--) {\n const other = Math.floor(random() * (index + 1));\n [inputs[index], inputs[other]] = [inputs[other]!, inputs[index]!];\n [labels[index], labels[other]] = [labels[other]!, labels[index]!];\n }\n return { vocabulary, radius, dropout, inputs, labels };\n}\n","import { prepareSupervision } from \"./prepare-supervision.js\";\nimport { fit, predict } from \"../../native/index.js\";\nimport { tensorPredictor, tokenize, windows } from \"@matchbox-ai/core/internal\";\nimport type { SequenceArtifact } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { SequenceRecipe } from \"./types.js\";\nexport async function fitSequence(\n examples: readonly DatasetExample<unknown>[],\n recipe: SequenceRecipe,\n metadata: Pick<SequenceArtifact, \"taskModule\" | \"taskMetadata\" | \"decoderModule\">,\n probes: readonly string[] = [],\n progress?: (epoch: number, loss: number) => void,\n) {\n const { vocabulary, radius, dropout, inputs, labels } = prepareSupervision(examples, recipe);\n const result = await fit(\n { vocabularySize: vocabulary.length + 2, labelCount: recipe.labels.length },\n inputs,\n labels,\n progress,\n );\n const artifact = (weights: Uint8Array): SequenceArtifact => ({\n formatVersion: 3,\n engine: \"burn-0.21\",\n kind: \"sequence-parser\",\n architecture: \"embedding-window-mlp\",\n ...metadata,\n tokenizer: recipe.tokenizer,\n readout: recipe.readout,\n vocabulary,\n labels: [...recipe.labels],\n radius: radius as 1,\n unknownTokens: dropout > 0 ? \"predict\" : \"abstain\",\n threshold: 0.75,\n precision: \"float32\",\n weights: Buffer.from(weights).toString(\"base64\"),\n });\n const model = artifact(result.weights);\n const checked = [...examples.slice(0, 16).map((row) => row.input), ...probes];\n const portable = await tensorPredictor(model);\n let maxConfidenceError = 0;\n let labelDisagreements = 0;\n try {\n for (const input of checked) {\n const tokens = tokenize(input, recipe.tokenizer);\n if (!tokens.length) {\n continue;\n }\n const scores = predict(\n { vocabularySize: vocabulary.length + 2, labelCount: recipe.labels.length },\n result.weights,\n windows(tokens, vocabulary, radius),\n );\n portable.sequence(input).forEach((token, index) => {\n const row = scores.slice(index * recipe.labels.length, (index + 1) * recipe.labels.length);\n const confidence = Math.max(...row);\n maxConfidenceError = Math.max(maxConfidenceError, Math.abs(confidence - token.confidence));\n if (recipe.labels[row.indexOf(confidence)] !== token.label) {\n labelDisagreements++;\n }\n });\n }\n } finally {\n portable.dispose();\n }\n if (labelDisagreements || maxConfidenceError > 1e-5) {\n throw new Error(\"Burn native and WASM predictions disagree.\");\n }\n return {\n model,\n parameters: result.parameters,\n history: result.loss,\n parity: { examples: checked.length, maxConfidenceError, labelDisagreements },\n supervisedTokens: inputs.length,\n };\n}\n","import { sameOutput } from \"../../evaluation/same-output.js\";\nimport { z } from \"zod\";\nimport { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createParser } from \"@matchbox-ai/core/runtime\";\nimport { readSequenceArtifact, tokenize } from \"@matchbox-ai/core/internal\";\nimport type { DatasetExample } from \"@matchbox-ai/core\";\nimport type { MatchboxParser, SequenceDecoder } from \"@matchbox-ai/core/runtime\";\nimport type { loadProject } from \"../../load-project.js\";\nimport { packageModel } from \"../../packaging/package-model.js\";\nimport { fitSequence } from \"./fit-sequence.js\";\nimport { evaluateSequence as evaluate } from \"../../evaluation/evaluate-sequence.js\";\nimport type { SequenceRecipe } from \"./types.js\";\nconst hash = (value: string) => createHash(\"sha256\").update(value).digest(\"hex\");\nexport async function runSequence(\n command: \"train\" | \"eval\",\n project: Awaited<ReturnType<typeof loadProject>>,\n progress?: (epoch: number, loss: number) => void,\n) {\n const { task, config } = project;\n const root = project.root;\n const sequence = config.sequence;\n if (!sequence) {\n throw new Error(\"A sequence pipeline needs both recipe and decoder modules.\");\n }\n const savedArtifact =\n command === \"eval\"\n ? readSequenceArtifact(JSON.parse(await readFile(project.output, \"utf8\")))\n : null;\n const decoderPath = savedArtifact\n ? resolve(dirname(project.output), savedArtifact.decoderModule)\n : resolve(root, sequence.decoder);\n const decode: SequenceDecoder = (await import(pathToFileURL(decoderPath).href)).default;\n const evaluateSequence = (\n parser: MatchboxParser<unknown>,\n examples: readonly DatasetExample<unknown>[],\n ) =>\n evaluate(parser, examples, (value) => task.validateOutput(value).success).finally(() => {\n if (\"dispose\" in parser && typeof parser.dispose === \"function\") {\n parser.dispose();\n }\n });\n const parser = (artifact: unknown) => createParser(artifact, task, decode);\n if (savedArtifact) {\n return { evaluation: await evaluateSequence(parser(savedArtifact), project.evaluation) };\n }\n const recipe: SequenceRecipe = (await import(pathToFileURL(resolve(root, sequence.recipe)).href))\n .default;\n const modulePath = (path: string) => {\n const value = relative(dirname(project.output), path).replaceAll(\"\\\\\", \"/\");\n return value.startsWith(\".\") ? value : `./${value}`;\n };\n const rejections = z\n .array(z.strictObject({ input: z.string(), output: z.null() }))\n .parse(recipe.rejections ?? []);\n const training = [...project.train, ...rejections];\n const heldOut = new Set(\n [...project.validation, ...project.evaluation].map((row) => row.input.trim().toLowerCase()),\n );\n for (const example of training) {\n if (!task.validateInput(example.input).success) {\n throw new Error(`Invalid training input: ${example.input}`);\n }\n if (heldOut.has(example.input.trim().toLowerCase())) {\n throw new Error(`Training input overlaps evaluation: ${example.input}`);\n }\n const tokens = tokenize(example.input, recipe.tokenizer);\n const labels = recipe.annotate(example, tokens);\n const value = decode(\n tokens.map((token, index) => ({ ...token, label: labels[index] ?? \"O\", confidence: 1 })),\n example.input,\n );\n if (!sameOutput(value, example.output)) {\n throw new Error(\n `Training annotations do not decode to the supplied output: ${example.input}`,\n );\n }\n }\n const started = performance.now();\n const fit = await fitSequence(\n training,\n recipe,\n {\n taskMetadata: task.toJSON(),\n taskModule: modulePath(project.taskPath),\n decoderModule: modulePath(resolve(root, sequence.decoder)),\n },\n project.validation.map((row) => row.input),\n progress,\n );\n const validation = await evaluateSequence(parser(fit.model), project.validation);\n const bytes = Buffer.byteLength(JSON.stringify(fit.model));\n if (validation.exactAccuracy < config.minAccuracy || bytes > config.maxBytes) {\n throw new Error(\n `Sequence model failed validation/size requirements (${validation.exactAccuracy}, ${bytes} bytes). ${JSON.stringify(validation.failures.slice(0, 10))}`,\n );\n }\n const challenges = config.challenges\n ? z\n .array(z.strictObject({ input: z.string(), output: z.null() }))\n .min(1)\n .parse(JSON.parse(await readFile(resolve(root, config.challenges), \"utf8\")))\n : null;\n const report = {\n formatVersion: 2,\n architecture: fit.model.architecture,\n backend: \"Burn native CPU\",\n seed: 42,\n artifactSha256: hash(JSON.stringify(fit.model)),\n bytes,\n parameters: fit.parameters,\n datasetSha256: project.sources.map((source) => ({\n source: source.source,\n sha256: hash(source.text),\n })),\n examples: {\n train: project.train.length,\n rejections: recipe.rejections?.length ?? 0,\n validation: project.validation.length,\n eval: project.evaluation.length,\n },\n supervisionSha256: hash(\n JSON.stringify(\n training.map((row) => ({\n ...row,\n labels: recipe.annotate(row, tokenize(row.input, recipe.tokenizer)),\n })),\n ),\n ),\n supervisedTokens: fit.supervisedTokens,\n loss: fit.history,\n exportParity: fit.parity,\n validation,\n evaluation: await evaluateSequence(parser(fit.model), project.evaluation),\n challenges: challenges ? await evaluateSequence(parser(fit.model), challenges) : null,\n trainingMs: performance.now() - started,\n notes:\n \"Float32 weights in a Burn binary record, base64-encoded in the artifact. Validation gates export. Eval labels do not influence selection. Scores are uncalibrated.\",\n };\n await packageModel(project.output, fit.model, report);\n return { report, output: project.output };\n}\n"],"mappings":"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"}
|