Web 前端架构师技能体系 · 第29课:Browser AI — WebGPU、WebNN 与 ONNX Runtime Web
今日主题
让 AI 模型直接在浏览器中运行——WebGPU、WebNN 和 ONNX Runtime Web 的架构选型与实践
为什么这项技能重要
前端架构师正在从"构建 UI"向"构建智能体验"转型。当 AI 推理跑在浏览器端时:
- 隐私优先:用户数据不出本地,无需上传到服务器
- 零延迟:推理响应在毫秒级,没有网络往返
- 无限扩展:推理成本由用户设备承担,服务端零压力
- 离线可用:模型预加载后完全离线运行
Meta 的 Llama.cpp Web 版、Google 的 TensorFlow.js、微软的 ONNX Runtime Web 都在推动这个方向。Figma 已将部分 AI 功能迁移到浏览器端推理。不适用的场景:超大模型(参数量 > 7B 的模型仍需服务端 GPU)。
核心原理(通俗易懂版)
浏览器运行 AI 模型就像给浏览器装了一个"微型深度学习引擎"。传统上浏览器只能处理图形和文本,现在通过新 API 可以直接执行张量运算。
三个关键角色:
- WebGPU:浏览器的 GPU 计算接口。类比:它是浏览器版的 Vulkan/DirectX,让 JS 代码能指挥显卡做矩阵乘法这种重活。
- WebNN:浏览器的神经网络专用 API。类比:WebGPU 是通用 GPU 计算器,WebNN 是专门给神经网络优化的"高速公路"——浏览器厂商可以针对卷积、注意力等常见算子做底层优化。
- ONNX Runtime Web:跨框架推理引擎。类比:ONNX 是 AI 模型的"通用语言",ORT Web 就是翻译器——你把 PyTorch/TF 导出的 ONNX 模型扔给它,它在浏览器里用 WebGPU 或 WebAssembly 跑起来。
`mermaid
graph LR
A[训练框架<br/>PyTorch/TF/JAX] -->|导出 ONNX| B[ONNX 模型文件]
B --> C{ONNX Runtime Web}
C -->|GPU 加速| D[WebGPU Backend]
C -->|CPU 回退| E[WebAssembly Backend]
D --> F[浏览器 GPU]
E --> G[浏览器 CPU]
`
选择逻辑很简单:有 WebGPU 就用 WebGPU(快 10-100 倍),没有就回退到 WebAssembly(兼容一切)。
企业级最佳实践
生产环境典型用法:- 图像分类/目标检测:YOLO-Nano、MobileNet 部署到浏览器端做实时检测
- 语音识别:Whisper.cpp 的 Web 版实现离线语音转文字
- 文本嵌入:BGE-small 在浏览器端做语义搜索,无需后端
- 模型体积过大导致首屏加载慢——用 INT8 量化,模型体积缩小 4 倍,精度损失通常 < 2%
- WebGPU 兼容性——Safari 17+ 和 Chrome 113+ 支持,老旧设备回退 WA 会慢 5-10 倍
- 内存管理——浏览器端内存有限(通常 2-4GB),大模型需要分片加载或用 Streaming
- 模型量化:FP32 → FP16 → INT8,逐级压缩
- 算子融合:将多个小算子合并为一个大算子,减少内核启动开销
- 懒加载:先加载模型结构,用户交互时再加载权重
示例代码
`typescript
// Browser-side AI inference with ONNX Runtime Web + WebGPU
import * as ort from 'onnxruntime-web';
// 1. 配置推理会话:优先 WebGPU,回退 WebAssembly
ort.env.wasm.numThreads = 2; // WASM 回退时的线程数
const sessionOptions: ort.SessionOptions = {
executionProviders: ['webgpu', 'wasm'], // 自动选择最快后端
graphOptimizationLevel: 'all', // 启用算子融合
};
// 2. 加载并运行模型
async function runInference(modelUrl: string, inputData: Float32Array) {
// 创建推理会话(首次加载可能需 2-5 秒)
const session = await ort.InferenceSession.create(modelUrl, sessionOptions);
// 准备输入张量:[batch_size, channels, height, width]
const inputTensor = new ort.Tensor('float32', inputData, [1, 3, 224, 224]);
// 构建输入映射
const feeds = { [session.inputNames[0]]: inputTensor };
// 执行推理
const results = await session.run(feeds);
// 解析输出:取概率最高的类别
const output = results[session.outputNames[0]].data as Float32Array;
const predictedClass = Array.from(output).indexOf(Math.max(...output));
const confidence = output[predictedClass];
console.log(预测类别: ${predictedClass}, 置信度: ${(confidence * 100).toFixed(1)}%);
return { predictedClass, confidence };
}
// 3. 检测 WebGPU 支持(优雅降级)
function isWebGPUSupported(): boolean {
return typeof navigator !== 'undefined' &&
'gpu' in navigator &&
!!navigator.gpu;
}
// 使用示例:加载 MobileNet 做图像分类
if (isWebGPUSupported()) {
console.log('✅ WebGPU 可用,将获得最佳推理性能');
} else {
console.log('⚠️ WebGPU 不可用,将使用 WebAssembly 回退');
}
`
学习路径建议
- 入门:ONNX Runtime Web 官方文档(onnxruntime.ai)、WebGPU 规范(gpuweb.github.io)
- 进阶:阅读 ONNX Runtime Web 源码(GitHub onnxruntime/web),理解 WebGPU compute shader 如何映射到张量运算
- 实践:用 PyTorch 训练一个 MobileNet 图像分类器 → 导出 ONNX → 在浏览器端跑起来做实时摄像头识别
今日思考题
假设你要为一个医疗影像筛查 App 设计架构,需要在浏览器端运行一个 50MB 的 UNet 分割模型。用户平均网络速度 10Mbps,设备内存 4GB。你会如何设计模型的加载策略、推理管线和降级方案?请给出 Trade-off 分析。
明日预告
第30课:AI 辅助开发——Copilot、Cursor、Claude Code 的最佳实践与工作流整合