Heuristic:Tensorflow Tfjs Backend Selection Strategy
| Metadata | |
|---|---|
| Source | Repo, Blog |
| Domains | Optimization, Infrastructure |
| Date | 2026-02-10 |
Overview
Choose the optimal TensorFlow.js backend (WebGL, WebGPU, WASM, CPU) based on model size, target device, and use case requirements.
Description
TensorFlow.js supports four backends with different performance profiles. The backend determines where tensor computations run. Auto-registration priorities are: WebGPU (3), WebGL (2), CPU (1). WASM must be explicitly set. Backend choice dramatically affects inference speed—up to 100x between worst and best.
Usage
Use this heuristic when deploying a TensorFlow.js model and choosing which backend package to include. Critical for production deployments where performance matters.
The Insight
- Action: Select backend based on model complexity and target environment
- Value: For medium models (100-500M MACs): WebGL/WebGPU >> WASM >> CPU. For lite models (20-60M MACs): WASM ≈ WebGL. For Node.js: use tfjs-node for native C++ speed.
- Trade-off: WebGPU has highest ceiling but limited browser support (Chrome M113+). WebGL has broadest support. WASM has best numerical stability and wider device support. CPU is slowest but universal.
- Backend priority: WebGPU (3) > WebGL (2) > CPU (1). WASM must be set explicitly with tf.setBackend('wasm').
Reasoning
From WASM README benchmarks: MobileNet V2 on Linux desktop:
| Backend | Inference Time |
|---|---|
| WebGL | 44.8ms |
| WASM | 122.7ms |
| Plain JS (CPU) | 1489.4ms |
| WASM+SIMD | 34.6ms |
| WASM+SIMD+threads | 12.4ms |
For Face Detector (lite model): WASM and WebGL are comparable. CPU handoff thresholds: WebGL delegates to CPU for tensors < 128 elements, WebGPU for < 1000 elements.
Code Evidence
From tfjs-backend-webgl/src/base.ts:24-26
if (device_util.isBrowser()) {
registerBackend('webgl', () => new MathBackendWebGL(), 2 /* priority */);
}
From tfjs-backend-webgpu/src/base.ts:25-68
if (isWebGPUSupported()) {
registerBackend('webgpu', async () => {
const gpuDescriptor: GPURequestAdapterOptions = {
powerPreference: env().get('WEBGPU_USE_LOW_POWER_GPU')
? 'low-power'
: 'high-performance'
};
const adapter = await navigator.gpu.requestAdapter(gpuDescriptor);
// ...
}, 3 /*priority*/);
}