浏览器中使用模型

news2024/11/25 16:01:45

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 translation
  let 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 thread
    self.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" button
          setDisabled(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.coloradmin.cn/o/2210775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux中真实的调度算法,进程地址空间,命令行参数

文章目录 Linux中真正的调度算法补充 命令行参数什么是命令行参数&#xff1f;命令行参数的用途如何在不同的编程语言中使用命令行参数命令行参数好处 Linux中真正的调度算法 这是Linux2.6的内核中进程队列的数据结构 其中有这两个指针*active,*expired&#xff0c;而Linux为…

论文及其创新点学习cvpr2022 On the Integration of Self-Attention and Convolution

代码地址 https://github.com/LeapLabTHU/ACmix https://gitee.com/mindspore/models 论文创新点&#xff0c;将注意力机制 和卷积 相结合 # encoding: utf-8author: duhanyue start time: 2024/10/13 10:04 import torch import torch.nn as nn def position(H, W, is_cudaT…

邮票鉴赏系统| 邮票鉴赏系统平台|基于java和vue的邮票鉴赏系统设计与实现(源码+数据库+文档)

邮票鉴赏系统\ 目录 基于java和vue的邮票鉴赏系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;阿里…

用 Gemini Google 生成图片的魔法

用 Gemini Google 生成图片的魔法指南 你是否曾经想过&#xff0c;用一些简单的文本描述来生成一张图片&#xff1f;这听起来像是科幻小说中的魔法&#xff0c;但实际上&#xff0c;这就是 Gemini Google 的魔力&#xff01;在这篇文章中&#xff0c;我将向你详细介绍如何使用…

【HarmonyOS NEXT】实现页面水印功能

关键词&#xff1a;鸿蒙、水印、Watermark、页面、触摸问题 注&#xff1a;本期文章同样适用 OpenHarmony 的开发 在app开发过程中时常会出现敏感信息页面&#xff0c;为保护信息安全和及时的数据追踪&#xff0c;通常会采用给页面加水印的形式&#xff0c;那么本期文章会介绍…

自回归视觉生成里程碑!比ControlNet 和 T2I-Adapter 快五倍!北大腾讯提出CAR:灵活、高效且即插即用的可控框架

文章链接&#xff1a;https://arxiv.org/pdf/2410.04671 项目链接&#xff1a;https://github.com/MiracleDance/CAR 亮点直击 CAR是首个为自回归模型家族设计的灵活、高效且即插即用的可控框架。CAR基于预训练的自回归模型&#xff0c;不仅保留了原有的生成能力&#xff0c;还…

sherpa-ncnn 语言模型简单对比

在昨天把系统搞崩溃前&#xff0c;对sherpa-ncnn的中文模型做了一个简单的对比。这次使用的分别是sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13&#xff08;以下简称bilingual-zh-en-2023-02-13&#xff09;和sherpa-ncnn-streaming-zipformer-small-bilingual…

服务器数据恢复—EMC存储RAID5磁盘阵列数据恢复案例

服务器数据恢复环境&#xff1a; 一台EMC某型号存储设备&#xff0c;该存储中有一组由12块&#xff08;包括2块热备盘&#xff09;STAT硬盘组建的raid5阵列。 服务器故障&#xff1a; 该存储在运行过程中突然崩溃&#xff0c;raid瘫痪。数据恢复工程师到达现场对故障存储设备进…

GPT联网分析到底有多强?实测效果告诉你答案!

文章目录 零、前言一、gpt-4o操作指导gpt4o 二、感受 零、前言 早上在聊到博主在选择平台时&#xff0c;要选择哪个平台发展。 通过GPT查询并分析了小红书&#xff0c;微信视频号&#xff0c;抖音和B站的用户群体。 由此可举一反三&#xff0c;如何让GPT联网分析&#xff0c;…

部署私有仓库以及docker web ui应用

官方地址&#xff1a;https://hub.docker.com/_/registry/tags 一、拉取registry私有仓库镜像 docker pull registry:latest 二、运⾏容器 docker run -itd -v /home/dockerdata/registry:/var/lib/registry --name "pri_registry1" --restartalways -p 5000:5000 …

如何针对项目中的技术难点准备面试?——黑马点评为例

最核心的&#xff0c;包装和准备 个人项目&#xff0c;怎么包装&#xff1f;一定要写出代码才可以吗&#xff1f; 你可以在系统A中实现就可以&#xff0c;了解其中实现的细节&#xff0c;怎么跟面试官对线等等&#xff0c;这些话术到位了之后&#xff0c;再把它融入到系统B&a…

《CUDA编程》7.全局内存的合理使用

上一章简单的介绍了一下各种内存&#xff0c;本章开始详细讲解各个内存的合理使用&#xff0c;在所有设备中&#xff0c;全局内存的访问速度最慢&#xff0c;是CUDA程序的一个性能瓶颈&#xff0c;所以值得特别关注 1 全局内存的合并与非合并访问 对全局内存的访问将触发内存事…

LabVIEW如何实现高精度定时器

在LabVIEW中实现高精度定时器通常需要考虑以下几个方面&#xff1a;定时器的精度要求、操作系统的调度机制、硬件资源&#xff08;如计时器、触发器&#xff09;等。以下是几种常见的实现方式&#xff1a; ​ 1. 使用 Wait(ms) 或 Wait Until Next ms Multiple VI 这两个函数…

【无人机设计与控制】PID_积分滑模_积分反步四旋翼无人机轨迹跟踪控制算法

摘要 本文基于四旋翼无人机设计与控制&#xff0c;提出了一种结合PID控制、积分滑模控制以及积分反步控制的轨迹跟踪算法。该算法通过调节无人机的运动轨迹&#xff0c;提升其在复杂环境下的稳定性与抗扰动能力。实验结果表明&#xff0c;该算法能有效改善无人机的轨迹跟踪精度…

【python实操】python小程序之计算对象个数、游戏更新分数

引言 python小程序之计算对象个数、游戏更新分数 文章目录 引言一、计算对象个数1.1 题目1.2 代码1.3 代码解释1.3.1 代码结构1.3.2 模块解释1.3.3 解释输出 二、游戏更新分数2.1 题目2.2 代码2.3 代码解释2.3.1 定义 Game 类2.3.2 创建 Game 实例并调用方法 三、思考3.1 计算对…

C++之String类模拟实现(下)

片头 哈喽~小伙伴们&#xff0c;在上一篇中&#xff0c;我们讲解了C的string类的相关函数&#xff0c;这一章中&#xff0c;我们将继续深入学习string类函数&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 五、对内容进行修改 ⑤insert函数 在指定位置插入字符或者字符串 …

基于Raspberry Pi人脸识别自动门

人脸识别自动门 简介 在当今数字化时代&#xff0c;智能家居安全变得越来越重要。今天&#xff0c;我要向大家介绍一个结合了安全性与便利性的项目——人脸识别自动门。这个项目通过在门上实施基于面部识别的高级安全系统&#xff0c;使用摄像头验证房主的面部&#xff0c;自…

重学SpringBoot3-集成Spring Boot Actuator

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Spring Boot Actuator 1. 什么是 Spring Boot Actuator&#xff1f;2. Spring Boot Actuator 的核心功能3. Spring Boot 3 中集成 Actuator3.1 添加…

ElasticSearch是什么?

1.概述 Elasticsearch 是一个基于 Apache Lucene 构建的开源分布式搜索引擎和分析引擎。它专为云计算环境设计&#xff0c;提供了一个分布式的、高可用的实时分析和搜索平台。Elasticsearch 可以处理大量数据&#xff0c;并且具备横向扩展能力&#xff0c;能够通过增加更多的硬…

2014年国赛高教杯数学建模C题生猪养殖场的经营管理解题全过程文档及程序

2014年国赛高教杯数学建模 C题 生猪养殖场的经营管理 某养猪场最多能养10000头猪&#xff0c;该养猪场利用自己的种猪进行繁育。养猪的一般过程是&#xff1a;母猪配种后怀孕约114天产下乳猪&#xff0c;经过哺乳期后乳猪成为小猪。小猪的一部分将被选为种猪&#xff08;其中公…