网页也能跑大模型?

写在最前

本故事主要介绍在网页上部署模型的来龙去脉,你想问的问题,可能都可以在这里找到答案

在这个 AI 内容生成泛滥的时代,依然有一批人"傻傻"坚持原创,如果您能读到最后,还请点赞或收藏或关注支持下我呗,感谢 ( ̄︶ ̄)↗

能在网页上跑模型吗?

丹尼尔:嘿,蛋兄,你这是要去哪儿遛弯呢?

蛋先生:刚吃完饭,准备散下步消消食

丹尼尔:一起呗。蛋兄,我最近对 AI 有点着迷,突然冒出个念头,你说咱们能不能在网页上跑机器学习模型呢?

蛋先生:这个嘛,确实可以

为什么可以在网页上跑模型?

丹尼尔:这我就纳闷了,一个专门看网页的浏览器,怎么还能"兼职"跑模型呢?蛋兄,快给我讲讲呗

蛋先生:你想啊,一颗种子能不能发芽,得看它有没有适合生存的环境。模型也一样,得有个能跑的"土壤"------runtime,还得有足够的"阳光"和"水"------也就是算力和存储

丹尼尔:哦,我好像有点懂了。但我还是不明白,浏览器是怎么做到这一点的

蛋先生:自从浏览器有了 WebAssembly 之后,它的"胃口"可就大了去了!现在,很多用 C、C++、Rust 等编程语言写的应用,都能编译成 WASM 格式,在浏览器里跑。这样一来,浏览器就能处理更加复杂的计算任务了

丹尼尔:原来如此!也就是说,原来用 C++ 等写的模型 runtime,现在可以直接放进浏览器里,成了模型的"土壤"了!

蛋先生:对头!而且,浏览器的 WebGL、WebGPU 这些技术,还能让你的应用用上 GPU 资源,速度更上一层楼!否则,能跑,但很慢,也没啥意义

丹尼尔:哈哈,我总结一下啊,WebAssembly 让模型有了土壤,WebGL、WebGPU 让算力提升成为可能!

蛋先生:不错不错,总结得挺到位!

为什么要跑在浏览器呢?

蛋先生:那我问你,你为什么想把模型跑在浏览器上呢?

丹尼尔:额~,这~,就觉得挺酷的嘛!不过说实话,我还真没认真想过这个问题。蛋兄,你给说道说道?

蛋先生:来,咱们从请求链路说起。模型部署在浏览器上,是不是就不用请求服务器了?

丹尼尔:那是肯定的

蛋先生:对于客户端,请求没有离开用户设备,这样是不是就可以更好地保护用户隐私了?

丹尼尔:是哦

蛋先生:计算是在浏览器本地进行的,距离用户更近,也没有网络请求的损耗,响应速度通常更快,这样是不是就可以提升用户体验了?

丹尼尔:是哦

蛋先生:还有,模型已经部署在浏览器了,只要应用本身支持离线访问,那是不是就可以离线使用了?

丹尼尔:是哦

蛋先生:对于服务端,因为把计算压力分摊出去了,是不是就可以减轻服务器的计算压力,降低运营成本呢?

丹尼尔:是哦

蛋先生:剩下的你自己琢磨琢磨吧

怎么跑在浏览器呢?

丹尼尔:好嘞,那具体要怎么实现呢?

蛋先生:主流的机器学习框架除了训练模型外,还能部署和推理模型。比如大名鼎鼎的 Tensorflow 就有 tensorflow.js,它可以将模型部署在浏览器端。不过今天我要给你说的是 onnxruntime-web

丹尼尔:onnxruntime-web?这名字听着有点新鲜啊!

蛋先生:onnxruntime-web,可以把这个拆成 onnx,onnxruntime 和 onnxruntime-web 来说

丹尼尔:您继续

蛋先生:onnx 就是个模型格式,就像你存音乐用的 mp3 格式一样,但它存的是机器学习模型;onnxruntime 呢,就是运行这些模型的"播放器";而 onnxruntime-web,则是让这个"播放器"能在网页上跑起来的神奇工具

丹尼尔:哦,那模型都有哪些格式呢?用这个 onnx 有什么优势呢?

蛋先生:正所谓合久必分,分久必合

丹尼尔:这是要讲三国的节奏吗

蛋先生:各个机器学习框架都有自己的模型格式,在没有 onnx 之前,你得用 tf 来部署 tensorflow 的模型,用 pytorch 来部署 pytorch 的模型。可用户只想部署个模型而已,能不能把问题简单化呢?

丹尼尔:确实

蛋先生:于是就有了 onnx 这个开放标准。各家的模型格式都能转换成这种标准格式,然后你就可以用一个 onnxruntime 来部署和推理模型了!

丹尼尔:那这个 onnxruntime 是用什么实现的呢?

蛋先生:它是用 C++ 实现的,在浏览器运行时会被编译成 WASM 格式。然后 onnxruntime-web 提供了 JS API 来与 WASM 进行交互

丹尼尔:原来如此!那快给我看个代码示例吧,我都迫不及待了

蛋先生:以下是一个数字图像识别的简单例子,不过接口有点底层哦,你得懂点 tensor 之类的。希望以后有第三方库能封装个高级的接口,比如手写数字识别输入是图片,输出是数字;生成式 AI 输入是 prompt,输出是回答之类的。当然你也可以自己尝试尝试

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
    ...
  </head>
  <body>
    ...
    <canvas id="canvas" width="28" height="28" style="display: none"></canvas>

    <script>
      let imageData;

      ...

      async function runModel() {
        // 提取图像数据并规范化为模型的输入格式
        const input = new Float32Array(28 * 28);
        for (let i = 0; i < input.length; i++) {
          const r = imageData.data[i * 4];
          const g = imageData.data[i * 4 + 1];
          const b = imageData.data[i * 4 + 2];
          const gray = 0.299 * r + 0.587 * g + 0.114 * b; // 转换为灰度值
          input[i] = gray / 255.0; // 规范化到 0~1
        }
        const inputTensor = new ort.Tensor("float32", input, [1, 1, 28, 28]);

        // 使用 mnist-12.onnx 模型创建推理会话
        const session = await ort.InferenceSession.create(
          "https://media.githubusercontent.com/media/onnx/models/refs/heads/main/validated/vision/classification/mnist/model/mnist-12.onnx"
        );

        // 推理
        const results = await session.run({ Input3: inputTensor });
        const output = results.Plus214_Output_0.data;

        // 找到最大值(概率最大)的索引,即预测的数字
        const predictedDigit = output.indexOf(Math.max(...output));

        // 显示结果
        document.getElementById("output").innerText = predictedDigit;
      }

      ...
    </script>
  </body>
</html>

有什么限制?

丹尼尔:除了数字识别,还能玩点儿别的花样不?

蛋先生:那当然咯!语音识别、图像分类、对象检测,甚至生成式 AI,都不在话下!

丹尼尔:哇塞,连大语言模型都能搞定?

蛋先生:不过在浏览器上运行有些小小的限制

丹尼尔:让我来猜猜,是不是模型的大小有限制?

蛋先生:对头

丹尼尔:具体能多大呢?

蛋先生:首先我们得加载远程模型

各大浏览器对 ArrayBuffer 的大小都是有限制的,比如 Chrome 就是2G。当你用 fetch 去加载模型时,需要用到 response.arrayBuffer(),如果模型超过2G,就 GG 了

还有啊,ONNX 模型是通过 protobuf 格式进行传输的,protobuf 单个消息的大小限制也刚好是 2G

丹尼尔:所以最多只能加载2G的模型了?

蛋先生:那也不完全是。一次不行,我们可以分次嘛!我们可以将模型分成模型图和权重,权重信息作为外部数据另外加载即可。只要模型图不超过2G,咱就可以突破这2G的限制了

丹尼尔:那岂不是可以加载超级大的模型了?

蛋先生:嘿嘿,别高兴得太早。模型最终是要加载到运行时环境的,而我们的运行时是在 WebAssembly 环境中。根据 WebAssembly 规范,Memory 对象的大小顶多4G。所以理论上4G就是天花板了

丹尼尔:哦......

蛋先生:而且啊,当模型太大时,对硬件的要求就更高了。这些大家伙就不推荐放在浏览器里折腾了

丹尼尔:明白了,那我去试一下咯

蛋先生:好的,祝你好运!

写在最后

亲们,都到这了,要不,点赞或收藏或关注支持下我呗 o( ̄▽ ̄)d

相关推荐
阿珊和她的猫4 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
GetcharZp8 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
加班是不可能的,除非双倍日工资9 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi9 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip9 小时前
vite和webpack打包结构控制
前端·javascript
excel10 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国10 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼10 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy10 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT10 小时前
promise & async await总结
前端