deeplearnjs 简介

闲来再做回搬运工,感觉和机器翻译比起来并没啥优势。。。

deeplearn.js 是一个用于机器智能的开源 WebGL 加速的 JavaScript 库。deeplearn.js 为您的指尖带来高性能机器学习构建模块,允许您在浏览器中训练神经网络或在推理模式下运行预训练模型。

让我们来看看 deeplearn.js 中的一些核心概念。

Tensors

在 deeplearn.js 中数据的核心单元便是 tensor,一个 Tensor 由一组任意维数的数值型数组构成。
Tensors 由 shape 属性定义其形状。该库为低秩的张量(Tensors)提供了 sugar 般的子类:Scalar, Tensor1D, Tensor2D, Tensor3DTensor4D,以及一些用于构建它们的辅助函数。

例如使用一个 2x3 维矩阵:

let shape = [2, 3]; // 2 rows, 3 columns
let a = dl.tensor2d([1.0, 2.0, 3.0, 10.0, 20.0, 30.0], shape);
// deeplearn.js can also infer the shape
let b = dl.tensor2d([[0.0, 2.0], [4.0, 6.0]]);  // 2 rows, 2 columns

译者注:可见 shape 重新规定了前面数组的形状。

Tensor 既可以用一个 WebGLTexture 将数据存到 GPU,或者以 JavaScript TypedArray 的形式存到 CPU 上。大多时候,用户都无需考虑存储问题,因为它是一个实现细节。

有个地方你得好好想想其差异的,就是当从一个 Tensor 取出数据时,例如在调试时:

let a = dl.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
a = a.square();

// Async call to get the data from the tensor
a.data().then(data => console.log('The data TypedArray', data));

// Alternatively we can also call this synchronously
let data = a.dataSync();
console.log('The data TypedArray', data);

在上例中,我们首先创建了一个 tensor,然后在其上调用了一个数学操作。这会将该 tensor 自动上传到 GPU。当我们想在 JavaScript 上下文使用它时(如打印出来),我们调用 data()dataSync() 将其下载到 CPU 内存中。请注意这是一个相对有代价的操作,所以你可能倾向于异步调用的版本。

译者注:需要搞明白的是——数据从哪导到哪,怎样的过程有什么开销,以及哪些数据该在 GPU 运算更好

Operations (Ops)

Tensors 允许我们存储数据,同时 Ops 允许我们操纵数据。deeplearn.js 带有大量的适合于线性代数和机器学习的数学运算。它们有像square()的一元运算,像add()的二元运算以及mul()这样的对某个 tensors 进行变换并返回一个新的 tensors 结果的运算。

let a = dl.tensor2d([[1.0, 2.0], [3.0, 4.0]]);  // tensor 
let b = dl.tensor2d([[0.0, 2.0], [4.0, 6.0]]);  // tensor 

// The library has a chainable API allowing you to call operations
// directly as methods on Tensors.
let average = a.sub(b).square().mean();

// All operations are also exposed as functions in the main namespace
// so we could also do.
// 译者注:这些方法不仅每个 tensor 实例都有,而且在 dl 这个命名空间上能直接访问到
let avg = dl.mean(dl.square(dl.sub(a, b)));

Tidy Operations

因为 deeplearn.js 使用了GPU加速数学运算,因此有必要管理GPU内存。在常规的 JavaScript 中,这部分工作由作用域(Scopes)处理,而在这里,我们提供了一个便捷的函数对 tensors
执行操作时所产生的中间内存进行清理。

我们把这个函数称作dl.tidy.

let a = dl.tensor2d([1.0, 2.0, 3.0, 4.0]);

// dl.tidy takes a function to tidy up after
let average = dl.tidy(() => {
  // dl.tidy will clean up all the GPU memory used by tensors inside
  // this function, other than the tensor that is returned.
  //
  // Even in a short sequence of operations like the one below, a number
  // of intermediate tensors get created. So it is a good practice to
  // put your math ops in a tidy!
  return a.sub(b).square().mean();
});

运用dl.tidy()有助于防止应用程序的内存泄漏,并且能更谨慎地控制何时内存回收。

手动方式清理 tensor 内存是dispose方法。

let a = dl.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
a = a.square();
a.dispose(); // Clean up GPU buffer

相比,使用dl.tidy函数更方便些。

Training

许多机器学习的核心问题是实质上是训练机器完成一些任务的问题。在 deeplearn.js 中,这一过程被封装在Optimizers(优化器)中。优化器是逐步调整模型变量的策略,目的是减少模型预测的错误(或者按机器学习的说法是减少损失)。

我们在教程中涵盖了训练和优化器,这里是 deeplearn.js 如何进行训练的一个大概轮廓:

import * as dl from 'deeplearn';

// 初始化模型变量
const weights = dl.variable(dl.randomNormal([10, 64]));
const biases = dl.variable(dl.zeros([64]));

// 设置学习率和创建优化器.
const LEARNING_RATE = .1;
const optimizer = dl.train.sgd(LEARNING_RATE)

/*
 * 进行推断并返回预测结果
 */
function inference(input) { }

/**
 * 通过比较预测值和真实值,计算模型损失
 *
 * 返回一个标量损失值 (如,单数值的张量)
 */
function loss(predictions, labels) { }

/**
 * 模型的单步训练
 */
function trainStep(data, labels, returnCost = true) {
  // Calling optimizer.minimize will adjust the variables in the
  // model based on the loss value returned by your loss function.
  // It handles all the backpropogation and weight updates.
  const cost = optimizer.minimize(() => {
    // Any variables used in this inference function will be optimized
    // by the optimizer.

    // Make a prediction using the current state of the model
    const prediction = inference(data);

    // Compute loss of the current model and return it. Calculating this loss
    // should involve the variables we are trying to optimize.
    //
    // Once we return the less the optimizer will adjust the network
    // weights for our next iteration.
    return loss(prediction, labels);
  }, returnCost);

  // return the current loss/cost so that we can visualize it
  return cost;
}

/**
 * 训练模型.
 *
 * 通过循环调用上述单步训练 trainStep. 用 `await dl.nextFrame()` 避免阻塞浏览器
 *
 * 可在此加载、批处理、清洗你的数据
 */
function train(data) { }

Backends

该库提供了一些后台来执行本库的核心数学运算,目前我们有一个 CPU 后台和一个 WebGL 后台,deeplearn.js 只要浏览器支持,是默认使用 WebGL 后台。WebGL 后台使用的是计算机的 GPU,旨在执行快速和高度优化的线性代数内核。

若强制使用 CPU 后台,你可以程序开始处调用dl.setBackend('cpu')

检查哪种后台正在被使用,可以调用dl.getBackend()

WebGL 后台

在使用WebGL后台时,数学运算如dl.add() 会推入着色器程序到GPU上执行。不像在CPU后台中那样,这些操作是不阻塞的(尽管将数据从主内存移动到GPU内存会有一些开销)。

这些着色器程序从 WebGLTextures 读取和写入。在链接数学运算时,textures 可以留在GPU内存中,这对性能非常重要。

你可以通过调用 tensor 的 data() 方法,定期从 gpu 下载数据,这样你就可以在你的主 Javascript 线程中读取这些数据。

获取两个矩阵之间均方差的例子:

const a = dl.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
const b = dl.tensor2d([[0.0, 2.0], [4.0, 6.0]]);

// All these operations will execute on the GPU (if available)
// without blocking the main thread.
const diff = dl.sub(a, b);

// Calling .data returns a promise that resolves to a TypedArray that holds
// the tensor data downloaded from the GPU.
diff.data().then(d => console.log('difference: ' + d));
// We could also use dataSync to do this synchronously.
console.log('difference: ' + diff.dataSync());

TIP: Avoid calling data()/dataSync() between mathematical GPU operations unless you are debugging. This forces a texture download, and subsequent operation calls will have to re-upload the data to a new texture.

CPU 后台

在使用CPU实现时,这些数学运算会阻塞,然后立即在主 JavaScript 线程隐含的 TypedArray 上执行 。

相同的操作在两种后台中都被实现,因此你的代码无需根据客户端上使用的后台进行更改。

想了解更多?请阅读这些教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容