AI · 開発者向けAI
ブラウザでAIモデルを動かすには?WebGPUとTransformers.jsの基本
結論
モデルファイル(多くはONNX形式)をダウンロードし、ONNX Runtime Web などのランタイム、多くは Transformers.js 経由で、Webページ内で実行します。ランタイムは、利用できればWebGPUでGPUを使い、なければWebAssemblyでCPUにフォールバックします。ファイルは初回の訪問後にキャッシュされ、データが端末の外に出ることはありません。
背景削除を開くなぜブラウザでAIを動かすのか
AI機能の多くはサーバーを呼び出します。写真やテキストをアップロードし、データセンターのGPUがモデルを実行し、結果が返ってきます。ブラウザ内AIはこれを逆転させます。モデルは一度ダウンロードされ、訪問者自身の端末が処理を行います。
- プライバシー:写真、音声、文書は端末の中にとどまります。アップロードも保存も不要で、多くの国のプライバシー法への対応も簡単になります。
- 利用ごとのサーバー費用がない:サイトが払うのはモデルファイルのホスティング費用で、GPU時間ではありません。無料ツールが成り立つ理由です。
- 初回読み込み後はオフラインで動き、リクエストごとの通信遅延もありません。
- アカウントもAPIキーも不要です。
トレードオフは確かにあります。初回訪問時は大きなダウンロードが必要で、速度は訪問者のハードウェア次第、そして収まるのは小〜中規模のモデルだけです。数百億パラメータの大規模チャットモデルには、いまもサーバーが必要です。現在うまく収まるタスクは、背景除去、画像の高画質化、深度推定、音声文字起こし、翻訳、テキスト分類、埋め込み、小規模な画像・言語モデルなどです。たとえば cv.cm の背景除去と音声文字起こしのツールは、この方法で BiRefNet と Whisper を動かしており、何もアップロードされません。
4つのレイヤー:モデル、ランタイム、バックエンド、ライブラリ
| レイヤー | 内容 | よくある選択 |
|---|---|---|
| モデルファイル | 学習済みの重みと計算グラフ | ONNXファイル。PyTorchからエクスポートされることが多い |
| ランタイム | ページ内で計算グラフを実行するコード | ONNX Runtime Web(TensorFlow.js や、チャットモデル向けの WebLLM などの代替もある) |
| バックエンド | ランタイムが使うハードウェアの経路 | GPU向けのWebGPU、CPU向けのWebAssembly(WASM)、対応環境ではWebNN |
| ライブラリ | 前処理、トークナイザ、パイプラインを扱う使いやすいAPI | Transformers.js(内部でONNX Runtimeを使用) |
ONNX(Open Neural Network Exchange)は、ニューラルネットワークのオープンな形式です。PyTorchで学習したモデルをONNXにエクスポートすれば、ONNX Runtime Web が複数のバックエンドで実行できます。WASMバックエンドはすべてのONNX演算子に対応しますが、GPUバックエンドは一部のみ対応なので、WebGPUでは失敗してもWASMなら動くモデルもあります。Transformers.js は、自分で書くことになる処理を肩代わりします。画像のリサイズ、テキストのトークン化、音声のデコード、生の出力値からラベル・マスク・テキストへの変換です。
WebGPUとWebAssemblyの比較
WebGPUは、ページがグラフィックカードを描画と汎用計算の両方に使えるようにする、W3Cのウェブ標準です。ニューラルネットワークで重要なのは計算の部分で、行列の積が多数のGPUコアで並列に実行されます。WebAssemblyはコンパイル済みのコードをネイティブに近い速度でCPU上で実行し、あらゆる最近のブラウザで動作します。
| 観点 | WebGPU | WebAssembly(WASM) |
|---|---|---|
| 実行場所 | GPU | CPU(SIMDを使ったマルチスレッドも可) |
| 大きなモデルでの速度 | 何倍も速いことが多い | 遅いが予測しやすい |
| 利用できる環境 | 拡大中だが、すべてのブラウザや端末ではない。MDNでは限定的な可用性とされている | あらゆる最近のブラウザ |
| ONNX Runtime Web の演算子対応 | 一部 | すべて |
| 要件 | セキュアコンテキスト(HTTPS) | スレッドにはクロスオリジン分離されたページが必要 |
| 向いているもの | 画像生成、大きなビジョンモデル、長い音声の Whisper | 小さなモデル、フォールバック、良いGPUがない端末 |
実際には、まずWebGPUを試し、だめならWASMにフォールバックします。ブラウザ名で判断してはいけません。ブラウザにアダプターを要求し、その機能を確認します。
// Check what this device can do before loading a model.
async function pickBackend() {
if (!("gpu" in navigator)) return { device: "wasm" }; // no WebGPU API
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) return { device: "wasm" }; // API exists, no usable GPU
const f16 = adapter.features.has("shader-f16"); // half-precision support
return { device: "webgpu", f16 };
}
console.log(await pickBackend(), "threads:", self.crossOriginIsolated);マルチスレッドのWASMは SharedArrayBuffer を使いますが、ブラウザはページがクロスオリジン分離されている場合にしか許可しません。そのためには Cross-Origin-Opener-Policy と Cross-Origin-Embedder-Policy ヘッダーを送る必要があります。これがないとWASMはシングルスレッドで動き、ずっと遅くなります。
Transformers.js の最小サンプル
Transformers.js では、タスクは pipeline の呼び出し1回で済みます。ライブラリがモデルをダウンロードし、選んだデバイスとデータ型に合うファイルを選び、呼び出せる関数を返します。
import { pipeline } from "@huggingface/transformers";
const { device } = await pickBackend(); // from the snippet above
// First call downloads the model and caches it. Later visits load from cache.
const classify = await pipeline(
"sentiment-analysis",
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
{
device, // "webgpu" or "wasm"
dtype: device === "webgpu" ? "fp32" : "q8",
progress_callback: (p) => console.log(p.status, p.file ?? "", p.progress ?? ""),
}
);
console.log(await classify("This runs entirely on my laptop."));
// [{ label: "POSITIVE", score: 0.99... }]これはモジュールスクリプトで、できれば Web Worker 内で実行します。モデルの推論は数百ミリ秒以上ブロックすることがあり、ワーカーならページは応答し続けます。WebGPUはワーカー内でも使えます。大きなモデルの初回読み込みは、回線が遅いと時間がかかるので、ダウンロードの進捗をユーザーに見せましょう。
ダウンロードサイズ、量子化、キャッシュ
ダウンロードサイズは、おおよそ「パラメータ数 × 1パラメータあたりのバイト数」です。この単純な計算で、そのモデルが現実的かどうかがわかります。
download size ~ number of parameters x bytes per parameter
fp32 (4 B) fp16 (2 B) int8 / q8 (1 B) q4 (0.5 B)
50 million params 200 MB 100 MB 50 MB 25 MB
500 million params 2.0 GB 1.0 GB 500 MB 250 MB
1 billion params 4.0 GB 2.0 GB 1.0 GB 500 MB
Real files differ a little: some layers stay at higher precision,
and the tokenizer and config add a few MB.量子化は、重みをより少ないビット数で保存する手法です。fp16はfp32の半分、8ビット量子化(q8)は4分の1、4ビット(q4)は約8分の1になります。重みが小さいほどダウンロードが速く、メモリも少なくて済みます。代償は精度の低下で、8ビットでは通常わずかですが、4ビットでは、特に小さなモデルや、小さな誤差が目立つ画像生成のようなタスクで目立ってきます。Transformers.js では dtype オプションでバリアントを選びます。既定値はWASMでq8、WebGPUでfp32で、使える選択肢はモデルの公開者がエクスポートしたものによります。
キャッシュのおかげで、2回目の訪問は速くなります。Transformers.js は、既定でダウンロードしたファイルをブラウザの Cache API に保存します。ブラウザはディスクサイズに応じてサイトごとにストレージの割り当てを与え、デスクトップなら数GBに及ぶことも多いのですが、このストレージはベストエフォートです。空き容量が少ないとブラウザが削除することがあり、Safariは、数日間ユーザーが操作していないサイトのスクリプト作成データを消すことがあります。サイトは navigator.storage.persist() で永続ストレージを要求でき、navigator.storage.estimate() で使用量を確認できます。
スマホなどの制約
- メモリ:モデルには、重みに加えて作業用のメモリが必要です。モバイルブラウザは1タブに与えるメモリがデスクトップよりずっと少なく、モデルが大きすぎると警告なしにタブが閉じられることがあります。モバイル向けのモデルは小さく、多くは数百MB以下に抑えましょう。
- スマホのWebGPU:対応状況は、ブラウザ、OSのバージョン、GPUドライバーによります。必ずWASMの経路か、わかりやすいメッセージを用意してください。
- 発熱とバッテリー:GPUの長時間利用でスマホが熱くなると、システムがチップの動作を落とします。1回目は2秒で終わるタスクが、5回目にはずっと長くかかることがあります。
- データ通信量:モバイル回線で大きなダウンロードを行う前に、ユーザーに警告しましょう。
- 精度:一部のGPUは高速な半精度(fp16)に対応していなかったり、少し違う数値を出したりするため、端末によって出力がわずかに異なることがあります。
- モデルのライセンスは引き続き適用されます。ブラウザで動かしても、利用規約は変わりません。
ブラウザ内AIを公開するためのチェックリスト
- 品質基準を満たす最小のモデルを選び、量子化版を並べてテストします。
- アダプターの要求でWebGPUを検出し、WASMにフォールバックします。
- サイトをHTTPSで配信し、WASMのスレッドが必要ならクロスオリジン分離を有効にします。
- 推論は Web Worker で実行し、ダウンロードと処理の進捗を表示します。
- ページの読み込み時にモデルをダウンロードしません。ユーザーがタスクを始めるまで待ち、ページを読むだけの訪問者に数GBの負担をかけないようにします。
- モデルファイルはバージョンを固定してホストし、キャッシュします。
- 開発用ノートPCだけでなく、低スペックのスマホでもテストします。
よくある質問
ブラウザ内AIは本当にプライベートですか?
モデルは端末上で動くので、入力をどこかに送る必要はありません。特定のサイトが何かをアップロードするかどうかはそのコード次第なので、プライバシーポリシーやブラウザのネットワークパネルで確認してください。
WebGPUに対応しているブラウザはどれですか?
主要なデスクトップブラウザと一部のモバイルブラウザで対応が広がっていますが、ブラウザのバージョン、OS、GPUによってまだ異なります。MDNの最新の互換性表を確認し、コードでは navigator.gpu の有無を調べましょう。
ChatGPTのようなモデルをブラウザで動かせますか?
数十億パラメータまでの小規模な言語モデルなら、良いGPUがあれば、1GB以上のダウンロードの後でブラウザ上で動かせます。ただし、ChatGPT、Claude、Gemini の裏にある大規模モデルよりは、はるかに能力が劣ります。
初回は遅く、2回目は速いのはなぜですか?
初回はモデルのダウンロードと、GPUシェーダーやWASMコードのコンパイルを行うからです。2回目以降は、ブラウザがそのストレージを消去していない限り、ブラウザのキャッシュからファイルを読み込みます。
ゲーミング用のカードがなくても、ブラウザのAIはGPUを使いますか?
はい。WebGPUは、一般的なノートPCやスマホの内蔵グラフィックスも使えます。専用カードより遅いものの、CPUの経路よりはずっと速いことが多いです。