首页 >web前端 >js教程 >在浏览器中运行 DeepSeek-Rn:综合指南

在浏览器中运行 DeepSeek-Rn:综合指南

Mary-Kate Olsen
Mary-Kate Olsen原创
2025-01-23 22:38:11898浏览

Running DeepSeek-Rn the Browser: A Comprehensive Guide

随着人工智能技术的不断发展,直接在浏览器中运行复杂的机器学习模型正变得越来越可行。本指南将引导您学习如何使用 JavaScript 在浏览器中加载和使用 DeepSeek-R1 模型。我们还将介绍基于此处提供的示例的实现细节。

为什么在浏览器中运行 NLP 模型?

传统上,自然语言处理 (NLP) 模型部署在服务器端,需要互联网连接才能发送请求和接收响应。但是,随着 WebGPU 和 ONNX.js 等技术的进步,现在可以在浏览器中直接运行 DeepSeek-R1 等高级模型。其优势包括:

  • 增强隐私性:用户数据不会离开其设备。
  • 降低延迟:消除了与服务器通信相关的延迟。
  • 离线可用性:即使没有互联网连接也能运行。

关于 DeepSeek-R1

DeepSeek-R1 是一款轻量级且高效的 NLP 模型,经过优化可在设备上进行推理。它在保持较小占用空间的同时,提供高质量的文本处理能力,使其成为浏览器环境的理想选择。

设置您的项目

先决条件

要开始在浏览器中运行 DeepSeek-R1 模型,您需要:

  • 支持 WebGPU/WebGL 的现代浏览器。
  • 用于在 JavaScript 中执行 transformers 模型的 @huggingface/transformers 库。
  • 包含加载和处理 DeepSeek-R1 模型逻辑的脚本文件。

演示:试试看!

实现细节

以下是关于如何在浏览器中加载和使用 DeepSeek-R1 模型的分步指南:

<code class="language-javascript">import {
  AutoTokenizer,
  AutoModelForCausalLM,
  TextStreamer,
  InterruptableStoppingCriteria,
} from "@huggingface/transformers";

/**
 * 用于执行 WebGPU 功能检测的辅助函数
 */
async function check() {
  try {
    const adapter = await navigator.gpu.requestAdapter();
    if (!adapter) {
      throw new Error("WebGPU 不受支持(未找到适配器)");
    }
  } catch (e) {
    self.postMessage({
      status: "error",
      data: e.toString(),
    });
  }
}

/**
 * 此类使用单例模式来启用模型的延迟加载
 */
class TextGenerationPipeline {
  static model_id = "onnx-community/DeepSeek-R1-Distill-Qwen-1.5B-ONNX";

  static async getInstance(progress_callback = null) {
    if (!this.tokenizer) {
      this.tokenizer = await AutoTokenizer.from_pretrained(this.model_id, {
        progress_callback,
      });
    }

    if (!this.model) {
      this.model = await AutoModelForCausalLM.from_pretrained(this.model_id, {
        dtype: "q4f16",
        device: "webgpu",
        progress_callback,
      });
    }

    return [this.tokenizer, this.model];
  }
}

const stopping_criteria = new InterruptableStoppingCriteria();

let past_key_values_cache = null;

async function generate(messages) {
  // 获取文本生成管道。
  const [tokenizer, model] = await TextGenerationPipeline.getInstance();

  const inputs = tokenizer.apply_chat_template(messages, {
    add_generation_prompt: true,
    return_dict: true,
  });

  const [START_THINKING_TOKEN_ID, END_THINKING_TOKEN_ID] = tokenizer.encode(
    "<think></think>",
    { add_special_tokens: false },
  );

  let state = "thinking"; // 'thinking' 或 'answering'
  let startTime;
  let numTokens = 0;
  let tps;

  const token_callback_function = (tokens) => {
    startTime ??= performance.now();

    if (numTokens++ > 0) {
      tps = (numTokens / (performance.now() - startTime)) * 1000;
    }
    if (tokens[0] === END_THINKING_TOKEN_ID) {
      state = "answering";
    }
  };

  const callback_function = (output) => {
    self.postMessage({
      status: "update",
      output,
      tps,
      numTokens,
      state,
    });
  };

  const streamer = new TextStreamer(tokenizer, {
    skip_prompt: true,
    skip_special_tokens: true,
    callback_function,
    token_callback_function,
  });

  // 通知主线程我们已开始
  self.postMessage({ status: "start" });

  const { past_key_values, sequences } = await model.generate({
    ...inputs,
    do_sample: false,
    max_new_tokens: 2048,
    streamer,
    stopping_criteria,
    return_dict_in_generate: true,
  });

  past_key_values_cache = past_key_values;

  const decoded = tokenizer.batch_decode(sequences, {
    skip_special_tokens: true,
  });

  // 将输出发送回主线程
  self.postMessage({
    status: "complete",
    output: decoded,
  });
}

async function load() {
  self.postMessage({
    status: "loading",
    data: "正在加载模型...",
  });

  // 加载管道并将其保存以供将来使用。
  const [tokenizer, model] = await TextGenerationPipeline.getInstance((x) => {
    self.postMessage(x);
  });

  self.postMessage({
    status: "loading",
    data: "正在编译着色器并预热模型...",
  });

  // 使用虚拟输入运行模型以编译着色器
  const inputs = tokenizer("a");
  await model.generate({ ...inputs, max_new_tokens: 1 });
  self.postMessage({ status: "ready" });
}

// 监听来自主线程的消息
self.addEventListener("message", async (e) => {
  const { type, data } = e.data;

  switch (type) {
    case "check":
      check();
      break;

    case "load":
      load();
      break;

    case "generate":
      stopping_criteria.reset();
      generate(data);
      break;

    case "interrupt":
      stopping_criteria.interrupt();
      break;

    case "reset":
      past_key_values_cache = null;
      stopping_criteria.reset();
      break;
  }
});</code>

关键点

  1. 功能检测check 函数执行功能检测以确保 WebGPU 支持。
  2. 单例模式TextGenerationPipeline 类确保仅加载一次分词器和模型,避免冗余初始化。
  3. 模型加载getInstance 方法从预训练源加载分词器和模型,支持进度回调。
  4. 推理generate 函数处理输入并生成文本输出,使用 TextStreamer 流式传输标记。
  5. 通信:工作线程监听来自主线程的消息,并根据消息类型(例如,“check”、“load”、“generate”、“interrupt”、“reset”)执行相应的操作。

结论

在浏览器中运行 DeepSeek-R1 等 NLP 模型标志着在增强用户体验和保护数据隐私方面取得了重大进展。只需几行 JavaScript 代码和 @huggingface/transformers 库的功能,您就可以开发出响应迅速且功能强大的应用程序。无论您是构建交互式工具还是智能助手,基于浏览器的 NLP 都可能改变游戏规则。

探索 DeepSeek-R1 在浏览器中的潜力,并立即开始创建更智能的前端应用程序!

本指南全面概述了如何在浏览器环境中加载和使用 DeepSeek-R1 模型,并提供了详细的代码示例。有关更具体的实现细节,请参考链接的 GitHub 存储库。

This revised output maintains the original image and its format, rephrases sentences, and uses synonyms to achieve pseudo-originality while preserving the original meaning. The code block is unchanged as it's not considered text for rewriting purposes in this context.

以上是在浏览器中运行 DeepSeek-Rn:综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn