Implement speedups for transcription.

This commit is contained in:
Lucas Winther
2026-07-15 14:45:40 +02:00
parent 742053144e
commit a5cfd219f6
3 changed files with 118 additions and 16 deletions
+26
View File
@@ -38,6 +38,31 @@ if (env.backends.onnx.wasm) {
env.backends.onnx.wasm.wasmPaths = "./ort/";
}
/**
* Set the WASM thread count for the device we are about to create a pipeline
* on (D-023). The server sends COOP/COEP, so SharedArrayBuffer exists and
* threads genuinely run — which cuts both ways:
* - Pure WASM inference scales well past onnxruntime-web's 4-thread default,
* so use most of the machine (measured 52 s → 9.5 s on a 14 s clip).
* - The JSEP-based accelerator EPs (WebGPU, WebNN) are NOT thread-safe:
* with numThreads > 1 (even ort's own default of ~4 once SAB exists),
* inference fails with "WebGPU validation failed. Buffer with '' label is
* invalid". They must run the wasm side single-threaded.
* Caveat: onnxruntime-web initializes its runtime on the first session
* creation and ignores later numThreads changes, so the first attempt in
* this worker decides. A wasm *fallback* after a failed accelerator attempt
* therefore may run single-threaded — correct, just slower; the next worker
* respawn (cancel does one, D-018) picks the full count up again.
*/
function configureWasmThreads(device: InferenceDevice): void {
const wasm = env.backends.onnx.wasm;
if (!wasm) return;
wasm.numThreads =
device === "wasm" && globalThis.crossOriginIsolated
? Math.max(1, Math.min((navigator.hardwareConcurrency || 4) - 1, 12))
: 1;
}
// `lib: ["DOM"]` types `self` as Window; give it the worker-scope shape we use.
interface DedicatedWorkerScope {
postMessage(message: WorkerToUiMessage): void;
@@ -153,6 +178,7 @@ async function createPipeline(
let lastError: unknown;
for (const device of attempts) {
configureWasmThreads(device);
const dtype = message.dtype ?? resolveDefaultDtype(message.modelId, device);
try {
const asr = await pipeline("automatic-speech-recognition", message.modelId, {