根據 GitHub Octoverse 2017 報告,JavaScript 是過去一年中 GitHub 最流行的編程語言。根據 pull requests 的數量,JavaScript 的體量與 Python、Java 以及 Go 語言的總和相當。
JavaScript 已經征服了 Web,并在服務器、移動電話、桌面和其他平臺上取得了進展。
與此同時,GPU 加速的使用已經遠遠超出了計算機圖形學的范圍,它現在已經成為機器學習的一個組成部分。
訓練深層神經網絡是一個計算密集型過程,深度神經網絡在機器智能的許多重要領域得到了當前最優結果。
本文著眼于這些趨勢的持續融合,并概述了將 GPU 加速的神經網絡引入 JavaScript 的一些項目。

概述
本文列出的所有項目都是正被社區積極維護的,它們在 GitHub 上有著數千 stars,并且通過 NPM 或 CDN 進行分發。
它們都是通過 WebGL 在瀏覽器中實現 GPU 加速的,如果沒有合適的顯卡,則返回到 CPU 模式。
本概述不包含旨在運行現有模型(尤其是使用 Python 訓練的模型)的庫。
最后,有 4 個項目被列入清單。
盡管 deeplearn.js 的特征集是面向神經網絡的,但是它也可被看作是一個通用的機器學習框架。Propel 是一個用于科學計算的庫,提供自動微分功能。gpu.js 提供了在 GPU 上運行 JavaScript 函數的便捷方式。Brain.js 是一個較老的神經網絡庫的延續,它使用 gpu.js 來完成硬件加速。

Deeplearn.js
Deeplearn.js 是以上四個項目中最流行的,被描述為「用于機器智能的硬件加速 JavaScript 庫」。它由 Google Brain 團隊和一個超過 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 中卷積層的定義
deeplearn.js 是仿照 TensorFlow 用 TypeScript 寫成的。deeplearn.js 支持由 Google Brain 主要開源項目提供的一個功能子集。API 基本上擁有 3 個部分(API http://www.deeplearnjs.org/docs/api/index.html)。
第一部分包括用來創建、初始化以及變換張量的函數(http://www.deeplearnjs.org/docs/api/index.html#Tensors-Creation),用類似數組的結構來保存數據。
第二部分提供了在張量上執行的操作(http://www.deeplearnjs.org/docs/api/index.html#Operations-Arithmetic),包括基本的數學運算、規約(reduction)、正則化以及卷積。對循環神經網絡的支持目前還處于初級階段,但是已包括 LSTM 單元的堆疊(http://www.deeplearnjs.org/docs/api/index.html#dl.multiRNNCell)。
API 的第三部分圍繞模型訓練展開。所有流行優化器,從隨機梯度下降到 Adam 都包含在其中。不過,目前 reference 中提及的損失函數只有交叉熵損失函數。
API 其他部分用來進行環境設置和資源管理。
可以通過 headless-gl(https://github.com/stackgl/headless-gl0)在 node.js 中實現 GPU 加速的實驗(參見 issue #49,https://github.com/PAIR-code/deeplearnjs/issues/49)。
項目網站有很多優秀的 demo(http://www.deeplearnjs.org/index.html#demos),包括使用循環神經網絡進行鋼琴演奏、用來構建模型的可視化界面,以及基于 SqueezeNet(一個使用較少參數的圖像分類器)的 webcam 應用。
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 數據集上使用 Propel 訓練一個三層的前饋神經網絡。
自動微分(AD)是這個項目的核心,它使得我們無需手動指定導數。給定一個由支持的張量運算定義的函數 f(x),它的梯度函數可以使用 grad(http://propelml.org/docs/#grad)得到。多變量的情況可以使用 multigrad 完成(http://propelml.org/docs/#multigrad)。
除了自動微分之外,目前尚不清楚該項目的方向。雖然網站上提到其目標是成為「類似 numpy 的基礎架構」,但該項目目前仍在開發中,并且包含與神經網絡(http://propelml.org/docs/#conv2d)和計算機視覺(http://propelml.org/docs/#imread)相關的功能。npy 文件的內容可以通過 load 函數(http://propelml.org/docs/#load)進行解析,并作為張量使用。
在瀏覽器環境中,PropelJS 利用了 deeplearn.js 中的 WebGL 功能。對于節點中的 GPU 加速,該項目則使用了 TensorFlow 的 C API。
gpu.js
雖然我的大部分經驗是使用 CUDA 而不是 WebGL,但我可以證明 GPU 編程的耗時性。因此,當我遇到 gpu.js 時,我感到非常意外。該項目在 GitHub 上擁有約 5700 個 stars,在知名度方面與 deeplearn .js 相當,共有 18 位貢獻者。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 的子集(https://github.com/gpujs/gpu.js#creating-and-running-functions)編寫。然后編譯代碼并在 GPU 上運行。幾周前,gpu.js 支持基于 OpenCL 的 Node.JS(https://github.com/mikeseven/node-opencl/issues/55)。
數字和最多具有三維的數組被用作輸入和輸出。除了基本的數學運算之外,gpu.js 還支持局部變量、循環和 if/else 語句。
為了實現代碼重用并允許更多模塊化設計,你們可以注冊自定義函數 ( https://github.com/gpujs/gpu.js#adding-custom-functions #),然后從內核代碼中使用。
在內核的 JavaScript 定義中,this 對象提供線程標識符,并存儲在實際內核里是常量、在外部是動態變量的值。
該項目專門研究加速 JavaScript 函數,并不試圖提供神經網絡框架。為此,我們可以求助一個依賴 gpu.js 的庫。
Brain.js
Brain.js 繼承自 harthur/brain(https://github.com/harthur/brain),一個可以回溯至 2010 年的 repo。
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 人對這兩個 repo 做出了貢獻。
對 GPU 加速神經網絡的支持基于 GPU.js,這可以算得上該項目近期最重要的進展了。
除了前饋網絡之外,Brain.js 還包括三種重要 RNN 類型的實現(https://github.com/BrainJS/brain.js#neural-network-types):經典 Elman 網絡、LSTM,以及具備門控循環單元的近期網絡。
該 repo 包含的 demo 處于早期階段。源代碼中還有另外兩個演示 ( https://github.com/BrainJS/brain.js/tree/develop/examples),其中一個 demo 涉及檢測用 ASCII 碼繪制的字符。
針對機器學習的加速 JavaScript 庫有很多有趣的應用。
在線課程可以將與機器學習或 GPU 計算相關的練習直接集成到 web 應用程序中。學生不必跨不同的操作系統和軟件版本去設置單獨的開發環境。
許多基于神經網絡的 demo 可以更容易地部署,并且不再需要服務器端 API。
對機器學習感興趣的 JavaScript 開發者可以充分利用他們的專業技能,在集成問題上花費更少的時間。
此外,客戶端上的可用計算資源應該被更好地利用。畢竟,并非所有的顯卡都一直用于虛擬現實和挖礦。
需要說清楚,我現在并不主張將本文中提到的庫用于任務關鍵型神經網絡。Python 生態系統仍然是大多數應用程序的首選。
然而,過去 12 個月取得的進展確實令人鼓舞。一年前既沒有 deeplearn.js,也沒有 Propel。彼時 gpu.js repo 中的活動水平相對較低,Brain.js 也不支持 GPU 加速。
隨著時間的推移,這些項目將在某些方面與已建立的框架發生競爭,并催生出 JavaScript 完美適合的全新應用。
https://towardsdatascience.com/gpu-accelerated-neural-networks-in-javascript-195d6f8e69ef
 
     
  
     
 
              
 
       
       
       
      














 
				
				