【IT168 编译】根据Github Octoverse 2017的报告,JavaScript是Github上最流行的语言。根据拉取请求的数量来衡量,JavaScript的活跃度与Python、Java和Go之和相当。
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的全新应用程序中使用。