123个Star,4次Fork,这个数字在GitHub上不算显眼。但点进Live Demo的人会发现,一个1024维的向量搜索任务,在浏览器里跑出了接近原生的速度。
这是TurboQuant-WASM——Google Research一篇ICLR 2026论文的浏览器移植版。开发者teamchong用Zig重写,再编译成WASM,最后塞进npm包。整个链条的终点,是你在Chrome里跑向量量化,压缩率约6倍,批量点积查询比单条循环快83倍。
从论文到浏览器,中间隔着多少坑
向量量化(Vector Quantization,VQ)不是新东西。把高维浮点数压缩成低维表示,省空间、加速检索,这是推荐系统和RAG(检索增强生成)的基建。但学术界的东西进浏览器,通常要脱层皮。
原论文TurboQuant的核心卖点是"在线量化"——流式数据进来,边学边压,不需要预训练码本。这对边缘场景很友好,但论文里的实现是Zig原生代码,依赖SIMD指令集。浏览器没有AVX-512,甚至连稳定的SIMD支持都是近年才补齐。
teamchong的解法分三层:先用Zig的relaxed SIMD做数学运算,@mulAdd直接映射到f32x4.relaxed_madd;再把QJL(一种随机投影签名算法)的打包解包逻辑向量化;最后用TypeScript包一层皮,暴露init/encode/decode/dot四个方法。
relaxed SIMD是关键妥协。标准WASM SIMD要求严格的IEEE 754精度,relaxed SIMD允许硬件用更快的指令,比如把乘加融合(FMA)做成单条指令。代价是结果可能因CPU而异,但向量量化本身对微小误差有容忍度——论文里的distortion bound保证了这点。
6倍压缩是怎么算的
看代码里的参数:dim=1024,输出compressed是Uint8Array。约4.5 bits/dim的压缩率,算下来每个原始float32(32比特)被压到4.5比特,压缩比7.1倍。但官方README写的是"~6x compression",取的是保守估计,留足安全边际。
实际调用链很干净:TurboQuant.init()做一次性初始化,seed固定随机投影矩阵;encode把Float32Array转成压缩字节流;decode还原;dot和dotBatch做相似度计算,后者把一批压缩向量concatenate后一次性送进WASM,避免JS-WASM边界往返。
83倍加速来自批量接口的设计。单条dot()每次都要跨边界调用WASM,dotBatch()把N个向量拼成一块内存,一次调用返回全部得分。这是边缘计算的经典trade-off:省带宽(压缩)换延迟,再用批处理摊平调用开销。
浏览器兼容性写在明处:需要支持relaxed SIMD的WASM引擎。Chrome 119+、Firefox 120+、Safari 17+都达标,但旧版浏览器会直接抛异常。这是技术选型时的清醒切割——不追求全覆盖,先拿下能跑的场景。
谁需要浏览器里的向量量化
Demo里放了三个场景:向量搜索、图像相似度、3D高斯泼溅(Gaussian Splatting)压缩。前两个是RAG和视觉搜索的标准用例,第三个更微妙——3DGS的显存占用是落地瓶颈,浏览器端压缩能缓解WebGL纹理压力。
一个具体的想象:你在做一个摄影社区,用户上传照片后自动找相似风格。传统做法是把特征向量传回服务器,现在可以浏览器里算完,只传压缩后的字节。6倍压缩意味着带宽成本打六折,或者同样带宽下多传6倍数据。
但限制也很硬。TurboQuant是在线算法,适合流式场景,不适合已经固化的海量索引。如果你的向量库是静态的、预先算好的,用传统PQ(Product Quantization)或HNSW索引会更省。换句话说,这是为"边来边压"设计的工具,不是万能药。
build.zig.zon文件暴露了依赖:基于botirk38/turboquant的Zig实现,用golden-value tests保证字节级一致。测试命令是zig test -target aarch64-macos,跨平台编译的野心写在配置里。
Zig+WASM的组合为什么值得看
选Zig而不是Rust或C++,是个值得品味的决定。Zig的编译时计算和显式内存控制,对WASM这种资源受限目标很友好。build脚本里bun run build:zig直接调Zig编译器,再用wasm-opt做二进制优化,最后用bun+TypeScript打包——整个工具链没有Webpack或Rollup的臃肿。
relaxed SIMD的启用需要显式配置,Zig的@mulAdd内置函数正好映射到这条指令。对比Rust的std::simd,Zig的底层控制更直接,代价是安全边界更薄。teamchong用golden-value tests兜底:同一组输入,Zig原生输出和WASM输出逐字节比对。
npm包的体积没写在README里,但嵌入base64编码的WASM是常规操作。预估在100KB-300KB区间,对现代Web应用可接受,但移动端仍需斟酌。
API设计显露出产品经理思维:四个方法覆盖90%场景,destroy()显式释放内存,避免WASM堆的泄漏焦虑。没有暴露底层的投影矩阵,seed参数固定随机性,降低误用风险。
GitHub页面的4个Fork里,有一个是fork到本地后改target为x86_64的尝试——社区已经开始魔改。但relaxed SIMD的指令集差异意味着,aarch64和x86_64的WASM二进制不能混用,这是移植时必须吞下的苦果。
论文的distortion bound保证了量化误差可控,但浏览器里的浮点行为本身就有平台差异。teamchong的测试矩阵覆盖了多少组合,README没提。这是开源项目的常见诚实:核心功能verified,边缘情况留待社区踩坑。
如果向量搜索的延迟能从百毫秒压到十毫秒,RAG应用的用户体验会跨过一道门槛。TurboQuant-WASM没承诺这个,但它把Google Research的算法变成了npm install就能试的东西——中间隔着Zig编译器、WASM SIMD规范和83倍加速的批量接口,这些细节堆起来,就是学术到工程的完整距离。
下一个问题是:当你的用户上传第100万张图片时,浏览器里的在线量化,和服务器端的预建索引,哪个会先摸到天花板?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.