Technical Deep Dives¶
Model sourcing, backend semantics, browser compatibility
CPU (pure JS) vs WASM — genuinely different in TF.js¶
TensorFlow.js has two CPU-targeting backends that are not aliases:
| Backend | Execution | Performance |
|---|---|---|
| CPU | Pure JavaScript TF ops (interpreted) | Slowest — no compilation, no threading |
| WASM | Compiled C++ TF ops via WebAssembly + SharedArrayBuffer threads | Significantly faster — multi-threaded C++ runtime |
This is one of the most interesting benchmark dimensions: the perf delta between interpreted JS and compiled WASM with threading. ONNX Runtime Web does not offer a pure-JS CPU path — its cpu option is an alias for wasm.
WebNN — emerging NPU backend (ORT only)¶
Discovered during review of the ONNX Runtime Web official docs: ORT supports webnn as an execution provider, usable for both GPU and CPU processing via deviceType.
| Browser | Platform | WebNN Backend |
|---|---|---|
| Chrome 113+ / Edge | Windows | DirectML (GPU via MLDeviceType.gpu) |
| Chrome / Edge | macOS | CoreML / ANE (Neural Engine via MLDeviceType.cpu) |
| Chrome / Edge | Linux | TBD — limited support |
| Safari / Firefox | All | Not supported |
WebNN routes inference through the OS-level ML stack — DirectML on Windows, CoreML/ANE on macOS. This is conceptually closer to an NPU backend than a traditional GPU backend, since it uses dedicated ML accelerators where available. Browser support is limited but growing. We include it in the backend matrix as ORT-only with a navigator.ml feature check gate.
Validated in benchy (Aug 2026)
WebNN works unflagged in Chromium-based browsers on supported hardware: onnx webnn completed end-to-end on Edge stable/Win11 (median 59.85 ms, internal backend truth-reported webnn); Firefox → skipped/webnn-unavailable (Detect & Report). Evidence: research/validation-gate-benchy.md. WebNN stays excluded from the primary measured matrix for cross-browser comparability (no non-Chromium browser ships it).
Why include Transformers.js when it wraps ORT?¶
Transformers.js v4 uses ONNX Runtime Web as its inference engine. Benchmarking both could be seen as comparing ORT against itself. However, Transformers.js adds meaningful differences:
- API level: Pipeline abstraction (
pipeline("image-classification", model)) vs raw session+tensor management in bare ORT - Ecosystem: HuggingFace model hub integration, auto-download, auto-tokenization
- Model variants: Uses
onnx-communityquantized models which may differ from the raw ONNX models we use with bare ORT - Developer experience: Represents the "ease of use" end of the spectrum — relevant to the thesis Integration criterion
The pipeline overhead for a single image classification forward pass is negligible, so performance should be nearly identical to bare ORT. Any difference would come from model quantization differences, not framework overhead.
Terminology
In the thesis, Transformers.js is classified as a framework (high-level API), not a runtime (low-level engine). The comparison includes both runtimes and frameworks to span the abstraction spectrum.
ONNX model sourcing: HuggingFace CDN¶
The ONNX Runtime Web adapter was originally broken — ONNX_MODEL_URL = null with the comment "GitHub LFS doesn't work via CDN." GitHub serves LFS-tracked binary files as pointer files (~130 bytes containing an OID hash) rather than the actual model weights when accessed via jsDelivr or raw URLs.
Resolution: ONNX models are loaded directly from HuggingFace's /resolve/main/ CDN path — no authentication required:
This serves the actual binary file (not LFS pointers) with proper CORS headers. The ONNX Model Zoo GitHub repo (github.com/onnx/models) discontinued LFS downloads in July 2025; HuggingFace is the official successor at huggingface.co/onnxmodelzoo with 2,326+ models.
The adapter reads model URLs from the MODEL_REGISTRY in pipeline.js rather than hardcoding them.
MODEL_REGISTRY — centralizing model distribution¶
Each adapter previously hardcoded model URLs from different sources (jsDelivr, HuggingFace, Google Storage). The MODEL_REGISTRY in pipeline.js centralizes:
- Model metadata: name, description, input size
- Per-runtime CDN URLs: one entry per (model, runtime) pair pointing to the appropriate CDN
- Runtime filtering: the UI greys out runtimes that don't have a model available
Three CDN sources cover all current needs: HuggingFace Hub (for ORT .onnx models), TF Hub / jsDelivr (for TF.js and LiteRT.js .tflite models), and Google Storage (for MediaPipe pre-optimized models).
Browser compatibility: SharedArrayBuffer & COOP/COEP¶
ONNX Runtime Web's WASM backend and MediaPipe Tasks require SharedArrayBuffer, which needs Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp HTTP headers. Without them, WASM backends cannot use multi-threading.
Non-technical users
Opening index.html via file:// will NOT work — a server with COOP/COEP headers is required. See ml-browser-check for server setup details.