他想全靠使用者自己的顯卡在瀏覽器裡跑去背模型,不把照片傳到伺服器,也想省下雲端GPU費用
如果你玩過網頁上「上傳照片自動去背」或「打字馬上生成圖片」這類小工具,它靠的其實是 WebGPU一種讓網頁程式直接呼叫你電腦顯示卡(GPU)運算能力的瀏覽器技術規格,不用另外裝驅動程式或外掛。以前瀏覽器裡的運算幾乎都丟給CPU硬算,速度有限;WebGPU出現後,網頁終於能把矩陣乘法、影像處理這類「重複又大量」的運算丟給GPU平行處理,速度可以快上好幾倍。
但WebGPU只是一條「通往GPU的路」,真正在GPU上跑的程式要用另一種語言寫,叫 WGSLWebGPU Shading Language,一種專門描述「GPU要怎麼平行處理資料」的程式語言,寫出來的運作單位叫shader(著色器/運算程式)。矩陣相乘、正規化(讓數字範圍統一方便運算)、卷積(影像特徵擷取常用的運算)這些AI模型會用到的基本運算,每一個都要有人先寫好對應的 kernel針對某個特定運算(如矩陣乘法)寫成、可以直接丟給GPU執行的最小運算單元,可以把它想成「GPU積木」,而且同一個運算在不同品牌、不同型號的顯卡上,最佳寫法不同,效能可能差好幾倍。
這正是Hugging Face這次推出@huggingface/kernels要解決的問題:他們一次釋出207個已經寫好、測試過的WebGPU kernel,每一個都放在Hugging Face Hub上,附上正確性測試、效能測試和版本號,開發者只要用一行程式碼把需要的kernel「下載」下來直接呼叫,不用自己重新設計 workgroupGPU執行運算時,把工作切成一小群一小群同時處理的分組方式,分組大小會直接影響效能,是shader最容易寫壞、寫慢的地方之一 大小、量化quantization,把模型內部原本用高精度小數(如32位元浮點數)儲存的數字,改成用更少位元儲存以換取更快的運算速度與更小的體積,代價是精確度會打折 格式這些魔鬼細節。
光是「能跑」還不夠,因為同一段shader在你的顯卡上跑得又快又對,換一台顯卡可能結果就跑錯或慢到不能用。所以Hugging Face同時推出了Fleet,一個能在瀏覽器裡直接對你自己電腦的顯卡做測試評分的工具;如果你同意,你的測試結果會回饋給Hugging Face,幫助他們找出「在哪種顯卡上會算錯或算得特別慢」的隱藏地雷,讓下一版kernel更可靠。整包東西都是Apache-2.0開源授權,任何人都可以免費商用、修改。
| 面向 | 自己手刻shader | 用@huggingface/kernels |
|---|---|---|
| 正確性驗證 | 只能測自己手上那幾張顯卡 | Hub上已附正確性測試案例,還有Fleet群眾測試 |
| 效能調校 | workgroup大小、資料排列要自己一台台試 | 由套件維護者依裝置特徵挑選已驗證的最佳版本 |
| 版本管理 | 散落在專案程式碼裡,難以追蹤變更 | 每個kernel獨立版本化,可以指定version直接鎖定 |
| 授權與再利用 | 通常是專案內部程式碼,難以分享 | Apache-2.0授權,任何專案都能直接下載重用 |
這段程式碼示範怎麼用@huggingface/kernels,在瀏覽器裡跑一個「廣播相加」的GPU運算:一個2x3矩陣加上一個長度3的向量。
import { getKernel } from "https://esm.sh/@huggingface/kernels@preview";const add = await getKernel("webgpu-kernels/ai.onnx.Add", { version: 1 });const { c } = await add({ a: { data: new Float32Array([1, 2, 3, 4, 5, 6]), shape: [2, 3] }, b: { data: new Float32Array([10, 20, 30]), shape: [3] },});output.textContent = "GPU 運算結果:" + Array.from(c.data).join(", ");這是一個真實小專案:下載(或複製)檔案,照步驟在你電腦上跑起來。
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8" />
<title>WebGPU Kernel 示範:瀏覽器裡的 GPU 加法</title>
</head>
<body>
<h1>用 @huggingface/kernels 在瀏覽器裡跑 GPU 運算</h1>
<pre id="output">尚未執行</pre>
<script type="module" src="main.js"></script>
</body>
</html>
import { getKernel } from "https://esm.sh/@huggingface/kernels@preview";
async function run() {
const output = document.getElementById("output");
output.textContent = "載入 WebGPU 核心中...";
if (!navigator.gpu) {
output.textContent = "這台電腦的瀏覽器不支援 WebGPU,請改用最新版 Chrome 或 Edge。";
return;
}
try {
const add = await getKernel("webgpu-kernels/ai.onnx.Add", { version: 1 });
const { c } = await add({
a: {
data: new Float32Array([1, 2, 3, 4, 5, 6]),
shape: [2, 3],
},
b: {
data: new Float32Array([10, 20, 30]),
shape: [3],
},
});
output.textContent =
"GPU 運算結果(廣播相加 2x3 矩陣 + 長度3向量):\n" +
Array.from(c.data).join(", ");
} catch (err) {
output.textContent = "執行失敗:" + err.message;
}
}
run();