JavaScript已經征服了網絡,並“滲入”了服務器、移動端、桌面和其他平臺。
與此同時,GPU加速的使用已經遠遠超出了計算機圖形領域,現在已經成為機器學習的一個必需組成部分。
訓練神經網絡與深層架構是一個計算密集型過程,在機器智能領域帶來了許多重要的先進結果。
本文著眼於這些趨勢的不斷融合,並提供了將GPU加速的神經網絡引入到JavaScript世界的一些項目的概述。
概述
下面列出的所有項目都是受到了積極維護的,在Github上有數千顆星,而且在NPM或CDN上也有分佈。
它們都是通過WebGL在瀏覽器中實現GPU加速,如果不存在合適的顯卡則可以退回到CPU。
本概述中不包括那些旨在運行現有模型的庫(特別是那些使用Python框架訓練的模型)。
最後,四個項目榜上有名。
雖然它的特性集面向神經網絡,但deeplearn.js可以被描述為通用機器學習框架。Propel是一個提供自動微分的科學計算的庫。Gpu.js提供了一種方便的方式來運行GPU上的JavaScript函數。Brain.js是舊的神經網絡庫的延續,並使用Gpu.js硬件加速。
Deeplearn.js
Deeplearn.js是這四個中最受歡迎的項目,被描述為“用於機器智能的硬件加速JavaScript庫”。它由谷歌大腦團隊和超過50個貢獻者組成的社區提供支持。兩位主要作者是Daniel Smilkov和Nikhil Thorat。
import * as dl from 'deeplearn'
const xs = inputXs.as4D(-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1)
const conv1Weights = dl.variable(
dl.randomNormal([FILTER_HEIGHT, FILTER_WIDTH, 1, NUMBER_FILTERS], 0, 0.1) as dl.Tensor4D)
const layer1 = dl.tidy(() => {
return xs.conv2d(conv1Weights, 1, 'same')
.relu()
.maxPool([2, 2], STRIDES, PADDING)
})
在deeplearn.js中定義卷積層
在TypeScript中編寫,且仿照Tensorflow,deeplearn.js支持谷歌大腦的旗艦開源項目中所提供功能的日益增長的部分。API有三個部分。
第一部分介紹了用於創建、初始化和轉換張量的函數,即用於保存數據的類似數組的結構。
API的下一部分提供了在張量上執行的操作。這包括基本的數學運算,還原,歸一化和卷積。在這一點上,對遞歸神經網絡的支持是不成熟的,但它包含了大量的長短期記憶網絡細胞。
第三部分圍繞模型訓練展開。所有流行的優化器,從隨機梯度下降(SGD)到Adam都包括在內。另一方面,交叉熵損失函數是文獻中提到的唯一損失函數。
API的其餘部分用於設置環境和管理資源。
node.js上的實驗GPU加速,可以通過headless-gl實現。
該項目網站有許多令人難忘的演示。其中包括由一個由遞歸神經網絡生成的鋼琴表演,一個建立模型的視覺界面和一個基於SqueezeNet(一個參數相對較少的圖像分類器)的網絡攝像頭應用。
PropelJS
PropelJS被描述為“JavaScript的可微分編程”。主要作者是Ryan Dahl和Bert Belder,其工作得到了11位社區貢獻者的補充。
import * as pr from "propel"
export async function train(maxSteps = 0) {
const ds = pr.dataset("mnist/train").batch(128).repeat(100)
const exp = await pr.experiment("exp001")
for (const batchPromise of ds) {
const { images, labels } = await batchPromise
exp.sgd({ lr: 0.01 }, (params) =>
images.rescale([0, 255], [-1, 1])
.linear("L1", params, 200).relu()
.linear("L2", params, 100).relu()
.linear("L3", params, 10)
.softmaxLoss(labels))
if (maxSteps && exp.step >= maxSteps) break
}
}
一種前饋神經網絡,它有三個層次的訓練,在MNIST數據集上進行了訓練
自動微分(AD)是這個項目的核心,使我們不必手動指定衍生品。對於一個給定的函數f(x)定義了受支持的張量操作,梯度函數可以用grad來得到。多變量案例由multigrad覆蓋。
除了AD之外,項目的方向似乎並不完全清楚。雖然在網站上提到了“類似numpy 的基礎架構”作為目標,但是API在“繁重的開發”下,包括與神經網絡和計算機視覺相關的功能。使用load函數,可以解析npy文件的內容並作為張量使用。
在瀏覽器環境中,PropelJS使用了deeplearn.js中的WebGL功能。對於節點的GPU加速,項目使用了TensorFlow的C API。
gpu.js
雖然筆者常用的是CUDA而不是WebGL,但可以證明GPU編程的耗時性。因此,當筆者遇到gpu.js時,感到非常驚喜。Github上大約有5700顆星,這個項目有有18個貢獻者,其受歡迎程度可以與deeplearn.js媲美。隨著時間的推移,有幾個人做出了巨大的貢獻。Robert Plummer是主要作者。
import GPU from 'gpu.js'
const gpu = new GPU()
const multiplyMatrix = gpu.createKernel(function(a, b) {
var sum = 0;
for (var i = 0; i < 512; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
}).setOutput([512, 512])
通過gpu.js實現矩陣乘法:在GPU編程中Hello World是等同的
一個內核,在當前上下文中,是在GPU上執行的函數,而不是CPU。通過gpu.js,內核可以在JavaScript的一個子集中編寫。然後編譯代碼並在GPU上運行。Node.js通過OpenCL的支持已經在幾個星期前增加了。
數字和數字數組的三個維度被用作輸入和輸出。除了基本的數學運算,gpu.js支持局部變量、循環和if/else語句。
為了使代碼重用和允許更模塊化的設計,可以在內核代碼中註冊和使用自定義函數。
在內核的JavaScript定義中,該對象提供了線程標識符,並持有在實際內核中保持不變的值,但在外部是動態的。
該項目專門研究加速JavaScript函數,並沒有嘗試提供一個神經網絡框架。為此,我們可以轉向一個取決於gpu.js的庫。
Brain.js
Brain.js是harthur/brain的繼承者,後者是一個可以追溯到2010年的歷史內容庫。
import brain from 'brain.js'
const network = new brain.recurrent.RNN()
const data = [
{input: [0, 0], output: [0]},
{input: [0, 1], output: [1]},
{input: [1, 0], output: [1]},
{input: [1, 1], output: [0]}
]
network.train(data)
總共有近30個人參與了這兩個內容庫。
對GPU加速的神經網絡的支持基於gpu.js,而且,可以說,這是該項目近期最重要的進展。
除了前饋網絡,Brain.js包括三種重要類型的遞歸神經網絡的實現:經典Elman網絡,長短期記憶網絡,以及最近的有門控的週期性單元的網絡。
主頁上顯示了一個學習顏色對比偏好的神經網絡。在源代碼中可以找到另外兩個演示,其中一個涉及到使用ASCII符號繪製的字符。
機器學習加速JavaScript庫的出現有幾個有趣的含義
在線課程可以將與機器學習或GPU計算相關的練習直接融入到web應用程序中。學生不必在不同的操作系統和軟件版本之間建立單獨的開發環境。
基於神經網絡的許多演示可以更輕鬆地部署,不再需要服務器端API。
對機器學習感興趣的JavaScript開發人員可以充分利用他們的專業技能,在集成問題上花費更少的時間。
此外,客戶端可用的計算資源可能更有效地使用。畢竟,並不是所有的顯卡都被用於虛擬現實和加密貨幣的挖掘。
要說明的是,筆者並不提倡將本文中提到的庫用於關鍵任務的神經網絡。Python的生態系統仍然是大多數應用程序的首選。
然而令人鼓舞的是,過去12個月裡取得了明顯的進展。Deeplearn.js在一年前並不存在。Gpu.js的活躍水平相對較低,Brain.js不支持GPU加速。
隨著時間的推移,這些項目將在某些方面與已建立的框架相競爭,並在某些最適合JavaScript的全新應用程序中使用。
閱讀更多 AI中國 的文章