AI · 開發者看 AI
如何在瀏覽器中執行 AI 模型?
簡答
你下載一個模型檔案(通常是 ONNX 格式),再用 ONNX Runtime Web 等執行階段(runtime)在網頁內執行,常搭配 Transformers.js 使用。執行階段在可用時透過 WebGPU 使用 GPU,否則退回以 WebAssembly 在 CPU 上執行。檔案在第一次造訪後會被快取,你的資料也不會離開裝置。
開啟AI 去背為什麼要在瀏覽器裡跑 AI
大多數 AI 功能都要呼叫伺服器:照片或文字被上傳,資料中心的 GPU 執行模型,再把結果傳回來。瀏覽器內 AI 則把這個流程反過來。模型只下載一次,由訪客自己的裝置來運算。
- 隱私:照片、音訊和文件都留在裝置上。不需要上傳或儲存任何東西,這也能簡化對許多國家隱私法規的遵循。
- 沒有每次使用的伺服器成本:網站只需負擔模型檔案的託管費,而不是 GPU 運算時間。這讓免費工具成為可能。
- 第一次載入後可離線使用,每次請求也沒有網路延遲。
- 不需要帳號或 API 金鑰。
代價也是實實在在的。第一次造訪需要大量下載,速度取決於訪客的硬體,而且只有小型與中型模型放得下。擁有數百億參數的大型聊天模型仍然需要伺服器。目前很適合的任務包括去背、圖片放大、深度估計、語音轉文字、翻譯、文字分類、嵌入向量(embeddings),以及小型圖像或語言模型。例如 cv.cm 的去背和語音轉文字工具,就是這樣執行 BiRefNet 和 Whisper,不會上傳任何東西。
四個層次:模型、執行階段、後端、函式庫
| 層次 | 是什麼 | 常見選擇 |
|---|---|---|
| 模型檔案 | 訓練好的權重與運算圖 | ONNX 檔案,通常從 PyTorch 匯出 |
| 執行階段(runtime) | 在頁面中執行運算圖的程式碼 | ONNX Runtime Web(另有 TensorFlow.js,或用於聊天模型的 WebLLM 等替代方案) |
| 後端(backend) | 執行階段所使用的硬體路徑 | GPU 用 WebGPU、CPU 用 WebAssembly(WASM),支援時也可用 WebNN |
| 函式庫 | 友善的 API:前處理、分詞器、pipeline | Transformers.js,底層使用 ONNX Runtime |
ONNX 是神經網路的開放格式。用 PyTorch 訓練的模型可以匯出成 ONNX,再由 ONNX Runtime Web 以多種後端執行。WASM 後端支援所有 ONNX 運算子;GPU 後端只支援其中一部分,所以模型可能在 WebGPU 上失敗,卻在 WASM 上正常運作。Transformers.js 補上了你原本得自己寫的部分:縮放圖片、把文字轉成 token、解碼音訊,以及把原始輸出數字轉成標籤、遮罩或文字。
WebGPU 與 WebAssembly 比較
WebGPU 是 W3C 的網頁標準,讓頁面可以使用顯示卡進行繪圖和通用運算。對神經網路來說,重點是運算部分:矩陣乘法在許多 GPU 核心上平行執行。WebAssembly 則在 CPU 上以接近原生的速度執行編譯後的程式碼,所有現代瀏覽器都支援。
| 問題 | WebGPU | WebAssembly(WASM) |
|---|---|---|
| 執行於 | GPU | CPU,可搭配 SIMD 多執行緒 |
| 大型模型的速度 | 通常快好幾倍 | 較慢,但可預測 |
| 可用性 | 持續增加,但並非每個瀏覽器和裝置都有;MDN 標註為有限可用 | 所有現代瀏覽器 |
| ONNX Runtime Web 的運算子涵蓋 | 一部分 | 全部運算子 |
| 需求 | 安全環境(HTTPS) | 多執行緒需要跨來源隔離的頁面 |
| 最適合 | 圖像生成、大型視覺模型、長音訊的 Whisper | 小型模型、備援、沒有好 GPU 的裝置 |
實務上,先試 WebGPU,失敗再退回 WASM。不要依瀏覽器名稱來判斷,而是向瀏覽器請求 adapter 並檢查它的功能:
// 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。函式庫會下載模型、依選定的裝置與資料型別挑選檔案,並回傳一個可以呼叫的函式:
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。模型推論可能阻塞數百毫秒甚至更久,放在 worker 裡,頁面才會保持回應。WebGPU 在 worker 內也可使用。請向使用者顯示下載進度,因為在網速慢時,第一次載入大型模型可能要等一陣子。
下載大小、量化與快取
下載大小大約是參數數量乘以每個參數佔用的位元組。這個簡單的算術能讓你判斷模型是否實用:
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 位元(q4)則縮小約八倍。權重越小,下載越快,也越省記憶體。代價是一些準確度,8 位元時通常很小,4 位元時比較明顯,尤其是小型模型,以及像圖像生成這類小誤差會被看出來的任務。Transformers.js 用 dtype 選項選擇版本。預設在 WASM 上是 q8、在 WebGPU 上是 fp32,可選項目則取決於模型發布者匯出了哪些版本。
快取讓第二次造訪變快。Transformers.js 預設用瀏覽器的 Cache API 儲存下載的檔案。瀏覽器依磁碟大小給每個網站一個儲存配額,在桌機上通常足夠存放數 GB,但這種儲存是盡力而為:裝置空間不足時,瀏覽器可能刪除它,Safari 也可能清除使用者數天沒有互動過的網站所建立的資料。網站可以用 navigator.storage.persist() 請求持久儲存,並用 navigator.storage.estimate() 查看用量。
手機及其他限制
- 記憶體:模型除了權重,還需要工作空間。行動瀏覽器給每個分頁的記憶體比桌機少得多,如果模型太大,可能在沒有警告的情況下關閉分頁。行動端的模型要保持小,通常不超過幾百 MB。
- 手機上的 WebGPU:支援程度取決於瀏覽器、作業系統版本和 GPU 驅動程式。一定要有 WASM 備援路徑,或清楚的提示訊息。
- 發熱與電量:長時間的 GPU 運算會讓手機發燙,系統隨後會降低晶片頻率。第一次只要 2 秒的任務,第五次可能要久得多。
- 行動數據方案:在行動網路上進行大量下載之前,要先提醒使用者。
- 精度:有些 GPU 沒有快速的半精度(fp16)支援,或算出略有不同的數字,所以不同裝置的輸出可能有些許差異。
- 模型授權依然適用。在瀏覽器中執行模型,並不會改變它的使用條款。
瀏覽器 AI 上線檢查清單
- 選擇符合品質要求的最小模型,並將它的量化版本並排測試。
- 用 adapter 請求偵測 WebGPU,並退回 WASM。
- 透過 HTTPS 提供網站;如果需要 WASM 多執行緒,就啟用跨來源隔離。
- 在 Web Worker 中執行推論,並顯示下載與處理進度。
- 不要在頁面載入時下載模型。等使用者開始任務,這樣只看頁面的訪客就不用花費好幾 GB 的流量。
- 以固定版本託管模型檔案,並做好快取。
- 在低階手機上測試,而不是只在開發用的筆電上。
常見問題
瀏覽器內的 AI 真的有隱私保障嗎?
模型在你的裝置上執行,所以你的輸入不需要傳送到任何地方。特定網站是否上傳了什麼,取決於它的程式碼,請查看其隱私聲明或瀏覽器的網路面板。
哪些瀏覽器支援 WebGPU?
主要桌面瀏覽器和部分行動瀏覽器的支援已經增加,但仍視瀏覽器版本、作業系統和 GPU 而定。請查看 MDN 上最新的相容性表格,並在程式碼中偵測 navigator.gpu。
可以在瀏覽器裡執行類似 ChatGPT 的模型嗎?
最多幾十億參數的小型語言模型,可以在好的 GPU 上於瀏覽器中執行,但需要先下載 1 GB 以上。它們的能力遠不如 ChatGPT、Claude 或 Gemini 背後的大型模型。
為什麼第一次執行很慢、第二次很快?
第一次執行要下載模型,並編譯 GPU shader 或 WASM 程式碼。之後的執行會從瀏覽器快取載入檔案,只要瀏覽器沒有清除那些儲存空間。
沒有遊戲顯示卡,在瀏覽器跑 AI 也會用到 GPU 嗎?
會。WebGPU 可以使用一般筆電和手機的內建顯示晶片。它比獨立顯卡慢,但通常仍比 CPU 路徑快很多。