<!-- Canonical: https://lucioduran.com/es/projects/webgpu-local-inference
Language: es
Content-SHA256: f2185eb8ec1201a6db604eabadbe50ae0fae45e589f76ed7e7209c6ba19feb9b
-->

[Proyectos](<https://lucioduran.com/es/projects>) / WebGPU Local Inference

# WebGPU Local Inference

Clasificación de solicitudes de soporte en el navegador, con WebGPU nativo, alternativa real en WebAssembly y arranque desde caché registrado durante un fallo local de recursos.

Autor: [Lucio Durán](<https://lucioduran.com/es>) · Node 24.8.0, Chromium 157.0.0.0, WebGPU y WebAssembly · Licencia: [MIT](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/LICENSE>)

Ficha publicada: 2026-11-10 · Ficha actualizada: 2026-11-10

[Repositorio](<https://github.com/lucioduran/webgpu-local-inference>) · [Informe original de ejecución del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-1794256500335.json>) · [Release v0.1.0](<https://github.com/lucioduran/webgpu-local-inference/releases/tag/v0.1.0>)

## Problema y utilidad para agentes

Los ejemplos de inferencia en el navegador pueden ocultar el uso de CPU como alternativa, omitir entradas reproducibles o confundir búferes asignados con memoria medida. Las afirmaciones sobre uso sin conexión también necesitan definir el fallo probado.

Un modelo pequeño compartido y modos explícitos permiten observar el comportamiento numérico, los motivos de cambio de motor, la cancelación y la dependencia de la caché en el navegador real.

## Arquitectura

1. **Compartir un modelo transparente.** Un clasificador bayesiano ingenuo multinomial entrenado con 12 solicitudes sintéticas originales genera pesos float32 para facturación, acceso y entrega. Se abstiene ante entradas sin coincidencias con el vocabulario.
2. **Ejecutar motores reales en el navegador.** Los productos escalares nativos en WGSL y un núcleo escalar WASM usan los mismos pesos. El modo automático informa el cambio de motor por un fallo de inicialización; el modo WebGPU estricto falla de forma visible en lugar de cambiar a CPU.
3. **Guardar en caché y conservar la evidencia.** Un service worker almacena una lista explícita de recursos locales. El ejecutor registra el uso en línea, rechaza los recursos estáticos, recarga el documento desde la caché y captura una segunda comparación de motores.

- [Diseño de motores y caché](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/docs/design.md>)
- [Protocolo de navegador congelado](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/docs/protocol.md>)
- [Núcleo en texto WebAssembly](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/src/kernel.wat>)

## Qué demuestra

- Inferencia real con WebGPU y WASM en el navegador, con 12 solicitudes de evaluación repetidas tres veces por motor en las fases en línea y de recarga desde caché.
- Las 144 predicciones de evaluación coincidieron con las etiquetas esperadas y con las puntuaciones exactas de referencia float32; el error absoluto máximo fue cero en esta tarea fija.
- Pruebas de abstención, entradas inválidas, cancelación, errores de modo estricto, destrucción deliberada del dispositivo y ausencia inyectada del adaptador, además de reproducción sin conexión y comprobaciones del paquete.

## Resultados publicados

Se probó un único Mac Pro físico: Intel Xeon W de ocho núcleos, 48 GB de RAM, AMD Radeon Pro W5700X con 16 GB de VRAM y macOS 26.7.1. Chromium 157.0.0.0 integrado en la aplicación expuso un adaptador AMD RDNA 1; los campos de dispositivo y descripción estaban vacíos.

Cada fila de tiempos cubre tres rondas fijas de 12 solicitudes, sin excluir calentamiento. La inicialización se registra por separado. La mediana promedia los dos valores centrales y el p95 usa el método del rango más próximo. Los textos de entrenamiento y evaluación son casos sintéticos propios, con particiones distintas y coincidencias de vocabulario intencionales.

### Latencia registrada en el navegador

| Fase y motor | Inicialización, ms | Primera inferencia, ms | Mediana de inferencia, ms | p95 de inferencia, ms |
| --- | --- | --- | --- | --- |
| WebGPU en línea | 49.2 | 7.3 | 0.4 | 1.5 |
| WASM en línea | 0.6 | 0.2 | Por debajo de la resolución del temporizador | 0.1 |
| WebGPU tras recarga desde caché | 6.0 | 0.7 | 0.4 | 0.7 |
| WASM tras recarga desde caché | 0.3 | Por debajo de la resolución del temporizador | Por debajo de la resolución del temporizador | 0.1 |

### Descargas y asignaciones lógicas

| Observación | Valor registrado |
| --- | --- |
| Cuerpo de respuesta del modelo | 3,951 bytes / 3.5 ms |
| Cuerpo de respuesta de WASM | 158 bytes / 3.1 ms |
| Asignación explícita de búferes de GPU | 712 bytes |
| Asignación de memoria lineal de WASM | 65,536 bytes |
| Error máximo frente a la referencia float32 | 0 |

En cada fase WASM, el temporizador del navegador registró cero en 34 de las 36 duraciones. Están por debajo de su resolución observable; no representan cómputo instantáneo. Estos productos escalares pequeños no justifican una proporción de aceleración entre motores ni afirmaciones de rendimiento para modelos mayores.

El valor de GPU corresponde a una asignación explícita de búferes y el de WASM al tamaño de su memoria lineal. Ninguno mide la memoria total del proceso, el consumo de memoria de GPU ni el máximo de memoria.

Los tamaños de los cuerpos de respuesta y los tiempos de descarga del modelo y WASM se obtuvieron mediante la conexión local. No son mediciones de transferencia por Internet. El informe conserva los tiempos de los recursos JavaScript. [Informe original de ejecución del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-1794256500335.json>).

Durante la recarga desde caché, el servidor rechazó ocho solicitudes de recursos estáticos, incluidos el modelo y WASM. El punto de recepción del informe local siguió disponible. Esto prueba un fallo de recursos del origen, no la desconexión de red del sistema operativo, el reinicio del navegador ni la eliminación de la caché.

La destrucción del dispositivo y la ausencia de adaptador fueron inyectadas explícitamente. No se observó una pérdida espontánea del dispositivo. Se conservan los fallos iniciales de conexión al navegador; no se probaron Safari ni otros dispositivos. [Fallo inicial de conexión conservado](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-blocker.json>).

## Reproducir

Usá el entorno registrado de Node 24.8.0. El modelo y el binario WASM incluidos permiten reproducir y probar sin instalar paquetes, descargar modelos ni usar servicios externos. Reconstruir el binario WASM requiere la dependencia de desarrollo wabt 1.0.37 fijada. El código, los casos y el modelo entrenado tienen licencia MIT.

El primer comando valida hashes de artefactos, ejecuta el núcleo WASM real y comprueba los informes guardados del navegador. El segundo ejecuta las pruebas pequeñas de Node, incluido el servidor HTTP local. Ninguno repite las mediciones de GPU. Para una nueva ejecución en el navegador, seguí el README y usá el bloqueo compartido y exclusivo de benchmarks.

### Verificar la evidencia guardada

```
git clone https://github.com/lucioduran/webgpu-local-inference.git
cd webgpu-local-inference
git checkout 7279202a64b6a047ca5f2ad88efd0360e876b333
node scripts/replay.mjs
```

### Ejecutar las pruebas de regresión

```
node --test
```

## Alcance y límites

- Solo se midieron un dispositivo físico y un entorno de navegador funcional. No se afirma compatibilidad con móviles, Safari, otros navegadores ni otros dispositivos.
- El vocabulario ASCII y las representaciones por conteo de palabras no resuelven de forma fiable negaciones, texto multilingüe, ambigüedad ni cambios de distribución. Las puntuaciones no son probabilidades calibradas ni evidencia de comprensión general del lenguaje.
- Las predicciones de GPU son secuenciales. La cancelación descarta un resultado pendiente, pero no puede interrumpir trabajo ya enviado a la GPU ni una llamada WASM síncrona; perder el dispositivo exige recrear el motor.
- El arranque desde caché depende de una acción previa explícita y de que el navegador conserve esos datos. El fallo simulado de recursos no demuestra comportamiento tras reiniciar el navegador o perder toda la conexión de red.
- La evidencia no mide memoria total, electricidad, energía, costo monetario de operación ni calidad de soporte en producción. La verificación de informes guardados solo establece consistencia.

- [Artículo relacionado sobre WebGPU](<https://lucioduran.com/es/blog/webgpu-compute-shaders-ml-inference>)

## Fuentes y revisión

La ejecución medida del navegador usó el commit 615e4051094b1b9ec865d920503a1516947cae71. El ejecutor con bloqueo comenzó a las 2026-11-09T20:34:26.446Z; el trabajo del navegador se ejecutó entre 2026-11-09T20:35:00.011Z y 2026-11-09T20:35:00.330Z, y el informe llegó a las 20:35:00.334Z. La release conserva el mismo modelo, los casos, los núcleos y la carga del navegador. Los cambios posteriores afectan informes, reproducción, empaquetado y metadatos de Git. Los manifiestos vinculan esos archivos; su consistencia no demuestra autenticidad independiente de las mediciones.

- Revisión consultada: [` 7279202a64b6a047ca5f2ad88efd0360e876b333 `](<https://github.com/lucioduran/webgpu-local-inference/commit/7279202a64b6a047ca5f2ad88efd0360e876b333>)
- Revisión registrada por el experimento: [` 615e4051094b1b9ec865d920503a1516947cae71 `](<https://github.com/lucioduran/webgpu-local-inference/commit/615e4051094b1b9ec865d920503a1516947cae71>)
- Fecha del informe (UTC): 2026-11-09T20:35:00.011Z
- Release publicada: [v0.1.0](<https://github.com/lucioduran/webgpu-local-inference/releases/tag/v0.1.0>) · 2026-11-09T20:39:55Z
- [Informe original de ejecución del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-1794256500335.json>) SHA-256: ` 47edab939f5456ab523926069cf0e2ae462df7015f8ad9516bb299a945bd40cd `
- [Resumen derivado de tiempos del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/summary.json>) SHA-256: ` 2427850504700de4d00e6d53f73649fc1c4fa88d52ddeae7b5369bc46a2390ec `
- [Modelo clasificador incluido](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/public/model.json>) SHA-256: ` 4c92113f9dc216f16da3052b22520e7296058727be907f9246bc67eca364960b `
- [Casos de entrenamiento y evaluación](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/data/fixtures.json>) SHA-256: ` e1575dfcf3fcaacb6fdf853ae9382cbea8fcc990f0a727822a4d198eaf03adbd `

- [README y reproducción en el navegador](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/README.md>)
- [Informe original de ejecución del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-1794256500335.json>)
- [Resumen derivado de tiempos del navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/summary.json>)
- [Inventario del equipo físico](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/hardware.json>)
- [Tiempos y procedencia de la ejecución](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/run-provenance.md>)
- [Licencia MIT](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/LICENSE>)
- [Diseño de motores y caché](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/docs/design.md>)
- [Protocolo de navegador congelado](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/docs/protocol.md>)
- [Casos de entrenamiento y evaluación](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/data/fixtures.json>)
- [Modelo clasificador incluido](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/public/model.json>)
- [Hashes del modelo y los núcleos](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/public/manifest.json>)
- [Hashes del código medido en el navegador](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-source-manifest.json>)
- [Núcleo en texto WebAssembly](<https://github.com/lucioduran/webgpu-local-inference/blob/7279202a64b6a047ca5f2ad88efd0360e876b333/src/kernel.wat>)
- [Resultados registrados de pruebas de Node](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/node-tests.txt>)
- [Fallo inicial de conexión conservado](<https://raw.githubusercontent.com/lucioduran/webgpu-local-inference/7279202a64b6a047ca5f2ad88efd0360e876b333/evidence/browser-blocker.json>)
