ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

浏览器端侧视觉AI实战:从WebGPU到TensorFlow.js的工程指南

浏览器端侧视觉AI实战:从WebGPU到TensorFlow.js的工程指南 端侧视觉 AI 聊了这么多年一直有个很反直觉的场景让我着迷把所有神经网络推理都塞进一个浏览器标签页。不装客户端、不调后端GPU、不传用户视频到服务器就在 Chrome 或 Edge 的标签页里完成图像分类、人脸检测、姿态估计这些任务。听起来像是炫技但真做完一个项目你会发现这不是炫技而是一套完全不同的工程约束——内存、带宽、算力、兼容性全都要重新算账。这篇文章就把我在这条路上攒下的工程真相写清楚包括为什么这么做、技术上靠什么撑住、实操时会遇到哪些坑以及一些可以抄作业的代码和配置。先说清楚“能做什么”它解决的是视觉 AI 在隐私敏感、弱网环境、以及低成本部署场景下的推理问题。摄像头画面不上传推理在浏览器本地完成这让很多医疗、工业巡检、在线教育场景变得可行。适合谁看适合那些想把模型跑在 Web 端、正在权衡 TensorFlow.js、ONNX Runtime Web 或 WebGPU 方案的开发者也适合纯粹好奇“浏览器到底能干多少AI活”的同行。1. 从“云端”到“标签页”为什么非要在浏览器里跑神经网络1.1 端侧推理的刚需做 AI 应用的都明白云端推理有天然优势模型随便大GPU 随便租代码更新不用用户管。但真落到产品层面痛点也极其具体。第一个是延迟和带宽比如人脸识别考勤机一次推理如果还要上传到云端、排队、返回结果在园区弱网环境下经常出现几秒的空白期这不可接受。要是做成浏览器本地推理从摄像头取帧到画框显示结果延迟能压到几十毫秒体验完全不是一个量级。第二个是隐私合规。这几年大家被隐私政策教育得比较到位用户面对“摄像头画面传到服务器”这种事越来越敏感。医疗影像、身份核验、企业内部员工行为分析这类数据一旦出本地就要签一堆合规协议审计成本极高。而浏览器内推理能做到“数据不出标签页”模型文件本身在本地运行整个生命周期里用户数字图像从未进入网络流。这个卖点在做 To B 方案时几乎是决定性的。第三个是部署成本。一个纯前端工程不需要申请服务器 GPU、不需要运维推理服务、不需要担心并发暴增把推理集群打崩。模型作为静态资源挂在 CDN 上用户打开页面自动加载更新模型只需要换文件。我见过不少团队把后端推理服务砍掉省下了每个月的云账单还顺手把首屏启动速度提了上来——因为某些场景下模型加载比云端握手还快。1.2 浏览器凭什么能跑神经网络浏览器这个运行时以前大家觉得它只能跑跑 DOM 操作和视觉稿还原但仔细拆解它这几年的底子已经厚到可以承载正经的神经网络推理。首先是计算能力。WebGL 2.0 可以在 GPU 上跑通用计算通过纹理采样做矩阵乘加WebGPU 更是直接暴露了现代 GPU 的计算管线compute shader 跑卷积简直是降维打击。再加上 WebAssembly 把 C 写的算子编译成 WASM 字节码CPU 上的性能也接近原生水平。我实测过一些旧笔记本上的 WebGL 推理速度能达到 CPU 推理的数倍而 WebGPU 在新型号 MacBook 和 Windows 独显机器上还能再翻几番。其次是内存模型。现代浏览器对 ArrayBuffer、SharedArrayBuffer 和 WebAssembly 内存的管理已经相当成熟。神经网络权重可以不做任何转码直接映射成 Float32Array 传给 GPU buffer训练好的模型文件本身也能被离线缓存Cache API。这意味着你可以像做原生 App 一样管理模型版本、做增量加载、做本地持久化而不需要重新发明轮子。最后是生态。TensorFlow.js、ONNX Runtime Web、Transformers.js、MediaPipe Tasks Vision 这些库把“从模型到 API”的门槛压得很低。哪怕你对底层 GPU 编程一窍不通也能用十几行代码跑起一个 MobileNet。但要真把性能压榨到极致还是得理解引擎下面的调度逻辑。所以说浏览器跑神经网络不是“能不能”的问题而是“怎么在工程预算内跑得又快又稳”的问题。2. 撑起端侧视觉 AI 的三大引擎WebGL、WebGPU 与 WASM2.1 算力从哪来不只是显卡的功劳很多人一听到浏览器跑 AI 就想到“调 GPU”其实完整算力结构是三层的。第一层是 CPU WASM。后端框架会提供纯 CPU 的实现算子用 C 写成编译成 WASM 后由浏览器的 JS 胶水层调度。这种方案的优点是兼容性最广任何现代浏览器都能跑缺点是速度一般对于大模型或者高分辨率图像通常只能勉强实时。适合做初始化、回退方案或者跑那些对帧率不敏感的模型。第二层是 WebGL 纹理计算。把张量数据塞进 2D 纹理的 RGBA 通道通过 fragment shader 实现矩阵乘法和卷积。这个思路听起来很绕但实践中非常成熟——TensorFlow.js 的 WebGL backend 就是这么做的。它利用了 GPU 的并行性但受限于纹理数量、像素格式和着色器的复杂度还是有些委屈。精度上也只能用 float32 转 texture 的技巧模拟稍不留神就丢精度。不过作为兼容性最好的 GPU 方案WebGL 目前依然是端侧视觉 AI 的主力。第三层是 WebGPU compute shader。这是相对正统的 GPGPU 方案直接调度 GPU 的 compute units没有纹理转换的奇技淫巧代码写起来也更接近 CUDA。WebGPU 的优势是性能稳定、内存管理可控、精度好缺点也很明显Chrome 已经支持Safari 在较新版本里也跟上了但老浏览器和老系统尤其是 Windows 7 和 macOS 10.x 全家桶依旧无缘。如果你做的是内部工具可以大胆用 WebGPU如果发布公网产品最好还是保留 WebGL 回退。2.2 内存与显存浏览器里最被低估的瓶颈神经网络在 GPU 上要占显存。浏览器标签页不是独立进程吗它是独立进程但显存可不给你单独隔离。一个网页能拿到的 GPU 资源上限取决于操作系统和浏览器的调度策略最常见的结局就是推理刚开始标签页黑屏控制台报 “Context Lost”因为显存分配失败被系统回收。我在实际项目中做过一次粗糙的估算MobileNetV3 224x224 输入float32 权重大约 10MB中间激活值在 batch 为 1 时可能也要几十 MB 峰值。这个体量在 4GB 显存的老机器上尚可但如果同时开一堆标签页系统随时可能把你的 WebGL context 干掉。更麻烦的是浏览器对显存占用不透明你无法像原生一样用 API 查询“当前剩余显存”只能靠经验和保守策略来规避。内存侧的坑也很多。TensorFlow.js 默认会缓存中间 tensor 以减少重复计算但如果你在循环里反复创建 tensor 而不调用 dispose内存会像漏水的桶一样涨上去。这是新手最容易踩的坑——你以为只是 JS 对象没释放其实是 GPU 显存和 CPU ArrayBuffer 都漏了。后面我会单开一节说怎么排查。2.3 模型格式从 PyTorch 到浏览器的变形记训练生态里大家都用 PyTorch 和 TensorFlow但浏览器要的模型格式是另一套。主流的落地路径有这么几条。PyTorch 模型通常导出为 ONNX再用 ONNX Runtime Web 加载。这是目前兼容性和算子覆盖度最平衡的方案。ONNX Runtime Web 底层可以用 WASM 或 WebGL 甚至 WebGPU 执行一般的卷积、池化、全连接、归一化都能覆盖。我自己的经验是把 PyTorch 的模型 export 成 ONNX 时要注意这么几件事动态轴要显式指定比如 batch 维用 batch 而不是固定 1很多训练时的小算子比如自定义 F.grid_sample在导出时可能不支持需要先重写成标准算子还有 BN 层和 Dropout 层必须设成 eval 模式后再 export否则推理结果准不了。TensorFlow 模型则可以直接转成 tfjs_graph_model或者 tfjs_layers_modelTensorFlow.js 加载后直接用。这个路径的好处是省事TensorFlow 官方维护转换脚本而且 TF Hub 上大量现成模型可以直接转。缺点是对 TF 版本的 sticky转换器版本和模型架构版本不匹配会给你一堆警告甚至直接转换失败。还有一条路是纯 WASM 的推理库比如 ncnn 的 WASM 版、Tengine 的 Web 版。如果你用的是专门为移动端优化的模型结构比如 YOLOv5 的 C 实现可以编译成 WASM性能很猛但工程成本高你还得自己管理输入输出张量的内存。事实上我现在更推荐一个“混合策略”把模型统一转成 ONNX用 ONNX Runtime Web 的 WebGPU execution provider 跑当 WebGPU 不可用时自动 fallback 到 WASM。这样可以最大化性能和兼容性的平衡代码量也不大。3. 实操把 CNN 分类模型塞进 Chrome 的完整流程3.1 模型选型MobileNet、EfficientNet 还是更小的家伙浏览器端做视觉 AI模型就是你的预算表。要考虑三个维度精度、体积、推理耗时。MobileNetV3-Small 是我在大部分项目里的默认选择224x224 输入70 多个算子权重只有 4MB 左右在普通笔记本 CPU 上跑一次分类大约 30 到 80 毫秒在 WebGL 上能压到 10 到 20 毫秒。对于通用分类、是否包含某个物体的二分类场景足够用了。EfficientNet-Lite0 也算合适精度略高但权重大概 6MB推理耗时也上浮一些。如果你的场景是低分辨率小目标检测你甚至可以选 MobileNetV1 作为骨干再挂一个 YOLO 风格的检测头。记住一个原则在浏览器里推理耗时和权重体积是正相关的而且大模型不仅拖慢推理还会拖慢模型加载——别小看 2MB 的差距在弱网下可能是 3 秒和 6 秒的差别。既然提到“神经网络”这个词顺带说一句并不是所有视觉模型都适合端侧。像 ViTVision Transformer这种结构也不是不能跑但注意力矩阵在 224x224 下产生的中间张量非常大容易爆显存而且 WASM 上的矩阵乘性能远不如卷积优化到位。硬要跑 ViT 的话最好用蒸馏后的小型化版本如 DeiT-Tiny或者使用能支持稀疏注意力的专用框架。3.2 推理框架选型对比我做过一张对比表可以贴在项目 wiki 里框架后端模型格式优点缺点TensorFlow.jsWebGL/WASM/WebGPUtfjs model生态最全API 稳定社区教程多模型转换工具链偶尔有兼容问题多层 API 封装导致性能优化空间受限ONNX Runtime WebWASM/WebGL/WebGPUONNX跨框架PyTorch 生态直接对接算子覆盖全面WebGPU API 还带些实验性不同 ep 之间的行为差异需要适配Transformers.jsWASM/WebGPUONNX面向 NLP/多模态视觉模型也能跑专注于 Transformers传统 CNN 支持不如前两个MediaPipe Tasks VisionWASM.task 模型人脸、姿态、手势检测开箱即用内置追踪优化模型固定不容易自定义结构task 模型格式不开放到自由训练自编译 WASMncnn 等WASM自定义性能极致可深度定制工程复杂度高需要原生开发经验不易维护就端侧视觉 AI 而言我的建议是如果做通用分类推荐 TensorFlow.js如果做目标检测/分割且模型从 PyTorch 转出首选 ONNX Runtime Web如果做极致优化的定制模型直接去折腾自编译 WASM 吧能学到不少但注定是个坑。注意MediaPipe 在“人脸关键点检测”这些细分任务上极其好用但它的模型难以替换不适合必须自己训练的严肃项目。3.3 实操一个 WebGPU 推理的最小代码骨架这里给一个基于 ONNX Runtime Web 的完整示例它跑在 WebGPU backend 上同时允许 fallback 到 WASM。假设你已经把模型转成了 model.onnx输入是 224x224 的 RGB 图像输出是 10 个分类的 logits。先创建整个工程的基本入口// 简单封装用来将 HTMLVideoElement / img 转换为 tensor 输入的 JPEG 流程 import * as ort from onnxruntime-web; // 使用 webgpu 作为优先执行后端不可用时动态回退 let session; async function initSession(modelPath) { const ep await checkWebGPU(); const options { executionProviders: ep ? [webgpu, wasm] : [wasm], graphOptimizationLevel: all, }; session await ort.InferenceSession.create(modelPath, options); } async function checkWebGPU() { if (typeof navigator undefined || !navigator.gpu) return false; try { const adapter await navigator.gpu.requestAdapter(); return adapter ? true : false; } catch (e) { return false; } } // 图像预处理函数canvas - normalized tensor function preprocessImage(img, width 224, height 224) { const canvas document.createElement(canvas); canvas.width width; canvas.height height; const ctx canvas.getContext(2d, { willReadFrequently: true }); ctx.drawImage(img, 0, 0, width, height); const imageData ctx.getImageData(0, 0, width, height); const data imageData.data; const pixels new Float32Array(1 * 3 * height * width); for (let i 0; i data.length; i 4) { const pixelIndex i / 4; const r data[i]; const g data[i 1]; const b data[i 2]; const offset pixelIndex; pixels[offset] (r / 255 - 0.485) / 0.229; pixels[width * height offset] (g / 255 - 0.456) / 0.224; pixels[2 * width * height offset] (b / 255 - 0.406) / 0.225; } return new ort.Tensor(float32, pixels, [1, 3, height, width]); } async function runInference(img) { const inputTensor preprocessImage(img); const feeds { input: inputTensor }; const results await session.run(feeds); const output results[output]; return output.data; }代码里的几个细节值得注意。第一preprocessImage 里的 mean/std 要和训练时保持一致很多人只改 RGB 归一化不换 mean/std导致推理结果完全不对。第二ONNX Runtime Web 的输入名这里是 input和输出名output必须和导出的图匹配可以用 netron 查看模型结构别硬猜。第三canvas.getContext(2d, { willReadFrequently: true })这个参数很重要它告诉浏览器我们频繁读取像素避免它走 GPU 加速读回路径导致的性能抖动。跑起来之后你可以继续观察 performance panel。如果发现 WebGPU 后端反复创建 session 或者每一帧都重新初始化那就成大问题了。session 创建很昂贵千万不要放在实时路径里务必做成单例。3.4 性能调优的核心指标我在浏览器里验证模型性能时不看单纯的“推理毫秒数”而是看端到端流水线的耗时。完整的视觉推理管道通常有四段图像采集摄像头/视频/图片解码、预处理缩放、归一化、通道变换、模型推理、后处理阈值过滤、NMS、绘制框。其中预处理尤其容易被忽略——很多人用 canvas 做 resize 和 pixel 读取这一步在每帧都跑时非常消耗 CPU最终导致帧率上不去。要提速可以把预处理搬到 GPU 或者使用 offscreenCanvas WebGL 的方式做 resize。此外尽量复用 tensor buffer避免每帧 new 一个 Tensor。ONNX Runtime Web 允许你通过ort.Tensor的data属性复用底层 buffer但要注意不要和正在进行的异步推理冲突。另一个性能杀手是 NMS非极大值抑制。YOLO 输出的候选框很多如果用纯 JS 写 NMS 的嵌套循环在 1080p 图像上可能耗时数十毫秒比推理本身还慢。解决方式通常有两个一是把 NMS 也做成一个模型里的自定义算子编译到 WASM二是在 JS 里用 vectorized 排序和简化循环。我实测过将 NMS 逻辑改为 typed array 配合预先排序后的线性扫描可以减少 70% 的时间。4. 视觉任务在浏览器里的真实体验检测、姿态与分割4.1 人脸关键点与姿态估计MediaPipe 的魔法浏览器端做视觉 AI 最成熟的应用恐怕就是人脸关键点和姿态估计了。MediaPipe Tasks Vision 里的 FaceLandmarker 和 PoseLandmarker 做得极其顺手模型经过量化后都很小面部模型大约 3MB姿态模型大约 8MB且自带追踪和 smoothing。用起来核心逻辑就是加载模型、传入 VideoFrame、得到 landmarks 并绘制。我自己在做一款远程健身产品时用过 PoseLandmarker印象最深的是它在 CPU 上的表现即使不用 WebGPU单帧 256x256 的姿态估计在普通笔记本上也能跑到 30FPS这得益于 MediaPipe 的 TFLite 模型和 WASM 运算的高度优化。当然你要清楚它内部用的是 TFLite 而非 ONNX所以别指望把自定义 PyTorch 模型塞进去。另外一个坑是 MediaPipe 的 Tasks API 在 Safari 上的视频帧摄入有时会丢关键帧你要手动做帧率控制和丢帧重试。人脸检测方面除了 MediaPipe你还可以用 TensorFlow.js 的 FaceDetector它内部是 BlazeFace 模型也能跑出不错的效果。但说实话如果只是要关键点而不是做质量评估MediaPipe 的稳定性和关键点平滑都更好不推荐自己造轮子。4.2 实时视频流里的帧率焦虑浏览器端做视频分析通常不是做单帧推理而是对连续的视频流做逐帧或跳帧推理。这时候帧率焦虑就来了。首选要搞清楚你的瓶颈在哪个环节。我常用一个简单方法打开 Chrome DevTools 的 Performance 面板录制几秒钟看看主线程被哪个任务占满。如果是推理任务占满那需要升级后端比如从 WASM 切到 WebGPU如果是 drawImage/canvas 操作占满那就是图像缩放和像素读取太频繁可以用离屏 Canvas 做缓存如果是 postMessage 占满说明你用了多个 worker 做并行但数据拷贝量太大。经验上视频流里的稳定帧率策略是“跳帧推理”。姿态估计一般不需要每帧都跑人体姿态在 30FPS 视频里连续两帧差异很小。我一般把推理频率控制在 15FPS视觉结果用插值/阻尼平滑算法补间形成平滑的动画效果。这样既保住了流畅度又大幅降低计算负载。这个思路在浏览器场景特别重要因为浏览器标签页资源是共享的你不可能为了视觉分析把所有标签页都拖死。还有一点如果页面上有两个模型串联比如先检测人脸框再对每个框做关键点或表情分类千万不要串行做。理想方式是先用一个快速检测器找到所有目标区域然后只对区域里的子图做精细分析。但如果目标数量不限而且区域重叠严重就要考虑调度策略限制最多处理的目标数并对已识别目标做时间分层隔几帧做一次精细分析。4.3 跨浏览器兼容性矩阵别再只知道 Chrome很多项目自始至终只在 Chrome 上测试等真上线用户反馈才发现“Safari 怎么这么卡”“Firefox 怎么画不出框”。不同浏览器对待 WebGL、WebGPU 和 WASM 的差异比想象大得多。先说 WebGPU。Chrome 111 开始默认支持Edge 对应版本也支持Firefox 还在实验状态需要手动开启Safari 在 16.4 稳定支持但不少 API 细节实现得很怪比如 computePass 的 encoding 有损坏问题需要打补丁。所以现在做公网产品必须提供备选路径。WebGL 2.0 的兼容性则好得多几乎所有现代浏览器都支持但注意部分老 GPU 对浮点纹理OES_texture_float的支持有阉割TensorFlow.js 会自动检测并 fallback但性能会下降。我在某台老 ThinkPad 上遇到过 WebGL 能初始化但纹理尺寸超过 4096 就黑屏的问题最后只能限制输入分辨率。最后是老生常谈的内存占用问题Safari 对标签页的 GPU 内存限制非常激进经常在运行大模型时被系统杀进程重启标签页后一切重来。对策是建立模型加载进度提醒并在关键节点做状态保存比如记录用户已完成的检测结果崩溃后快速恢复。这件事在商业项目里非常关键。5. 工程排雷我在端侧视觉 AI 项目里踩过的 12 个坑5.1 问题与排查速查表这里整理一份高频问题清单都是我自己在项目里实际碰到、并确认原因的现象根因解决思路页面加载模型后直接崩溃显存不足WebGL context lost降分辨率改用 WASM 后端用 Cache API 做模型分段加载推理结果全为均值输入归一化方式与训练不一致检查 mean/std 顺序检查 NCHW 与 NHWC 顺序摄像头视频无法传给模型摄像头帧被 canvas taint确保图片源同源或使用 CORS 标记不要对跨域画布做 getImageDataSafari 上 WebGPU session 偶尔丢失Safari 的 WebGPU 实现 bug 或资源回收监听 GPUDevice lost 事件并重建 session回到 WebGL/ wasm第一帧推理耗时极慢首次编译 shader 或 session warm-up启动后立即用占位输入跑一次推理做好骨架屏CPU 占用飙高主线程同时处理 video、canvas、推理把视频帧获取和推理放 web worker避免阻塞渲染模型加载超时大文件 并发连接限制使用 signed URL 断点续传或拆成分片模型WASM 后端的表现远差于 WebGL没有关闭多线程支持确保服务器返回 SharedArrayBuffer 的跨源隔离头开启多线程 WASM每个问题都对应一个“如果早点知道就好了”的教训。拿“第一帧推理极慢”来说几乎所有团队都会遇到。其实你可以在页面加载完成后立刻用一个 1x1 的占位 tensor 跑一次空推理让引擎完成 shader 编译和内核预热之后真实推理的速度就能上去。这个预热动作甚至比调优后端配置都要有效。5.2 内存泄漏看似小问题实则为大事故浏览器里的 JS 内存泄漏大家都有意识但 GPU 内存泄漏几乎不可见直到它导致整页崩溃。最常见的原因是 TensorFlow.js 或者 ONNX Runtime Web 的中间 tensor 没被 dispose。我推荐在开发阶段开启严格清理模式比如把每次 session.run 的结果里的中间变量全部记下用完即调tensor.dispose()。同时定期用performance.memoryChrome 支持监控 JS 堆大小虽然不能直接反映 GPU 内存但如果堆一直在涨通常显存也在涨。更有效的办法是给循环推理加一个“每 N 帧强制清除缓存”的保险丝比如每次推理后总调ort.env.webgpu?.freePendingResources?.()或对应后端的清缓存方法防止隐性张量累积。还有个现象某些浏览器的 WebGL context 丢失后不会自动恢复。你需要在 canvas 上监听webglcontextlost事件在事件里阻止默认行为并做好重建准备否则用户就是白屏只能刷新。这也是我为什么把 session 创建封装成initSession函数并且暴露一个重建入口——用于随时被调用。5.3 跨浏览器差异的实战心得做浏览器端视觉 AI我养成了一个习惯不把一个浏览器当作唯一基准。项目启动时就定下三个目标环境Chrome 最新版主力、Edge 最新版因为内核相同但 GPU 调度可能有差异、Safari 15最麻烦但用户不可能放弃。Firefox 作为 bonus能跑就行不做过高要求。在 Safari 上最经典的问题是对OffscreenCanvas支持不完整还有一些视频帧 API 的限制。如果遇到 Safari 拿不到视频帧常用的 workaround 是改用隐藏 video 元素配合setTimeout和绘制到一个小尺寸 canvas不要用requestVideoFrameCallbackSafari 不支持。这个月初我为了修一个 iPad 上的白屏就是把所有 GPU 后端强制切换为 WASM才让问题消失。所以很多时候回退不是丢人而是成熟产品的必选项。5.4 安全与性能的平衡模型文件保护认真做的项目都会关注模型权重是否容易被窃取。浏览器端模型基本是公开的就算你混淆了 JS模型文件依然能被人下载下来所以很多团队选择把模型整体加密运行时解密到内存。但加密解密的开销不容小觑尤其是大模型。我的建议是如果模型价值很高可以在服务端做一道鉴权返回一个短期有效的模型 URL同时用 wasm 封装推理逻辑并对权重做一次轻量 XOR 加密——这不防专业 hacker但能挡住 90% 的随手抓包。加密必然带来冷启动变慢所以将权重拆成多个 chunk 并按需加载是更好的平衡。比如一个 20MB 的模型先加载 3MB 的骨干网络输出粗结果再按用户行为懒加载后续的 deeplayer。这种“渐进式模型加载”很符合浏览器的交互节奏。6. 几个从实战里悟出来的经验之谈说了这么多坑最后再分享几条我个人的体会。第一浏览器端视觉 AI 不是把模型从服务器搬到前端那么单纯。整套工程的性能观、资源观、降级策略都要重写。以前部署到云端时我把模型当服务来治理现在部署到标签页里我把模型当“前端资源包”来治理有版本号、有增量更新、有加载失败检测、有资源回收策略。第二别一上来就追求“最酷”的模型架构。有时候一个 MobileNet 二分类就能解决的场景根本没必上大模型。我见过太多团队为了炫技术把一个复杂模型塞进页面结果内存爆炸、帧率崩盘最后回到轻量模型反而口碑爆棚。端侧 AI 的精髓永远是“精准的轻”。第三始终给用户一个保底体验。我做的每个视觉功能最后都会加一个“云端推理”的后备开关一旦本地推理失败或者用户设备太老旧就提示一键切换到云端模式。这个开关初看很蠢但它能救回大量边缘用户。要知道浏览器环境太碎片化了随便一个老 Windows、老 iOS WebView 都会让你的 WebGPU 美好幻想破灭。第四工具链也要玩得熟练。ONNX、TFLite、Netron、Chrome DevTools 的 Memory/Performance 面板、WebGPU Inspector 插件这些你都要会用。调试端侧 AI 问题很多时候不是靠直觉而是靠“看内存”“看 CPU 火焰图”“看 GPU 调用栈”。如果把浏览器调试工具用得不了然你连问题在哪都找不到更别说优化了。这些经验不是从书上来的是踩了无数个夜里的坑换来的。现在每次打开 Chrome 标签页看到那个小猫发来的视频里实时画着检测框我依然会觉得神奇——神经网络跑在浏览器里这事从一开始就透着股不真实感但工程真相就是只要把资源、兼容性和降级策略想清楚它确实能成为生产环境里最省心的一环。希望这篇东西能让你少走点弯路至少在把神经网络塞进标签页的时候心里能少一点嘀咕多一点把握。
返回列表