ホームページ > ウェブフロントエンド > jsチュートリアル > DeepSeek Janus-Pro-Inブラウザの実行:ステップバイステップガイド

DeepSeek Janus-Pro-Inブラウザの実行:ステップバイステップガイド

Mary-Kate Olsen
リリース: 2025-01-28 10:32:09
オリジナル
570 人が閲覧しました

Running DeepSeek Janus-Pro-in the Browser: A Step-by-Step Guide

ブラウザで大規模な言語モデル(LLM)を直接実行すると、プライバシーを保護するクライアントAIアプリケーションに新しい可能性がもたらされます。このブログ投稿では、BrowserのWebGPUとHugging FaceのTransformers.jsライブラリを使用する方法を調べて、強力なテキストから画像生成モデル

deepseek janus-pro-1bを完全に実行します。

なぜブラウザベースの推論を選択するのですか?

プライバシー

:データがユーザーのデバイスを離れることはありません。
  1. コストメリット:サーバーインフラストラクチャは必要ありません。
  2. Accessability
  3. :最新のブラウザとWebGPUを備えた任意のデバイスで実行できます。
  4. transformers.js
  5. andwebgpuは、最適化を加速し、テキストからイメージの生成インタビューと推論などのマルチモーダルタスクの設計に捧げられているためです。
キーツールとライブラリ

Transformers.js :ブラウザの実行に最適化された、ハグする顔のトランスライブラリライブラリのJavaScriptバージョン。

webgpu :ブラウザで加速したGPUの最新のAPIは、WebGLを改善されたMLワークロードパフォーマンスに置き換えます。

onnx runtime
    :モデル実行は、最適化された計算図によって実装されます。
  1. デモンストレーションコード演習
  2. 次の例は、非ブロッキング推論のためにWebワーカーでDeepSeek Janus-Pro-1Bをロードして実行する方法を示しています。完全なコードは、GitHubリポジトリにあります。
  3. デモンストレーションを実行しますここでリアルタイムのデモンストレーションを見る:deepseek janus-pro-1bブラウザーデモ
デモンストレーションの重要な機能

モデルの読み込みと推論の実際の時間の進捗が更新されます。

WebGPUが加速されます(Chrome 113またはEdge 113が必須)。
<code class="language-javascript">import {
  AutoProcessor,
  MultiModalityCausalLM,
  BaseStreamer,
  TextStreamer,
  InterruptableStoppingCriteria,
} from "@huggingface/transformers";

// 定义常量
const IMAGE_GENERATION_COMMAND_PREFIX = "/imagine ";
const MAX_NEW_TEXT_TOKENS = 1024;

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

/**
 * 此类使用单例模式来启用管道延迟加载
 */
class ImageGenerationPipeline {
  static model_id = "onnx-community/Janus-Pro-1B-ONNX";

  static async getInstance(progress_callback = null) {
    this.processor ??= AutoProcessor.from_pretrained(this.model_id, {
      progress_callback,
    });

    this.model ??= MultiModalityCausalLM.from_pretrained(this.model_id, {
      dtype: fp16_supported
        ? {
            prepare_inputs_embeds: "q4",
            language_model: "q4f16",
            lm_head: "fp16",
            gen_head: "fp16",
            gen_img_embeds: "fp16",
            image_decode: "fp32",
          }
        : {
            prepare_inputs_embeds: "fp32",
            language_model: "q4",
            lm_head: "fp32",
            lm_head: "fp32",
            gen_head: "fp32",
            gen_img_embeds: "fp32",
            image_decode: "fp32",
          },
      device: {
        prepare_inputs_embeds: "wasm", // TODO 当错误修复后使用“webgpu”
        language_model: "webgpu",
        lm_head: "webgpu",
        gen_head: "webgpu",
        gen_img_embeds: "webgpu",
        image_decode: "webgpu",
      },
      progress_callback,
    });

    return Promise.all([this.processor, this.model]);
  }
}

class ProgressStreamer extends BaseStreamer {
  constructor(total, on_progress) {
    super();
    this.total = total;
    this.on_progress = on_progress;

    this.count = null;
    this.start_time = null;
  }

  put(value) {
    if (this.count === null) {
      // 忽略第一批标记(提示)
      this.count = 0;
      this.start_time = performance.now();
      return;
    }

    const progress = ++this.count / this.total;

    this.on_progress({
      count: this.count,
      total: this.total,
      progress,
      time: performance.now() - this.start_time,
    });
  }

  end() {
    /* 什么也不做 */
  }
}

const stopping_criteria = new InterruptableStoppingCriteria();

async function generate(messages) {
  // 对于此演示,我们只响应最后一条消息
  const message = messages.at(-1);

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

  // 加载管道
  const [processor, model] = await ImageGenerationPipeline.getInstance();

  // 确定用户是否要生成图像或文本
  if (message.content.startsWith(IMAGE_GENERATION_COMMAND_PREFIX)) {
    const text = message.content.replace(IMAGE_GENERATION_COMMAND_PREFIX, "");

    const conversation = [
      {
        role: "", // 使用标题大小写
        content: text,
      },
    ];
    const inputs = await processor(conversation, {
      chat_template: "text_to_image",
    });

    const callback_function = (output) => {
      self.postMessage({
        status: "image-update",
        ...output,
      });
    };

    const num_image_tokens = processor.num_image_tokens;
    const streamer = new ProgressStreamer(num_image_tokens, callback_function);

    const outputs = await model.generate_images({
      ...inputs,
      min_new_tokens: num_image_tokens,
      max_new_tokens: num_image_tokens,
      do_sample: true,
      streamer,
    });

    const blob = await outputs[0].toBlob();

    // 将输出发送回主线程
    self.postMessage({
      status: "image-update",
      blob,
    });
  } else {
    const inputs = await processor(
      message.image
        ? [
            {
              role: "",
              content: "<image_placeholder>\n" + message.content,
              images: [message.image],
            },
          ]
        : [
            {
              role: "",
              content:
                "您是一位乐于助人的助手。以简洁的方式回答用户的问题。",
            },
            {
              role: "",
              content: message.content,
            },
          ],
    );

    let startTime;
    let numTokens = 0;
    let tps;
    const token_callback_function = () => {
      startTime ??= performance.now();

      if (numTokens++ > 0) {
        tps = (numTokens / (performance.now() - startTime)) * 1000;
      }
    };
    const callback_function = (output) => {
      self.postMessage({
        status: "text-update",
        output,
        tps,
        numTokens,
      });
    };

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

    // 生成响应
    const outputs = await model.generate({
      ...inputs,
      max_new_tokens: MAX_NEW_TEXT_TOKENS,
      do_sample: false,
      streamer,
      stopping_criteria,
    });
  }

  // 告诉主线程我们已完成
  self.postMessage({
    status: "complete",
  });
}

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

  // 加载管道并将其保存以备将来使用。
  const [processor, model] = await ImageGenerationPipeline.getInstance((x) => {
    // 我们还向管道添加进度回调,以便我们可以
    // 跟踪模型加载。
    self.postMessage(x);
  });

  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":
      stopping_criteria.reset();
      break;
  }
});</code>
ログイン後にコピー

完全なクライアント実行 - データは外部サーバーに送信されません。

挑戦と最適化

モデルの定量化

:モデルの定量化は8桁になり、サイズを縮小し、負荷速度を向上させます。 メモリ管理

:: Webワーカーは、推論中にUIが凍結するのを防ぐことができます。
  • ブラウザの互換性
  • :: WebGPUはまだテスト段階にありますが、パフォーマンスには不可欠です。
  • 結論

ブラウザでDeepSeek Janus-Pro-1Bを実行すると、クライアントAIの可能性が示されています。 Transformers.JSやWebGPUSなどのツールを使用すると、複雑なモデルが限られた環境で効率的に実行され、ユーザーのプライバシーを保護できるようになりました。 フォローアップステップ

    • さまざまなプロンプトとモデルの構成を試してください。
    • 特定のフィールドのミッションの微調整モデルの探索。
    • WebGPUの採用を監視して、より広い互換性を確保します。

    開発者にとって、これは降下とユーザー中心のAIアプリケーションのエキサイティングな変化を示しています。サンプルコードに関する詳細な調査と構築を開始してください! ?

    この復活した出力は、diffferengと文の構造を使用している間、元の意味を維持しますが、それは非常に長いコードスニペットであり、実際のアプリケーションでより小さな、管理可能なチャンクになることから利益を得るかもしれません

    以上がDeepSeek Janus-Pro-Inブラウザの実行:ステップバイステップガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    ソース:php.cn
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    著者別の最新記事
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート