Skip to content
目录

ONNX 后端、执行提供者与推理串行化

1. 为何同时依赖 onnxruntime-nodeonnxruntime-web

backends/onnx.js 顶部注释说明:理想情况是按环境 动态 import,但历史上有 bundler 与 top-level await 限制,因此 静态同时 import,构建时再 tree-shake(Node 包不打进浏览器 bundle)。

运行时选择:

  • Nodeonnxruntime-node
  • 浏览器onnxruntime-web/webgpu 路径(与 WebGPU 能力绑定)。

另:若全局存在 Symbol.for('onnxruntime'),则优先使用宿主注入的 ORT(便于嵌入已加载 ORT 的运行时)。

1:17:packages/transformers/src/backends/onnx.js
/**
 * @file Handler file for choosing the correct version of ONNX Runtime, based on the environment.
 * Ideally, we could import the `onnxruntime-web` and `onnxruntime-node` packages only when needed,
 * but dynamic imports don't seem to work with the current webpack version and/or configuration.
 * This is possibly due to the experimental nature of top-level await statements.
 * So, we just import both packages, and use the appropriate one based on the environment:
 *   - When running in node, we use `onnxruntime-node`.
 *   - When running in the browser, we use `onnxruntime-web` (`onnxruntime-node` is not bundled).

2. 设备 → Execution Provider

deviceToExecutionProviders 将逻辑设备(wasmwebgpucudawebnn-npu 等)映射到 ORT 的 EP 配置;auto / gpu 会展开为 候选列表(按优先级尝试)。

浏览器默认 defaultDevices = ['wasm'];若检测到 WebGPU/WebNN,则把对应设备列入 supportedDevices 供选择。

3. Web 端 Session 创建串行:webInitChain

注释写明:当前不支持在 WASM/WebGPU 下并行加载多个 session,因此用 Promise 链 串行化 InferenceSession.create,否则易出现加载阶段竞态。

180:297:packages/transformers/src/backends/onnx.js
/**
 * Currently, Transformers.js doesn't support simultaneous loading of sessions in WASM/WebGPU.
 * For this reason, we need to chain the loading calls.
 * @type {Promise<any>}
 */
let webInitChain = Promise.resolve();
...
export async function createInferenceSession(buffer_or_path, session_options, session_config) {
    await ensureWasmLoaded();
    const logSeverityLevel = getOnnxLogSeverityLevel(env.logLevel ?? LogLevel.WARNING);
    const load = () =>
        InferenceSession.create(buffer_or_path, {
            logSeverityLevel,
            ...session_options,
        });
    const session = await (apis.IS_WEB_ENV ? (webInitChain = webInitChain.then(load)) : load());
    session.config = session_config;
    return session;
}

4. Web 端推理串行:webInferenceChain

更关键的是 run 阶段runInferenceSession 在 Web 环境把 session.run 也串到同一链上,注释直接点出典型错误:Error: Session already started

300:316:packages/transformers/src/backends/onnx.js
/**
 * Currently, Transformers.js doesn't support simultaneous execution of sessions in WASM/WebGPU.
 * For this reason, we need to chain the inference calls (otherwise we get "Error: Session already started").
 * @type {Promise<any>}
 */
let webInferenceChain = Promise.resolve();

export async function runInferenceSession(session, ortFeed) {
    const run = () => session.run(ortFeed);
    return apis.IS_WEB_ENV ? (webInferenceChain = webInferenceChain.then(run)) : run();
}

设计权衡(可简述为)

  • 正确性/兼容性优先:ORT Web 在部分环境下对并发 run 敏感,全局串行是最稳妥策略;
  • 代价:多标签页或多模型并行推理时 无法真正并行,吞吐量受限于单链;若需并行,通常要 Worker 隔离多 ORT 实例(需自行验证 EP 支持)。

5. WASM 预加载与 Deno 特例

ensureWasmLoaded 在启用 env.useWasmCache 且配置了 wasm/mjs 路径时,预取二进制与 factory;Deno web 运行时若关闭 cache 会 直接抛错(避免错误走 Node API 分支)。

6. 日志级别映射

getOnnxLogSeverityLevel 将库的 LogLevel 映射到 ORT 的 0–4,并刻意 合并部分级别,因为 ORT 在 session 创建时日志极多,避免淹没用户。

7. 与 session.js 的关系

models/session.jsgetSession / constructSessions 负责:

  • 调用 selectDevice / selectDtype
  • getCoreModelFile + getModelDataFiles(external data);
  • WebGPU 下可选 preferredOutputLocation: gpu-buffer 以优化 KV cache(见 设备与量化生成)。

小结:读 Transformers.js 的 ORT 集成,应同时记住 EP 选择Web 双链(init + inference),这是线上「偶现 Session already started」类问题的根源与官方缓解手段。

下一篇:设备、dtype 与量化选择

MIT License.