浏览器中使用模型

LLM 参数越来越小,使模型跑在端侧成为可能,为什么要模型跑在端侧呢,首先可以节省服务器的算力,现在 GPU 的租用价格还是比较的高的,例如租用一个 A10 的卡1 年都要 3 万多。如果将一部分算力转移到端侧通过小模型进行计算,这样可以释放服务器的大部分算力。其次是安全问题,跑在端侧,所有数据只在本地使用不会上传到服务器,确保了个人的隐私数据不进行上传。

怎么将模型运行在端侧呢,我们拿浏览器举例,现在很多推理引擎都已经支持 CPU,例如 Ollama/Llamafile,这些都是服务端。微软 ONNX Runtime 主要用于端侧,需要将模型转为 ONNX 格式。ONNX web runtime 可以使用 GPU 或者 CPU 在浏览器进行推理,GPU 使用 WEBGL,CPU 使用的是 WASM。

本文使用 Transformer.js 加载 Qwen1.5,由于模型调用比较耗时,使用 Webworker 加载/推理模型,通过 Message 机制与 UI 进行交互。

worker.js

加载 Model 、 Tokenizer

import { env, pipeline } from '@xenova/transformers';
import {AutoModelForCausalLM, AutoTokenizer } from '@xenova/transformers';env.allowLocalModels = false;
env.useBrowserCache = true;class MyTranslationPipeline {static modelId="Xenova/Qwen1.5-0.5B-Chat"static model = null;static tokenizer = null;static async getModel(progress_callback = null) {if (this.model === null) {let model = await AutoModelForCausalLM.from_pretrained(this.modelId, { progress_callback });this.model = model;}return this.model;}static async getTokenizer(progress_callback = null) {if (this.tokenizer === null) {let tokenizer = await AutoTokenizer.from_pretrained(this.modelId,  { progress_callback });this.tokenizer = tokenizer;}return this.tokenizer;}
}// Listen for messages from the main thread
self.addEventListener('message', async (event) => {// Retrieve the translation pipeline. When called for the first time,// this will load the pipeline and save it for future use.let model = await MyTranslationPipeline.getModel(x => {// We also add a progress callback to the pipeline so that we can// track model loading.self.postMessage(x);});let tokenizer = await MyTranslationPipeline.getTokenizer(x => {// We also add a progress callback to the pipeline so that we can// track model loading.self.postMessage(x);});let prompt = "Give me a short introduction to large language model."let messages = [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": prompt}]let text = tokenizer.apply_chat_template(messages,{tokenize: false,add_generation_prompt: true})let model_inputs = await tokenizer([text], {"return_tensors":"pt"})// // Actually perform the translationlet output = await model.generate(model_inputs.input_ids,{"max_new_tokens":512,callback_function: x => {console.log(tokenizer.decode(x[0].output_token_ids, { skip_special_tokens: true }))self.postMessage({status: 'update',output: tokenizer.decode(x[0].output_token_ids, { skip_special_tokens: true })});}
});// Send the output back to the main threadself.postMessage({status: 'complete',output: tokenizer.decode(output[0], { skip_special_tokens: true }),});
});

定义 Message

通过 Message 回调进行交互

useEffect(() => {const onMessageReceived = (e: MessageEvent<WorkerMessage>) => {switch (e.data.status) {case 'initiate':// Model file start load: add a new progress item to the list.setReady(false);setProgressItems(prev => [...prev, { file: e.data.file!, progress: 0 }]);break;case 'progress':// Model file progress: update one of the progress items.setProgressItems(prev =>prev.map(item =>item.file === e.data.file ? { ...item, progress: e.data.progress! } : item));break;case 'done':// Model file loaded: remove the progress item from the list.setProgressItems(prev => prev.filter(item => item.file !== e.data.file));break;case 'ready':// Pipeline ready: the worker is ready to accept messages.setReady(true);break;case 'update':// Generation update: update the output text.setOutput(e.data.output!);break;case 'complete':// Generation complete: re-enable the "Translate" buttonsetDisabled(false);break;}};if (!worker.current) {// Create the worker if it does not yet exist.worker.current = new Worker(new URL('./worker.js', import.meta.url), {type: 'module'});}// Attach the callback function as an event listener.worker.current.addEventListener('message', onMessageReceived);// Define a cleanup function for when the component is unmounted.return () => {if (worker.current) {worker.current.removeEventListener('message', onMessageReceived);}};}, []);

在这里插入图片描述

总结

TransformerJS 实现了 Transformer 库中的所有类和方法,目前并不是所有模型的都支持在浏览器中使用,支持的模型可以在官网进行查询。https://github.com/xenova/transformers.js

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/446394.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode热题100】分治-快排

本篇博客记录分治快排的4道题目&#xff1a;颜色分类、排序数组、数组中的第K个最大元素、数组中最小的N个元素&#xff08;库存管理&#xff09;。 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,right n;for(int…

React速成

useRef获取DOM 组件通讯 子传父 function Son({ onGetMsg }){const sonMsg this is son msgreturn (<div>{/* 在子组件中执行父组件传递过来的函数 */}<button onClick{()>onGetMsg(sonMsg)}>send</button></div>) }function App(){const getMsg…

Python基础常见面试题总结

文章目录 1.深拷贝与浅拷贝2.迭代器3.生成器4.装饰器5.进程、线程、协程6.高阶函数7.魔法方法8.python垃圾回收机制 1.深拷贝与浅拷贝 浅拷贝是对地址的拷贝&#xff0c;只拷贝第一层&#xff0c;第一层改变的时候不会改变&#xff0c;内层改变才会改变。深拷贝是对值的拷贝&a…

智能驾驶|迈向智能出行未来,AI如何应用在自动驾驶?

自动驾驶通过人工智能&#xff08;AI&#xff09;、机器学习、传感器融合和实时数据处理&#xff0c;使车辆能够在无需人类干预的情况下自主驾驶。随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;与智能汽车的结合正在成为现代交通运输领域的热潮。无人驾驶…

selenium-Alert类用于操作提示框/确认弹框(4)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.alert()可以返回Alert对象&#xff0c;而Alert对象主要用于网页中弹出的提示框/确认框/文本输入框的确认或者取消等动作。 Alert介绍 当在页面定位到提示框/确认框/文本录入…

Flythings学习(二)控件相关

文章目录 1 前言2 通用属性2.1 控件ID值2.2 控件位置2.3 背景色2.4 背景图2.5 显示与隐藏2.6 控件状态2.7 蜂鸣器控制 3 文本类TextView4 按键类 Button4.1 系统按键4.2 处理按钮长按事件4.3 处理按键触摸事件 5 复选框CheckBox6 单选组 RadioGroup7 进度条&#xff0c;滑块7.1…

Ubuntu卸载Mysql【ubuntu 24.04/mysql 8.0.39】

一、准备工作 查看ubuntu版本号 查看mysql版本号(如果没有安装mysql,这一步省略) 二、Ubuntu上卸载mysql(如果没有安装mysql这一步省略) 在Ubuntu上卸载MySQL可以通过以下步骤进行&#xff0c;确保完全移除MySQL相关的包和数据&#xff1a; 1. 停止MySQL服务 在卸载之前…

verilog端口使用注意事项

下图存在组合逻辑反馈环&#xff0c;即组合逻辑的输出反馈到输入(赋值的左右2边存在相同的信号)&#xff0c;此种情况会造成系统不稳定。比如在data_in20的情况下&#xff0c;在data_out0 时候&#xff0c;输出的数据会反馈到输入&#xff0c;输入再输出&#xff0c;从而造成不…

java项目之基于vue的工厂车间管理系统的设计源码(springboot+mysql+vue)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的基于vue的工厂车间管理系统的设计。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于vu…

QT开发--多线程

第十四章 多线程 QThread 是 Qt 中实现多线程编程的核心类&#xff0c;提供跨平台线程管理。 使用 QThread 有两种方法&#xff1a; 1、 继承 QThread&#xff1a;重写 run() 方法&#xff0c;实现线程的具体操作。Qt4.8 之前较常用。 2、 使用 QObject 和 moveToThread()&…

树莓派应用--AI项目实战篇来啦-17.YOLOv8目标检测-安全帽检测

1. YOLOv8介绍 YOLOv8是Ultralytics公司2023年推出的Yolo系列目标检测算法&#xff0c;可以用于图像分类、物体检测和实例分割等任务。YOLOv8作为YOLO系列算法的最新成员&#xff0c;在损失函数、Anchor机制、样本分配策略等方面进行了全面优化和创新。这些改进不仅提高了模型的…

深入理解Transformer的笔记记录(精简版本)NNLM → Word2Vec

文章的整体介绍顺序为: NNLM → Word2Vec → Seq2Seq → Seq2Seq with Attention → Transformer → Elmo → GPT → BERT 自然语言处理相关任务中要将自然语言交给机器学习中的算法来处理,通常需要将语言数学化,因为计算机机器只认数学符号。向量是人把自然界的东西抽象出…

iOS 14 自定义画中画悬浮窗 Custom AVPictureInPictureController 实现方案

iOS 14&#xff0c;基于 AVPictureInPictureController&#xff0c;实现自定义画中画&#xff0c;涵盖所有功能与难点。 市面上的各种悬浮钟和提词器的原理都是基于此。 Demo源码在文末。 使用 iOS 画中画的要求&#xff1a; 真机&#xff0c;不能使用模拟器&#xff1b;iO…

Android平台RTSP|RTMP播放器PK:VLC for Android还是SmartPlayer?

好多开发者&#xff0c;希望在Android端低延迟的播放RTMP或RTSP流&#xff0c;本文就目前市面上主流2个直播播放框架&#xff0c;做个简单的对比。 VLC for Android VLC for Android 是一款功能强大的多媒体播放器&#xff0c;具有以下特点和功能&#xff1a; 广泛的格式支持…

FFmpeg的简单使用【Windows】--- 简单的视频混合拼接

实现功能 点击【选择文件】按钮在弹出的对话框中选择多个视频&#xff0c;这些视频就是一会将要混剪的视频素材&#xff0c;点击【开始处理】按钮之后就会开始对视频进行处理&#xff0c;处理完毕之后会将处理后的文件路径返回&#xff0c;并在页面展示处理后的视频。 视频所…

MySQL-08.DDL-表结构操作-创建-案例

一.MySQL创建表的方式 1.首先根据需求文档定义出原型字段&#xff0c;即从需求文档中可以直接设计出来的字段 2.再在原型字段的基础上加上一些基础字段&#xff0c;构成整个表结构的设计 我们采用基于图形化界面的方式来创建表结构 二.案例 原型字段 各字段设计如下&…

JAVA就业笔记4——第二阶段(1)

课程须知 A类知识&#xff1a;工作和面试常用&#xff0c;代码必须要手敲&#xff0c;需要掌握。 B类知识&#xff1a;面试会问道&#xff0c;工作不常用&#xff0c;代码不需要手敲&#xff0c;理解能正确表达即可。 C类知识&#xff1a;工作和面试不常用&#xff0c;代码不…

Redis:分布式 - 主从复制

Redis&#xff1a;分布式 - 主从复制 概念配置主从模式info replicationslave-read-onlytcp-nodelay 命令slaveof 主从结构一主一从一主多从 主从复制流程数据同步命令全量同步部分同步实时同步 节点晋升 概念 Redis的最佳应用&#xff0c;还是要在分布式系统中。对于非分布式…

Dockerfile 详解

Dockerfile是自定义Docker镜像的一套规则&#xff0c;由多条指令构成&#xff0c;每条指令都会对应于Docker镜像中的每一层&#xff0c;因为Docker是分层存储的。以下是Dockerfile中各个参数的详解及演示解析&#xff1a; 1. FROM 功能&#xff1a;指定待扩展的父级镜像&#…

【Linux系列】写入文本到文件

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…