ONNX Runtime JSEP(JS Execution Provider)弃用指南:onnxruntime-web 的 WebGPU 原生半体与其向原生 WebGPU EP 的迁移
【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime
本文围绕 JSEP 原生端目录说明 展开:解释onnxruntime/core/providers/js/在 onnxruntime-web 中扮演的角色、该 EP 已进入"仅接受 bug 修复与安全修复"维护模式的原因、其 TypeScript 内核与 C++ 桩代码协同工作的实现机制、--use_jsep(USE_JSEP)构建链路,以及如何判断你的构建到底在跑哪套 WebGPU 后端,并给出向原生 WebGPU EP 迁移的具体路径。
目录定位:JSEP 的"原生半体"
onnxruntime/core/providers/js/ 是JSEP(JS Execution Provider)的原生半体,对应onnxruntime-web中 JavaScript/TypeScript 实现的 WebGPU 计算路径。JSEP 的核心思想是:把 WebGPU 计算逻辑用 TypeScript 写在浏览器端(js/web/lib/wasm/jsep/),而 C++ 侧(即本目录)只负责生成内核桩(kernel stubs),每个算子在构造与执行时通过 Emscripten 的EM_ASM内联汇编把调用"派发回" JavaScript 侧真正执行。
该目录当前的文件构成(均可在仓库中直接查看):
| 文件 | 职责 |
|---|---|
| js_execution_provider.h / js_execution_provider.cc | EP 主体:能力划分(GetCapability)、内核注册表、数据布局偏好、图捕获(Graph Capture)策略 |
| js_kernel.h / js_kernel.cc | JsKernel基类与JSEP_KERNEL_IMPL等宏,完成"序列化上下文 → 回调 JS 内核"的执行桥 |
| js_provider_factory.cc / js_provider_factory_creator.h | IExecutionProviderFactory工厂,按 ProviderOptions 创建JsExecutionProvider |
| allocator.h / data_transfer.h / external_data_loader.h | EP 私有分配器、CPU↔JS 内存搬运、外部数据加载 |
| js_data_types.h | JSEP 自定义数据类型的桥接定义 |
| js_export.h | EMSCRIPTEN_KEEPALIVE导出的 C 函数(JsepOutput、JsepGetNodeName),供 JS 侧回调 |
| operators/ | 约 40 组 ONNX 算子桩:Conv、MatMul、Gemm、Pool、Softmax、Resize、LayerNorm、GatherND、ScatterND、DFT、Einsum 等 |
JSEP 的完整组成跨越仓库多个区域(引自权威弃用声明 docs/JSEP_Deprecation.md):
| 路径 | 内容 |
|---|---|
js/web/lib/wasm/jsep/ | TypeScript WebGPU 后端及全部内核实现 |
onnxruntime/core/providers/js/(本目录) | 原生 "JS EP"——把执行派发回 JavaScript 的内核桩 |
onnxruntime/contrib_ops/js/ | 同一 EP 的 contrib 算子注册(js_contrib_kernels.cc 等) |
onnxruntime/wasm/pre-jsep.js | Emscripten 胶水脚本 |
cmake/onnxruntime_providers_js.cmake、js/build_jsep.bat | 构建管线 |
当前状态:弃用与贡献政策
README 开宗明义:本目录已弃用,计划移除;替代品是 onnxruntime/core/providers/webgpu/ 下的原生 WebGPU execution provider。JSEP 处于维护模式(maintenance mode),仅接受 bug 修复与安全修复;新算子、新特性、性能优化一律应提交到原生 WebGPU EP。
docs/JSEP_Deprecation.md 给出了权威的变更归属表:
| 变更类型 | 归属 |
|---|---|
| 既有 JSEP 内核的正确性/安全修复 | JSEP——接受 |
| 新算子 | 原生 WebGPU EP——onnxruntime/core/providers/webgpu/或onnxruntime/contrib_ops/webgpu/ |
| 新特性或性能工作 | 原生 WebGPU EP |
需要注意两点细节:
- 移除时间表尚未确定,官方表示会依据真实世界的 JSEP 使用量在移除前公告;
js/web/docs/webgpu-operators.md虽名为 webgpu,但实际列举的是JSEP算子,不能用它来判断原生 WebGPU EP 的算子覆盖情况;若某模型在 JSEP 上能跑、在原生 WebGPU EP 上跑不了,属于值得报告的缺口(open issue 或在原生 EP 中补齐)。
"现在往 JSEP 加代码,等于这些工作日后被删除、还要针对原生 EP 重写一遍"——这是弃用声明中明确的贡献者警示。
实现机制:C++ 桩如何驱动 TypeScript 内核
内核注册与构造
本目录中的算子桩普遍采用js_kernel.h中定义的一组宏。以JSEP_KERNEL_IMPL(classname, optype)为例,它生成的类在构造时执行JSEP_INIT_KERNEL(optype),展开为:
#define JSEP_INIT_KERNEL(optype) EM_ASM({ Module.jsepCreateKernel(#optype, $0, undefined); }, this)即 C++ 内核对象构造时,通过EM_ASM内联 JavaScript 在浏览器端注册同名内核(Module.jsepCreateKernel),析构时调用Module.jsepReleaseKernel释放。带属性的算子(如 Conv 的 strides/pads)则通过JSEP_CLASS_IMPL_ATTRIBUTE_FLOAT_DEFAULT等宏把OpKernelInfo中读到的属性值一并传给 JS 侧。
执行桥:上下文序列化
JsKernel::ComputeInternal展示了每次Compute的完整链路(见 js_kernel.h):
SerializeKernelContext把OpKernelContext序列化为一段连续uintptr_t数组:context_ptr | input_count | output_count | custom_data_ptr | custom_data_size,随后对每个输入写入type | data_ptr | dim_size | dim[0..N-1];可选输入为空时写入三个 0 占位,JS 侧据此感知输入个数;- 通过
EM_ASM_INT调用Module.jsepRunKernel,传入内核对象、序列化缓冲、session handle 与错误通道; - 依据返回状态码映射为
Status::OK()或失败。
此外js_export.h用EMSCRIPTEN_KEEPALIVE导出JsepOutput/JsepGetNodeName供 JS 回调;JsKernel还支持SerializeCustomData供子类追加自定义数据(JsMultiProgramKernel的多程序内核在源码中仍标注为 TODO)。
EP 层行为特征
从 js_execution_provider.h 可以看到几个影响使用者行为的关键设定:
- 首选数据布局 NHWC:
JsExecutionProviderInfo从 ProviderOptions 的preferred_layout读取,仅支持"NCHW"/"NHWC",JSEP 默认为NHWC(L23-L38); - 禁止并发运行:
ConcurrentRunSupported()返回false,源码注释解释原因是底层实现(如 WebGPU 后端)依赖全局状态,异步并发运行可能破坏状态导致未定义行为(L63-L65); - 融合风格
FusionStyle::FilteredGraphViewer,并内置图捕获(Graph Capture)支持:要求最少 1 次常规运行后才捕获,节点分配策略为ALLOW_CPU_FOR_SHAPES。
js_execution_provider.cc中还在kJsExecutionProvider下注册了MemcpyFromHost/MemcpyToHost(执行队列 0/1),用于 CPU 与 JS 内存域之间的张量搬运,以及数十个带版本区间的一阶算子(如 Abs、Neg、Tanh 注册在 opset 6–12 与 13 两个区间)。
构建链路:USE_JSEP 与 WASM 产物
JSEP 通过构建参数--use_jsep(CMake 变量USE_JSEP)启用,注册到 EP 名称JsExecutionProvider之下。仓库中的构建管线证据:
- cmake/CMakeLists.txt 定义
option(onnxruntime_USE_JSEP "Build with JavaScript implemented kernels support" OFF),为真时追加-DUSE_JSEP=1编译定义; - tools/ci_build/build_args.py 中的 argparse 定义
--use_jsep("Enable JavaScript EP (used with WebAssembly)"); - cmake/onnxruntime_providers_js.cmake 负责把本目录与 contrib_ops/js 源文件纳入编译;js/build_jsep.bat 是 Windows 下的 JSEP 构建入口。
浏览器侧的产物选择则体现在 js/web/package.json 的导出映射中(.jsep.wasm资产路径等)。
区分两套 "WebGPU":import 与 WASM 文件名
JSEP 与原生 WebGPU EP 都注册在 JavaScript 的webgpu后端键下,运行哪一个由构建期决定,而非运行期。docs/JSEP_Deprecation.md 给出的对照表是排障时的首选依据:
| Import | WebGPU 实现 | WASM 产物 |
|---|---|---|
onnxruntime-web(默认) | JSEP | ort-wasm-simd-threaded.jsep.wasm |
onnxruntime-web/all | JSEP | ort-wasm-simd-threaded.jsep.wasm |
onnxruntime-web/webgpu | 原生 WebGPU EP | ort-wasm-simd-threaded.asyncify.wasm |
onnxruntime-web/jspi | 原生 WebGPU EP | ort-wasm-simd-threaded.jspi.wasm |
WASM 文件名中的.jsep中缀是可靠判别信号。一份没有指明 import 或产物的 bug 报告在 triage 前属于歧义状态,应先澄清。
如何迁移到原生 WebGPU EP
onnxruntime-web/webgpu与onnxruntime-web/jspi今天已经基于原生 WebGPU EP 构建,不需要任何代码改动即可使用:
import * as ort from 'onnxruntime-web/webgpu';结合迁移设计文档 docs/design/onnxruntime_web_jsep_to_webgpu_ep_migration.md,使用者需要关注以下差异点:
- 默认 import 暂未切换:当前
onnxruntime-web默认仍选 JSEP,计划在未来版本翻转为原生 WebGPU EP;翻转后官方会提供临时的onnxruntime-web/jsep逃生舱导出用于固定旧行为(至少保留一个 release,期间使用会发出一次性弃用警告)。 - int64 行为:原生 WebGPU EP 默认
enableInt64 = false,与 JSEP 默认行为一致(int64 算术在 CPU/WASM 上全精度执行,int64 索引在 GPU 上按 i32 截断)。如需 GPU 上全量 int64,可通过extra: { 'ep.webgpuexecutionprovider.enableInt64': '1' }开启,代价是> 2³¹的真值会丢失精度;另外enableGraphCapture = true会强制打开 int64。 - JSEP 专属的
env.webgpu设置:env.webgpu.profiling.ondata(每次 dispatch 的 JS 回调,携带kernelId/时间戳/张量元数据)在原生路径上没有等价物,属 JSEP-only 机制,将随 JSEP 一起移除;adapter/forceFallbackAdapter在原生路径上为 no-op,自定义设备请走 per-session 的executionProviders: [{ name: 'webgpu', device }];powerPreference将转发到原生 EP 的ep.webgpuexecutionprovider.powerPreference选项,且需注意两者的未设置默认行为不同(JSEP 让浏览器自选,原生侧默认HighPerformance)。 - wasmPaths:翻转后底层产物从
.jsep.wasm变为.asyncify.wasm,固定了 WASM 路径的消费者(对象形式env.wasm.wasmPaths、预加载/CSP 规则、复制的资源)需要同步更新。 - 算子/类型面:原生 WebGPU EP 构建当前应用了缩减构建参数(禁用 ml ops、generation ops 与 string/float4/float8/optional/sparse 类型),翻转前该差异需要按设计文档 §7 的 A/B/C 构建测量结果统一处理。
Phase 2:JSEP 将被移除什么
设计文档明确了删除范围(约 130 个 C++/CMake 文件,几乎全是删除):onnxruntime/core/providers/js/(约 90 文件)与onnxruntime/contrib_ops/js/(约 30 文件)、cmake/onnxruntime_providers_js.cmake 及USE_JSEP在多个 CMake 文件中的管线、onnxruntime/wasm/pre-jsep.js、js/build_jsep.bat,以及 CI 中--use_jsep参数。两处需要特别留意:kJsExecutionProvider属于公共 C API 面(声明于include/onnxruntime/core/graph/constants.h并在onnxruntime_c_api.h中命名),其移除是一次 API 变更;post-webnn.js在 JSEP 构建下被抑制,移除 JSEP 会改变 WebNN 构建链接的胶水脚本,需要 WebNN 冒烟测试而不只是编译通过。
小结
onnxruntime/core/providers/js/ 承载的是 JSEP 的 C++ 内核桩与 EP 基础设施:内核通过EM_ASM把执行派发回 TypeScript 侧的 WebGPU 实现,EP 侧提供 NHWC 偏好布局、禁止并发运行、图捕获等策略。该组件已进入"仅 bug 与安全修复"的维护模式,替代品是原生 WebGPU EP——今天即可通过onnxruntime-web/webgpu或onnxruntime-web/jspiimport 使用,默认 bundle 的翻转与 JSEP 的最终移除将按 docs/JSEP_Deprecation.md 与 迁移设计文档 的分期推进,并在移除前公告时间表。
【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考