<!-- Canonical: https://lucioduran.com/es/blog/webnn-api-hardware-accelerated-ml-browser
Language: es
Content-SHA256: b1ed1f478e292d3d43c894a93dd7e8a177b79d6e2be0d041d5122a50b61a6770
-->

AI/ML

# WebNN API: ML Acelerado por Hardware en el Browser, Acceso a NPU y Benchmarks Reales de Inferencia On-Device

2025-12-144 min lectura

Lucio Durán
Engineering Manager & AI Solutions Architect

También disponible en: [English](<https://lucioduran.com/blog/webnn-api-hardware-accelerated-ml-browser>)

## Ejecución de Modelos ONNX

El camino práctico a WebNN es a través de ONNX Runtime Web:

```javascript
import * as ort from 'onnxruntime-web';

async function runInference(imageData) {
 const session = await ort.InferenceSession.create(
 'mobilenet_v3_small_int8.onnx',
 {
 executionProviders: [
 {
 name: 'webnn',
 deviceType: 'npu',
 powerPreference: 'default',
 },
 ],
 fallbackExecutionProviders: ['wasm'],
 },
 );

 const tensor = new ort.Tensor('float32', preprocessImage(imageData), [1, 3, 224, 224]);

 const startTime = performance.now();
 const results = await session.run({ input: tensor });
 const elapsed = performance.now() - startTime;

 console.log(`Tiempo de inferencia: ${elapsed.toFixed(2)}ms`);

 const probabilities = softmax(results.output.data);
 return getTopK(probabilities, 5);
}

function preprocessImage(imageData) {
 const canvas = new OffscreenCanvas(224, 224);
 const ctx = canvas.getContext('2d');
 ctx.drawImage(imageData, 0, 0, 224, 224);

 const pixels = ctx.getImageData(0, 0, 224, 224).data;
 const float32 = new Float32Array(3 * 224 * 224);

 const mean = [0.485, 0.456, 0.406];
 const std = [0.229, 0.224, 0.225];

 for (let i = 0; i < 224 * 224; i++) {
 float32[i] = (pixels[i * 4] / 255 - mean[0]) / std[0];
 float32[i + 224 * 224] = (pixels[i * 4 + 1] / 255 - mean[1]) / std[1];
 float32[i + 2 * 224 * 224] = (pixels[i * 4 + 2] / 255 - mean[2]) / std[2];
 }

 return float32;
}
```

## Benchmarks Reales

Se benchmarkearon tres modelos en diferentes backends en dos máquinas:

**Máquina 1: Intel Core Ultra 7 (Meteor Lake), 16GB RAM, Chrome 126**

| Modelo | WASM (CPU) | WebGPU | WebNN (NPU) | WebNN (GPU) |
| --- | --- | --- | --- | --- |
| MobileNetV3-Small (INT8) | 18ms | 4.2ms | 2.8ms | 3.1ms |
| MobileNetV3-Large (FP32) | 45ms | 8.5ms | , | 7.2ms |
| ResNet-50 (INT8) | 125ms | 15ms | 11ms | 12ms |
| DistilBERT (INT8, seq=128) | 340ms | 42ms | 28ms | 35ms |

**Máquina 2: Apple M3 Pro, 18GB RAM, Chrome 126**

| Modelo | WASM (CPU) | WebGPU | WebNN (GPU)\* |
| --- | --- | --- | --- |
| MobileNetV3-Small (INT8) | 12ms | 3.8ms | 3.2ms |
| ResNet-50 (INT8) | 95ms | 12ms | 10ms |

\*WebNN en macOS usa el delegado CoreML, que routea al ANE (Apple Neural Engine).

## Patrones de IA que Preservan la Privacidad

El caso de uso más convincente para inferencia on-device no es el performance, es la privacidad:

```javascript
async function analyzeSkinLesion(image) {
 const session = await getOrCreateSession('dermnet_classifier_int8.onnx');
 const tensor = preprocessDermatologyImage(image);

 // Inferencia local, la imagen nunca se manda a un server
 const results = await session.run({ input: tensor });

 // Solo el resultado de clasificación se manda al server
 await reportClassification(results.classification, {
 confidence: results.confidence,
 });

 return results;
}
```

Este patrón se ha aplicado exitosamente en clasificación de documentos para aplicaciones de legal tech. Los documentos se procesan con OCR localmente (usando Tesseract.js), después se clasifican con un modelo DistilBERT corriendo a través de WebNN. El contenido del documento nunca sale del dispositivo.

## Optimización de Modelos para On-Device

```python
# Paso 1: Exportar a ONNX desde PyTorch
torch.onnx.export(model, dummy_input, "model_fp32.onnx", opset_version=17)

# Paso 2: Cuantizar a INT8
from onnxruntime.quantization import quantize_dynamic, QuantType
quantize_dynamic("model_fp32.onnx", "model_int8.onnx", weight_type=QuantType.QInt8)

# Paso 3: Optimizar grafo para WebNN
import onnxoptimizer
model = onnx.load("model_int8.onnx")
optimized = onnxoptimizer.optimize(model, [
 'eliminate_deadend',
 'fuse_bn_into_conv',
 'fuse_consecutive_transposes',
])
onnx.save(optimized, "model_int8_optimized.onnx")
```

Resultado: MobileNetV3-Small pasa de 14.3MB (FP32) a 3.8MB (INT8 cuantizado). Lo suficientemente pequeño para cachear en un Service Worker.

## Para Cerrar

WebNN cierra la brecha entre "ML en el browser es un juguete" y "ML en el browser es viable en producción." El hardware está, NPUs vienen en cada laptop nueva Intel y Qualcomm. La API está, Chrome la soporta hoy. Los modelos están, modelos ONNX cuantizados corren a frame rates interactivos.

Los case es de uso donde esto más importa: aplicaciones sensibles a privacidad donde los datos no pueden salir del dispositivo, aplicaciones sensibles a latencia donde los round-trips de red son inaceptables, y aplicaciones offline-capable que necesitan ML sin conectividad.

Para todo lo demás, llamar a una API sigue siendo más simple. Pero el conjunto de "todo lo demás" se está achicando rápido.

## Preguntas frecuentes

### ¿Qué es WebNN y cómo difiere de correr ML en WebAssembly?

WebNN es una API del browser que da acceso directo a aceleradores ML de hardware, NPUs, GPUs y DSPs. ML basado en WASM (como ONNX Runtime Web con backend WASM) corre en la CPU usando bytecode portable. WebNN es típicamente 5-20x más rápido porque usa silicio dedicado diseñado para operaciones matriciales, con kernels optimizados provistos por el driver del fabricante del hardware.

### ¿Qué browsers soportan WebNN en 2026?

Chrome 124+ y Edge 124+ incluyen con soporte WebNN. Firefox lo tiene detrás de un flag. Safari no tiene timeline público. El soporte de NPU específicamente requiere hardware compatible, Intel Meteor Lake/Arrow Lake, Qualcomm Snapdragon X Elite, o Apple M-series (a través del delegado CoreML).

### ¿Es la inferencia on-device realmente práctica para aplicaciones de producción?

Para modelos bajo 50MB (cuantizados), absolutamente. Clasificación de imágenes, embeddings de texto, análisis de sentimiento, detección de poses, todo corre fluido on-device. Para LLMs, on-device todavía está limitado a modelos pequeños (\< 1B parámetros). Los principales case es de uso en producción son aplicaciones sensibles a privacidad (análisis de imágenes médicas, procesamiento de documentos) y las sensibles a latencia (efectos de video en tiempo real, predicción de input).

## Tips

1. **Tip:** Siempre verificar soporte de WebNN con ` navigator.ml ` antes de intentar usarlo, y caé back a ONNX Runtime Web (backend WASM) cuando no esté disponible. A principios de 2026, solo browsers basados en Chromium incluyen WebNN, y el soporte de NPU depende del hardware.
2. **Tip:** Cuantizá tus modelos ONNX a INT8 antes de deployar a WebNN. El path de NPU está optimizado para operaciones enteras, los benchmarks muestran un speedup de 4.2x en un modelo MobileNetV3 yendo de FP32 a INT8 en un NPU Intel Meteor Lake.
3. **Tip:** Utilizar el tipo de dispositivo ` 'npu' ` para workloads sostenidos y ` 'gpu' ` para inferencia en ráfagas. Los NPUs son eficientes en energía pero tienen mayor latencia de dispatch inicial. Para una sola clasificación de imagen, GPU gana. Para procesar un stream de video frame-por-frame, NPU gana por lejos en vida de batería.

- webnn
- machine-learning
- browser-ml
- npu
- onnx
- inferencia-on-device
- webgpu
- privacidad
- edge-ai
- aceleracion-hardware

[Volver al Blog](<https://lucioduran.com/es/blog>)
