WASM和機器學習

webassembly

什么是WebAssembly?

WebAssembly 是一種可以在現(xiàn)代Web瀏覽器中運行的低級的類匯編語言滑负,具有緊湊的二進制格式,接近本機的性能運行的帮匾。為了實現(xiàn)代碼緊湊WebAssembly 被設計成了不容易手寫痴鳄,但是支持C痪寻、C++、C#槽华、Golang、Rust 等源語言編寫代碼猫态,使用相應工具鏈翻譯源語言代碼亲雪。

webassembly

WebAssembly旨在補充并與JavaScript一起運行,使用 WebAssemblyJavaScript API虾标,你可以將WebAssembly模塊加載到 JavaScript 應用程序中并在兩者之間共享功能灌砖。這使您可以在相同的應用程序中利用WebAssembly的性能和功能以及 JavaScript 的表現(xiàn)力和靈活性基显。WebAssembly 模塊甚至可以導入Node.js應用程序中來提供高性能的服務。

為什么需要 WebAssembly库继?

從歷史上看窜醉,Web瀏覽器的VM 只能加載 JavaScript。這對我們來說效果很好拜英,因為 JavaScript 足夠強大读串,可以解決當今人們在 Web 上遇到的大多數(shù)問題。然而排监,當我們嘗試將 JavaScript 用于更密集的用例時舆床,例如 3D 游戲、虛擬和增強現(xiàn)實谷暮、計算機視覺盛垦、圖像/視頻編輯以及許多其他需要本機性能的領域時腾夯,我們遇到了性能問題。

W3C WebAssembly 標準

WebAssembly Core Specification定義了一個低級虛擬機班利,模擬運行該虛擬機的許多微處理器的功能榨呆。 通過即時編譯或解析,WebAssembly 引擎使編寫的代碼可以以接近本地平臺的速度運行闯割。.wasm 資源類似于 Java .class 文件浅侨,它包含靜態(tài)數(shù)據(jù)和對該靜態(tài)數(shù)據(jù)進行操作的代碼段如输。

WebAssembly Web API定義了一個基于 Promise 的接口央勒,用于請求和執(zhí)行 .wasm 資源崔步。 .wasm 資源的結構經(jīng)過優(yōu)化,允許在檢索整個資源之前開始執(zhí)行灶似。

WebAssembly JavaScript Interface提供了一個 JavaScript 接口,用于調用并將參數(shù)傳遞給 WebAssembly 函數(shù)希痴。 在 Web 瀏覽器中春感,WebAssembly 與主機環(huán)境的交互都通過 JavaScript 進行管理鲫懒。

WebAssembly 關鍵概念

了解 WebAssembly 如何在瀏覽器中運行需要幾個關鍵概念。所有這些概念都在WebAssembly JavaScript API中 1:1 反映甲献。

Module : 表示已被瀏覽器編譯成可執(zhí)行機器代碼的 WebAssembly 二進制文件颂翼。Module 是無狀態(tài)的,因此锥累,像
Blob一樣桶略,可以在 windows 和 worker 之間顯式共享(通過postMessage的方式)诲宇。Module 聲明導入和導出就像 ES 模塊一樣。

Memory : 一個可調整大小的ArrayBuffer鹅心,其中包含由WebAssembly的低級內存訪問指令讀取和寫入的線性字節(jié)數(shù)組纺荧。

Table : 一個可調整大小的類型化引用數(shù)組(例如宙暇,函數(shù)),否則無法將其作為原始字節(jié)存儲在內存中(出于安全和可移植性原因)桃熄。

Instance :一個模塊與它在運行時使用的所有狀態(tài)配對型奥,包括內存、表和一組導入的值谐宙。Instance 就像一個 ES 模塊血崭,它已通過一組特定的導入加載到特定的全局中。

JavaScript API 為開發(fā)人員提供了創(chuàng)建模塊(Module)咽瓷、內存(Memory)茅姜、表(Table)和實例(Instance)的能力月匣。給定一個WebAssembly實例,JavaScript代碼可以同步調用它的導出素标,這些導出作為普通的JavaScript函數(shù)公開萍悴。通過將這些JavaScript函數(shù)作為導入傳遞給WebAssembly實例癣诱,WebAssembly代碼也可以同步調用任意JavaScript函數(shù)。

WebAssembly 工作流程

如果您使用C/C++鲫惶,您可能使用過gcc或類似的編譯器实抡。為了獲得Webassembly二進制文件,我們需要一些其他特殊的編譯器艺蝴∧穹希可用的不止一種姑荷,但目前最好的一種是Emscripten它是開源的。
與"普通"匯編語言不同胯盯,Webassembly 不是特定于 CPU 的计露,因此可以在多個平臺上運行票罐,從手機等嵌入式系統(tǒng)到計算機的 CPU。
一旦我們用 Emscripten 編譯了我們的 C/C++ 代碼疗杉,我們就獲得了一個可以在瀏覽器上運行的合適的 WASM 文件蚕礼,很簡單吧奠蹬?
實際上,還有更多細節(jié)需要考慮冀痕,但我們將逐步介紹它們割以。
WASM WebApp 工作的步驟是:

  1. 使用Emscripten編譯C/C++代碼严沥,以獲得WASM二進制文件。

  2. 使用JavaScript"膠水代碼"將WASM二進制文件綁定到頁面跟伏。

  3. 運行您的應用程序并讓瀏覽器實例化您的WASM模塊翩瓜、內存和引用表兔跌。一旦完成,您的WebApp就可以完全運行了华望。

webassembly

從C/C++代碼生成

c/c++

Emscripten 首先將 C/C++ 輸入到 clang+LLVM( C/C++ 編譯器工具鏈)赖舟,將C/C++代碼編譯成.wasm 二進制文件宾抓。

WebAssembly 本身目前無法直接訪問 DOM;它只能調用 JavaScript幢泼,傳入整數(shù)和浮點原始數(shù)據(jù)類型旭绒。因此焦人,要訪問任何 Web API花椭,WebAssembly 需要調用 JavaScript,然后 JavaScript 會調用 Web API丹允。因此袋倔,Emscripten 創(chuàng)建了實現(xiàn)此目的所需的 HTML 和 JavaScript 粘合代碼宾娜。

要使 WebAssembly 可用,我們需要兩個主要組件:將代碼編譯成 WebAssembly 的工具鏈嚣艇,以及可以執(zhí)行該輸出的瀏覽器华弓。這兩個組件都依賴于完成WebAssembly 規(guī)范的進展寂屏,但除此之外娜搂,很大程度上是獨立的工程工作涌攻。這種分離是一件好事频伤,因為它將使編譯器能夠發(fā)出在任何瀏覽器中運行的 WebAssembly憋肖,并且無論是哪個編譯器生成它婚苹,瀏覽器都可以運行 WebAssembly膊升;換句話說,它允許多個工具鏈和多個瀏覽器協(xié)同工作评肆,改善用戶選擇瓜挽。分離還允許兩個組件的工作立即并行進行征绸。

git clone https://github.com/emscripten-core/emsdk.git

cd emsdk

./emsdk install latest

./emsdk activate latest

source ./emsdk_env.sh

在你的IDE中復制如下代碼:

// hello.c
#include <stdio.h>
int main() {
    printf("hello, world!\n");
    return 0;
}

然后編譯這個文件

emcc hello.c -o hello.js

您可以使用node.js運行它們:

node hello.js

Emscripten 還可以生成用于測試嵌入式 JavaScript 的 HTML管怠。要生成 HTML渤弛,請使用-o( output ) 命令并指定一個 html 文件作為目標文件:

emcc hello.c -O3 -o hello.html

請注意,除了發(fā)出WebAssembly之外鹿驼,我們在此模式下發(fā)出的構建通常使用Emscripten工具鏈中的所有其他內容:Emscripten的musl libc端口和訪問它的系統(tǒng)調用辕宏、OpenGL/WebGL 代碼瑞筐、瀏覽器集成代碼、node.js 集成代碼块蚌,等等峭范。因此,它支持Emscripten已經(jīng)做的所有事情辆毡,并且使用Emscripten的現(xiàn)有項目只需輕按一下開關即可切換到發(fā)出WebAssembly舶掖。這是讓現(xiàn)有的 C++ 項目在WebAssembly啟動時從WebAssembly中受益的關鍵部分尔店,而他們幾乎不需要付出任何努力嚣州。

WebAssembly 在機器學習中的應用

僅僅使用 WebAssembly 協(xié)議很難滿足機器學習所需的各種矩陣運算所需的計算指令,因此有了很多不同補充協(xié)議實現(xiàn)協(xié)機器學習的功能龟虎,下面介紹三種比較主流的實現(xiàn)方式WebAssembly SIMD, WASI-NN, Apache TVM鲤妥。

WebAssembly SIMD

SIMD代表單指令多數(shù)據(jù)拱雏。SIMD 指令是一類特殊的指令铸抑,它通過同時對多個數(shù)據(jù)元素執(zhí)行相同的操作來利用應用程序中的數(shù)據(jù)并行性。音頻/視頻編解碼器蒲赂、圖像處理器等計算密集型應用程序都是利用 SIMD 指令來加速性能的應用程序示例滥嘴。大多數(shù)現(xiàn)代架構支持 SIMD 指令的一些變體若皱。

WebAssembly SIMD 提案中包含的一組操作由在各種平臺上得到很好支持的操作組成,并且被證明是高性能的晦譬。為此互广,目前的提議僅限于標準化固定寬度 128 位 SIMD 操作兜辞。

當前的提議引入了一種新的v128值類型,以及對這種類型進行操作的許多新操作。用于確定這些操作的標準是:

這些操作應該在多個現(xiàn)代架構中得到很好的支持扫皱。

在一個指令組內的多個相關架構中韩脑,性能優(yōu)勢應該是積極的粹污。

所選的一組操作應盡量減少性能懸崖(如果有)壮吩。

在Chrome 中的 SIMD 支持

默認情況下,Chrome 91 提供 WebAssembly SIMD 支持觉啊。確保使用最新版本的工具鏈杠人,如下所述嗡善,以及最新的 wasm-feature-detect 來檢測支持最終版本規(guī)范的引擎学歧。

在 Firefox 中啟用實驗性 SIMD 支持

WebAssembly SIMD 在 Firefox 的標志后面可用撩满。目前它僅在 x86 和 x86-64 架構上受支持绅你。要在 Firefox 中試用 SIMD 支持忌锯,請轉到about:config并啟用javascript.options.wasm_simd. 請注意偶垮,此功能仍處于試驗階段帝洪,正在開發(fā)中葱峡。

WASI-NN

如同WASM SIMD一樣,wasi-nn也允許WebAssembly 程序訪問主機提供的機器學習(ML)功能蛛芥。為保持足夠的兼容性WASM SIMD只能使用CPU作為計算但愿仅淑,但是許多機器學習模型利用了一些其他輔助處理單元(例如GPU胸哥、TPU)空厌。目前很難找到一種合適的方法使用WASM編譯到這樣的設備上的蝇庭,因此在WASM基礎上提供一種使用這些設備的方法,wasi-nn就是為了實現(xiàn)這一目的而被設計出來的更高級別的 API 盗棵。

最后纹因,將 ML 推理部署到 Wasm 運行時已經(jīng)足夠困難了瞭恰,而無需將翻譯的復雜性添加到較低級別的抽象中。因此狱庇,wasi-nn允許程序員直接部署模型惊畏,將針對適當設備編譯模型的工作轉移到其他工具(例如OpenVINO恶耽、TF)。如果在某個時候有一個WASM提案可以使用機器的完整 ML 性能(例如靈活向量颜启、GPU)偷俭,那么可以想象,wasi-nn可以僅使用WASM原語"在后臺"實現(xiàn)——直到到那時缰盏,ML程序員仍然可以使用此處描述的方法執(zhí)行推理涌萤,并且如果發(fā)生這種切換口猜,應該會看到最小的變化负溪。

經(jīng)過訓練的機器學習模型都會被部署在具有不同體系結構和操作系統(tǒng)類型的各類不同設備上。而借助于 wasi-nn济炎,.wasm 文件便能夠以一種可移植的方式去執(zhí)行諸如"描述張量"及"執(zhí)行推理請求"等操作川抡,而無視底層具體的指令集架構(ISA)及操作系統(tǒng)(OS)差異。

tvm

Apache TVM

在Apache TVM深度學習編譯器中引入了WASM和WebGPU的支持须尚。實驗表明猖腕,在將模型部署到Web時,TVM的WebGPU后端可以接近本機 GPU的性能恨闪。

tvm

計算是現(xiàn)代機器學習應用程序的支柱之一。GPU的引入加快了深度學習的工作量放坏,極大地提高了運行速度咙咽。部署機器學習的需求不斷增長,瀏覽器已成為部署智能應用程序的自然之所淤年。

TensorFlow.js和ONNX.js將機器學習引入瀏覽器钧敞,但是由于缺乏對Web上GPU的標準訪問和高性能訪問的方式,他們使用了WASM SIMD優(yōu)化CPU計算麸粮,通過過WebGL提供GPU計算部分溉苛。但是WebGL缺少高性能著色學習所需的重要功能,例如計算著色器和通用存儲緩沖區(qū)弄诲。

WebGPU是下一代Web圖形標準愚战。與最新一代的圖形API(例如Vulkan和Metal)一樣,WebGPU提供了一流的計算著色器支持齐遵。

為了探索在瀏覽器中使用WebGPU進行機器學習部署的潛力寂玲,增強了深度學習編譯器Apache(incubating)TVM,以WASM(用于計算啟動參數(shù)并調用設備啟動的主機代碼)和WebGPU(用于設備)為目標梗摇。使用TVM在Web上部署機器學習應用程序時拓哟,仍能接近GPU的本機性能。

tvm

WebGPU的傳統(tǒng)工作流程是為深度神經(jīng)網(wǎng)絡(矩陣乘法和卷積)中的原始算子編寫著色器伶授,然后直接優(yōu)化性能断序。這是現(xiàn)有框架(TensorFlow.js)最新版本中使用了這種工作模式流纹。

TVM則與之相反,采用了基于編譯的方法违诗。TVM自動從TensorFlow漱凝,Keras,PyTorch较雕,MXNet和ONNX等高級框架中提取模型碉哑,使用機器學習驅動的方法自動生成低級代碼,在這種情況下亮蒋,將以SPIR-V格式計算著色器扣典。然后可以為可部署模塊生成的代碼打包。

編譯的方法的一個重要優(yōu)點是基礎架構的重用慎玖。通過重用基礎結構來優(yōu)化CUDA贮尖,Metal和OpenCL等本機平臺的GPU內核,能夠輕松地以Web為目標趁怔。如果WebGPU API到本機API的映射有效湿硝,可以通過很少的工作獲得類似的性能。更重要的是润努,AutoTVM基礎架構关斜,能夠針對特定模型專門化計算著色器,從而能夠為感興趣的特定模型生成最佳的計算著色器铺浇。

TVM已經(jīng)有Vulkan的SPIR-V目標痢畜,使用LLVM生成主機代碼△⒙拢可以僅將二者的用途重新生成設備和主機程序丁稀。

主要挑戰(zhàn)是runtime。需要一個runtime來加載著色器代碼倚聚,并使主機代碼對話能夠正確地與著色器通信线衫。TVM具有最低的基于C ++的runtime。構建了一個最小的Web runtime庫惑折,生成的著色器和主機驅動代碼鏈接授账,生成一個WASM文件。但是唬复,此WASM模塊仍然包含兩個未知的依賴項:

runtime需要調用系統(tǒng)庫調用(malloc矗积,stderr)。

wasmruntime需要與WebGPU驅動程序進行交互(在Javascript中敞咧,WebGPU API是the first-class citizen)棘捣。

WASI是解決第一個問題的標準解決方案。盡管網(wǎng)絡上還沒有成熟的WASI,使用Emscripten生成類似WASI的庫乍恐,提供這些系統(tǒng)庫评疗。

通過在TVM的JS runtime內部構建WebGPU runtime來解決第二個問題,在調用GPU代碼時茵烈,從WASM模塊中回調這些功能百匆。使用TVM runtime系統(tǒng)中的PackedFunc機制,可以通過將JavaScript閉包傳遞到WASM接口呜投,直接公開高級runtime原語加匈。這種方法將大多數(shù)runtime代碼保留在JavaScript中,隨著WASI和WASM支持的成熟仑荐,可以將更多JS代碼引入WASM runtime雕拼。

未來的某個時候,當WebGPU成熟粘招,通過WASI標準化時啥寇,可以將其定位為WebGPU的本機API,使用WebGPU的獨立WASM應用程序洒扎。

Reference

WebAssembly-Wiki

WebAssembly

WebAssembly – Where is it going?

WebAssembly SIMD

WasmEdge

WebGPU-wiki

Apache TVM

更多技術分享瀏覽我的博客:

https://thierryzhou.github.io

本文由mdnice多平臺發(fā)布

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末辑甜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袍冷,更是在濱河造成了極大的恐慌磷醋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胡诗,死亡現(xiàn)場離奇詭異子檀,居然都是意外死亡,警方通過查閱死者的電腦和手機乃戈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亩进,“玉大人症虑,你說我怎么就攤上這事」檠Γ” “怎么了谍憔?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長主籍。 經(jīng)常有香客問我习贫,道長,這世上最難降的妖魔是什么千元? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任苫昌,我火速辦了婚禮,結果婚禮上幸海,老公的妹妹穿的比我還像新娘祟身。我一直安慰自己奥务,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布袜硫。 她就那樣靜靜地躺著氯葬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婉陷。 梳的紋絲不亂的頭發(fā)上帚称,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音秽澳,去河邊找鬼闯睹。 笑死,一個胖子當著我的面吹牛肝集,可吹牛的內容都是我干的瞻坝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼杏瞻,長吁一口氣:“原來是場噩夢啊……” “哼所刀!你這毒婦竟也來了?” 一聲冷哼從身側響起捞挥,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浮创,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砌函,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斩披,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哨免。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片助析。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厕倍,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情贩疙,我是刑警寧澤讹弯,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站这溅,受9級特大地震影響组民,放射性物質發(fā)生泄漏。R本人自食惡果不足惜悲靴,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一臭胜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦庇楞、人聲如沸榜配。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛋褥。三九已至,卻和暖如春睛驳,著一層夾襖步出監(jiān)牢的瞬間烙心,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工乏沸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淫茵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓蹬跃,卻偏偏與公主長得像匙瘪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蝶缀,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容