@simulatte/doppler 0.1.5 → 0.1.6
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 +23 -8
- package/package.json +7 -4
- package/src/config/kernels/kernel-ref-digests.js +39 -39
- package/src/config/kernels/registry.json +42 -2
- package/src/config/loader.js +31 -2
- package/src/config/merge.js +18 -0
- package/src/config/presets/models/qwen3.json +9 -2
- package/src/config/presets/models/transformer.json +5 -0
- package/src/config/required-inference-fields-contract-check.js +6 -0
- package/src/config/schema/inference-defaults.schema.js +3 -0
- package/src/config/schema/inference.schema.d.ts +9 -0
- package/src/config/schema/kernel-path.schema.d.ts +6 -0
- package/src/config/schema/manifest.schema.d.ts +6 -0
- package/src/config/schema/manifest.schema.js +3 -0
- package/src/converter/rope-config.js +42 -0
- package/src/gpu/device.js +58 -0
- package/src/gpu/kernels/attention.js +98 -0
- package/src/gpu/kernels/bias_add.wgsl +8 -6
- package/src/gpu/kernels/bias_add_f16.wgsl +8 -5
- package/src/gpu/kernels/conv2d.js +1 -1
- package/src/gpu/kernels/conv2d.wgsl +7 -8
- package/src/gpu/kernels/conv2d_f16.wgsl +7 -8
- package/src/gpu/kernels/depthwise_conv2d.js +2 -1
- package/src/gpu/kernels/depthwise_conv2d.wgsl +6 -9
- package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +6 -9
- package/src/gpu/kernels/grouped_pointwise_conv2d.js +2 -1
- package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +6 -9
- package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +6 -9
- package/src/gpu/kernels/matmul.js +25 -0
- package/src/gpu/kernels/pixel_shuffle.js +1 -1
- package/src/gpu/kernels/pixel_shuffle.wgsl +4 -5
- package/src/gpu/kernels/pixel_shuffle_f16.wgsl +4 -5
- package/src/gpu/kernels/relu.js +15 -2
- package/src/gpu/kernels/relu.wgsl +2 -1
- package/src/gpu/kernels/relu_f16.wgsl +2 -1
- package/src/gpu/kernels/repeat_channels.js +1 -1
- package/src/gpu/kernels/repeat_channels.wgsl +4 -5
- package/src/gpu/kernels/repeat_channels_f16.wgsl +4 -5
- package/src/gpu/kernels/residual.js +44 -8
- package/src/gpu/kernels/residual.wgsl +6 -3
- package/src/gpu/kernels/residual_f16.wgsl +2 -1
- package/src/gpu/kernels/residual_f16_vec4.wgsl +2 -1
- package/src/gpu/kernels/residual_vec4.wgsl +2 -1
- package/src/gpu/kernels/rmsnorm.js +58 -6
- package/src/gpu/kernels/rmsnorm.wgsl +14 -6
- package/src/gpu/kernels/rmsnorm_f16.wgsl +10 -2
- package/src/gpu/kernels/rope.d.ts +2 -0
- package/src/gpu/kernels/rope.js +11 -1
- package/src/gpu/kernels/rope.wgsl +56 -40
- package/src/gpu/kernels/sana_linear_attention.js +1 -2
- package/src/gpu/kernels/sana_linear_attention_apply.wgsl +4 -5
- package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +4 -5
- package/src/gpu/kernels/sana_linear_attention_summary.wgsl +4 -0
- package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +4 -0
- package/src/gpu/kernels/silu.d.ts +1 -0
- package/src/gpu/kernels/silu.js +32 -14
- package/src/gpu/kernels/silu.wgsl +19 -9
- package/src/gpu/kernels/silu_f16.wgsl +19 -9
- package/src/gpu/kernels/transpose.js +15 -2
- package/src/gpu/kernels/transpose.wgsl +5 -6
- package/src/gpu/kernels/upsample2d.js +2 -1
- package/src/gpu/kernels/upsample2d.wgsl +6 -9
- package/src/gpu/kernels/upsample2d_f16.wgsl +6 -9
- package/src/gpu/kernels/utils.js +16 -1
- package/src/inference/browser-harness.js +47 -1
- package/src/inference/pipelines/diffusion/pipeline.js +15 -6
- package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +5 -0
- package/src/inference/pipelines/diffusion/text-encoder-gpu.js +27 -15
- package/src/inference/pipelines/text/attention/record.js +11 -2
- package/src/inference/pipelines/text/attention/run.js +11 -2
- package/src/inference/pipelines/text/chat-format.js +25 -1
- package/src/inference/pipelines/text/config.d.ts +4 -0
- package/src/inference/pipelines/text/config.js +68 -1
- package/src/inference/pipelines/text/execution-plan.js +23 -31
- package/src/inference/pipelines/text/execution-v0.js +29 -2
- package/src/inference/pipelines/text/ffn/standard.js +3 -0
- package/src/inference/pipelines/text/init.d.ts +4 -0
- package/src/inference/pipelines/text/init.js +56 -9
- package/src/inference/pipelines/text/layer.js +11 -0
- package/src/inference/pipelines/text.js +4 -0
- package/src/inference/tokenizers/bundled.js +156 -33
- package/src/rules/tooling/command-runtime.rules.json +18 -0
- package/src/tooling/command-api.d.ts +27 -1
- package/src/tooling/command-api.js +142 -3
- package/src/tooling/node-browser-command-runner.d.ts +4 -0
- package/src/tooling/node-browser-command-runner.js +58 -3
- package/src/tooling/node-command-runner.js +15 -0
- package/src/tooling/node-webgpu.js +9 -87
- package/src/training/checkpoint-watch.d.ts +7 -0
- package/src/training/checkpoint-watch.js +106 -0
- package/src/training/checkpoint.d.ts +6 -1
- package/src/training/checkpoint.js +12 -2
- package/src/training/distillation/artifacts.d.ts +71 -0
- package/src/training/distillation/artifacts.js +132 -0
- package/src/training/distillation/checkpoint-watch.d.ts +10 -0
- package/src/training/distillation/checkpoint-watch.js +57 -0
- package/src/training/distillation/dataset.d.ts +59 -0
- package/src/training/distillation/dataset.js +337 -0
- package/src/training/distillation/eval.d.ts +34 -0
- package/src/training/distillation/eval.js +310 -0
- package/src/training/distillation/index.d.ts +29 -0
- package/src/training/distillation/index.js +29 -0
- package/src/training/distillation/runtime.d.ts +20 -0
- package/src/training/distillation/runtime.js +121 -0
- package/src/training/distillation/scoreboard.d.ts +6 -0
- package/src/training/distillation/scoreboard.js +8 -0
- package/src/training/distillation/stage-a.d.ts +45 -0
- package/src/training/distillation/stage-a.js +338 -0
- package/src/training/distillation/stage-b.d.ts +24 -0
- package/src/training/distillation/stage-b.js +20 -0
- package/src/training/index.d.ts +10 -0
- package/src/training/index.js +10 -0
- package/src/training/lora-pipeline.d.ts +40 -0
- package/src/training/lora-pipeline.js +796 -0
- package/src/training/operator-artifacts.d.ts +62 -0
- package/src/training/operator-artifacts.js +140 -0
- package/src/training/operator-command.d.ts +5 -0
- package/src/training/operator-command.js +453 -0
- package/src/training/operator-eval.d.ts +48 -0
- package/src/training/operator-eval.js +230 -0
- package/src/training/operator-scoreboard.d.ts +5 -0
- package/src/training/operator-scoreboard.js +44 -0
- package/src/training/runner.d.ts +52 -0
- package/src/training/runner.js +29 -4
- package/src/training/suite.d.ts +112 -0
- package/src/training/suite.js +9 -9
- package/src/training/workloads.d.ts +164 -0
- package/src/training/workloads.js +539 -0
- package/src/version.js +1 -1
- package/tools/doppler-cli.js +137 -40
package/tools/doppler-cli.js
CHANGED
|
@@ -66,6 +66,8 @@ function usage() {
|
|
|
66
66
|
' doppler debug --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
67
67
|
' doppler bench --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
68
68
|
' doppler verify --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
69
|
+
' doppler lora --config <path.json|json> [--surface auto|node]',
|
|
70
|
+
' doppler distill --config <path.json|json> [--surface auto|node]',
|
|
69
71
|
'',
|
|
70
72
|
'Flags:',
|
|
71
73
|
' --config <path|json> Required command config payload (file path or JSON object string).',
|
|
@@ -337,7 +339,89 @@ function resolveStaticRootDir(browserOptions = {}) {
|
|
|
337
339
|
return process.cwd();
|
|
338
340
|
}
|
|
339
341
|
|
|
340
|
-
|
|
342
|
+
function resolveRdrrRoot(options = {}) {
|
|
343
|
+
return path.resolve(asStringOrNull(options.rdrrRoot) || DEFAULT_EXTERNAL_RDRR_ROOT);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function findResolvableModelCandidate(candidates) {
|
|
347
|
+
const discoveredManifestCandidates = [];
|
|
348
|
+
|
|
349
|
+
for (const candidate of candidates) {
|
|
350
|
+
if (!await pathExists(candidate.manifestPath)) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
discoveredManifestCandidates.push(candidate);
|
|
354
|
+
|
|
355
|
+
const modelDir = path.dirname(candidate.manifestPath);
|
|
356
|
+
try {
|
|
357
|
+
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
358
|
+
const hasShards = files.some((entry) =>
|
|
359
|
+
entry.isFile() && /^shard_\d+\.bin$/u.test(entry.name)
|
|
360
|
+
);
|
|
361
|
+
if (hasShards) {
|
|
362
|
+
return { candidate, discoveredManifestCandidates };
|
|
363
|
+
}
|
|
364
|
+
} catch {
|
|
365
|
+
return { candidate, discoveredManifestCandidates };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return { candidate: null, discoveredManifestCandidates };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function resolveExternalModelDirectory(rdrrRoot, modelId) {
|
|
373
|
+
const directModelDir = path.join(rdrrRoot, modelId);
|
|
374
|
+
const directManifestPath = path.join(directModelDir, 'manifest.json');
|
|
375
|
+
if (await pathExists(directManifestPath)) {
|
|
376
|
+
return {
|
|
377
|
+
modelDir: directModelDir,
|
|
378
|
+
manifestPath: directManifestPath,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let entries = [];
|
|
383
|
+
try {
|
|
384
|
+
entries = await fs.readdir(rdrrRoot, { withFileTypes: true });
|
|
385
|
+
} catch {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const matches = [];
|
|
390
|
+
for (const entry of entries) {
|
|
391
|
+
if (!entry.isDirectory()) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const manifestPath = path.join(rdrrRoot, entry.name, 'manifest.json');
|
|
395
|
+
if (!await pathExists(manifestPath)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
let manifest = null;
|
|
399
|
+
try {
|
|
400
|
+
manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
|
|
401
|
+
} catch {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (manifest?.modelId !== modelId) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
matches.push({
|
|
408
|
+
modelDir: path.join(rdrrRoot, entry.name),
|
|
409
|
+
manifestPath,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (matches.length > 1) {
|
|
414
|
+
const matchPaths = matches.map((match) => match.modelDir).join(', ');
|
|
415
|
+
throw new Error(
|
|
416
|
+
`Model "${modelId}" matched multiple external directories. ` +
|
|
417
|
+
`Disambiguate by setting request.modelUrl in --config. Matches: ${matchPaths}`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return matches[0] || null;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export async function resolveBrowserModelUrl(request, browserOptions = {}) {
|
|
341
425
|
if (request.modelUrl || !request.modelId) {
|
|
342
426
|
return request;
|
|
343
427
|
}
|
|
@@ -353,49 +437,32 @@ async function resolveBrowserModelUrl(request, browserOptions = {}) {
|
|
|
353
437
|
}
|
|
354
438
|
|
|
355
439
|
const staticRootDir = resolveStaticRootDir(browserOptions);
|
|
356
|
-
const
|
|
440
|
+
const externalModel = await resolveExternalModelDirectory(resolveRdrrRoot(browserOptions), modelId);
|
|
441
|
+
const candidates = [
|
|
442
|
+
{
|
|
357
443
|
modelUrl: `/models/curated/${encodedModelId}`,
|
|
358
444
|
manifestPath: path.join(staticRootDir, 'models', 'curated', modelId, 'manifest.json'),
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
},
|
|
446
|
+
{
|
|
361
447
|
modelUrl: `/models/local/${encodedModelId}`,
|
|
362
448
|
manifestPath: path.join(staticRootDir, 'models', 'local', modelId, 'manifest.json'),
|
|
363
|
-
|
|
364
|
-
|
|
449
|
+
},
|
|
450
|
+
{
|
|
365
451
|
modelUrl: `/models/${encodedModelId}`,
|
|
366
452
|
manifestPath: path.join(staticRootDir, 'models', modelId, 'manifest.json'),
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
modelUrl: `/models/external/${encodeURIComponent(path.basename(externalModel?.modelDir || modelId))}`,
|
|
456
|
+
manifestPath: externalModel?.manifestPath || path.join(resolveRdrrRoot(browserOptions), modelId, 'manifest.json'),
|
|
457
|
+
},
|
|
372
458
|
];
|
|
373
|
-
const discoveredManifestCandidates = [];
|
|
374
459
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const modelDir = path.dirname(candidate.manifestPath);
|
|
382
|
-
try {
|
|
383
|
-
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
384
|
-
const hasShards = files.some((entry) =>
|
|
385
|
-
entry.isFile() && /^shard_\d+\.bin$/u.test(entry.name)
|
|
386
|
-
);
|
|
387
|
-
if (hasShards) {
|
|
388
|
-
return {
|
|
389
|
-
...request,
|
|
390
|
-
modelUrl: candidate.modelUrl,
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
} catch {
|
|
394
|
-
return {
|
|
395
|
-
...request,
|
|
396
|
-
modelUrl: candidate.modelUrl,
|
|
397
|
-
};
|
|
398
|
-
}
|
|
460
|
+
const { candidate, discoveredManifestCandidates } = await findResolvableModelCandidate(candidates);
|
|
461
|
+
if (candidate) {
|
|
462
|
+
return {
|
|
463
|
+
...request,
|
|
464
|
+
modelUrl: candidate.modelUrl,
|
|
465
|
+
};
|
|
399
466
|
}
|
|
400
467
|
|
|
401
468
|
if (discoveredManifestCandidates.length > 0) {
|
|
@@ -421,13 +488,13 @@ export async function resolveNodeModelUrl(request, options = {}) {
|
|
|
421
488
|
}
|
|
422
489
|
|
|
423
490
|
const modelId = String(request.modelId);
|
|
424
|
-
const rdrrRoot =
|
|
425
|
-
const
|
|
426
|
-
if (!
|
|
491
|
+
const rdrrRoot = resolveRdrrRoot(options);
|
|
492
|
+
const externalModel = await resolveExternalModelDirectory(rdrrRoot, modelId);
|
|
493
|
+
if (!externalModel) {
|
|
427
494
|
return request;
|
|
428
495
|
}
|
|
429
496
|
|
|
430
|
-
const modelDir =
|
|
497
|
+
const modelDir = externalModel.modelDir;
|
|
431
498
|
try {
|
|
432
499
|
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
433
500
|
const hasShards = files.some((entry) =>
|
|
@@ -593,10 +660,18 @@ function buildBrowserRunOptions(runConfig, jsonOutput, request = {}) {
|
|
|
593
660
|
executablePath: asStringOrNull(browser.executablePath),
|
|
594
661
|
runnerPath: asStringOrNull(browser.runnerPath),
|
|
595
662
|
staticRootDir: asStringOrNull(browser.staticRootDir),
|
|
663
|
+
rdrrRoot: asStringOrNull(browser.rdrrRoot),
|
|
596
664
|
baseUrl: asStringOrNull(browser.baseUrl),
|
|
597
665
|
browserArgs: parseBrowserArgs(browser.browserArgs),
|
|
598
666
|
headless: headed ? false : (explicitHeadless ?? true),
|
|
599
667
|
};
|
|
668
|
+
const rdrrRoot = resolveRdrrRoot(options);
|
|
669
|
+
options.staticMounts = [
|
|
670
|
+
{
|
|
671
|
+
urlPrefix: '/models/external',
|
|
672
|
+
rootDir: rdrrRoot,
|
|
673
|
+
},
|
|
674
|
+
];
|
|
600
675
|
|
|
601
676
|
const port = parseNumberFlag(browser.port, 'run.browser.port');
|
|
602
677
|
if (port !== null) {
|
|
@@ -644,6 +719,7 @@ function isNodeWebGPUFallbackCandidate(error, fallbackPolicy = DEFAULT_CLI_POLIC
|
|
|
644
719
|
function isTrainingCommandFlow(request) {
|
|
645
720
|
if (!request || typeof request !== 'object') return false;
|
|
646
721
|
if (request.suite === 'training') return true;
|
|
722
|
+
if (request.command === 'lora' || request.command === 'distill') return true;
|
|
647
723
|
return request.command === 'bench' && request.workloadType === 'training';
|
|
648
724
|
}
|
|
649
725
|
|
|
@@ -726,6 +802,13 @@ function toSummary(result) {
|
|
|
726
802
|
return `converted ${result.manifest.modelId} (${result.tensorCount} tensors, ${result.shardCount} shards)${contractStatus}${graphStatus}`;
|
|
727
803
|
}
|
|
728
804
|
|
|
805
|
+
if (result.kind === 'lora' || result.kind === 'distill') {
|
|
806
|
+
const workloadId = result.workloadId || 'unknown';
|
|
807
|
+
const action = result.action || 'run';
|
|
808
|
+
const runRoot = result.runRoot || 'n/a';
|
|
809
|
+
return `${result.kind} ${action} workload=${workloadId} runRoot=${runRoot}`;
|
|
810
|
+
}
|
|
811
|
+
|
|
729
812
|
const suite = result.suite || result.report?.suite || 'suite';
|
|
730
813
|
const modelId = result.modelId || result.report?.modelId || 'unknown';
|
|
731
814
|
const passed = Number.isFinite(result.passed) ? result.passed : null;
|
|
@@ -1122,6 +1205,20 @@ function printConvertReportSummary(result) {
|
|
|
1122
1205
|
|
|
1123
1206
|
function printMetricsSummary(result) {
|
|
1124
1207
|
if (!result || typeof result !== 'object') return;
|
|
1208
|
+
if (result.kind === 'distill') {
|
|
1209
|
+
const stageCount = Array.isArray(result.stageResults) ? result.stageResults.length : 0;
|
|
1210
|
+
console.log(
|
|
1211
|
+
`[metrics] kind=distill action=${result.action || 'run'} stages=${stageCount} runRoot=${quoteOneLine(result.runRoot)}`
|
|
1212
|
+
);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
if (result.kind === 'lora') {
|
|
1216
|
+
const exportCount = Array.isArray(result.exports) ? result.exports.length : 0;
|
|
1217
|
+
console.log(
|
|
1218
|
+
`[metrics] kind=lora action=${result.action || 'run'} exports=${exportCount} runRoot=${quoteOneLine(result.runRoot)}`
|
|
1219
|
+
);
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1125
1222
|
const suite = String(result.suite || '');
|
|
1126
1223
|
const metrics = result.metrics;
|
|
1127
1224
|
if (!metrics || typeof metrics !== 'object') return;
|