TensorFlow.js 中的核心概念

TensorFlow.js 是一个开源的用于开发机器学习项目的 WebGL-accelerated javascript 库。TensorFlow.js 可以为你提供高性能的、易于使用的机器学习构建模块,允许你在浏览器上训练模型,或以推断模式运行预训练的模型。TensorFlow.js 不仅可以提供低级的机器学习构建模块,还可以提供高级的类似 Keras 的 API 来构建神经网络。

一、张量:tensors

tensor 是 TensorFlow.js 的数据中心单元:由一组数值组成的一维或多维数组。Tensor 实例的 shape 属性定义了这个数组的形状(例如:数组的每个维度有多少个值)。

最主要的 Tensor 构造函数是 tf.tensor 函数

// 2x3 Tensor
const shape = [2, 3]; // 可以看做是两行三列组成
const a = tf.tensor([1.0, 2.0, 3.0, 10.0, 20.0, 30.0], shape);
a.print(); 
// Output: [[1 , 2 , 3 ],
//          [10, 20, 30]]

// The shape can also be inferred:
const b = tf.tensor([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
b.print();
// Output: [[1 , 2 , 3 ],
//          [10, 20, 30]]

但是,在构建低阶张量时,为了提高代码的可读性,我们推荐使用下列的函数:

// 0阶张量,即标量
tf.scalar(3.14).print(); // 3.140000104904175, 默认dtype 是 float32
tf.scalar(3.14, 'float32').print(); // 3.140000104904175
tf.scalar(3.14, 'int32').print(); // 3
tf.scalar(3.14, 'bool').print(); // 1

// 1阶张量
tf.tensor1d([1, 2, 3]).print(); // [1, 2, 3]

// 2阶张量
// Pass a nested array.
tf.tensor2d([[1, 2], [3, 4]]).print();
// Pass a flat array and specify a shape.
tf.tensor2d([1, 2, 3, 4], [2, 2]).print();
// ouput
//    [[1, 2],
//   [3, 4]]

// 3阶张量
// Pass a nested array.
tf.tensor3d([[[1], [2]], [[3], [4]]]).print();
// Pass a flat array and specify a shape.
tf.tensor3d([1, 2, 3, 4], [2, 2, 1]).print();
// output
//    [[[1],
//      [2]],

//     [[3],
//      [4]]]

// 4阶张量
// Pass a nested array.
tf.tensor4d([[[[1], [2]], [[3], [4]]]]).print();
// Pass a flat array and specify a shape.
tf.tensor4d([1, 2, 3, 4], [1, 2, 2, 1]).print();
// output
//    [[[[1],
//       [2]],

//      [[3],
//       [4]]]]

上述 5个低阶张量的表示方法,除了 scalar 和 tensor1d 两方法没有 shape 属性外,其它的都会传入values、shape、dtype 三个参数,注意有无 shape 传入时,values 的表示方式。
TensorFlow.js 也提供了把 Tensor 实例中的所有元素的值重置为 0 和 1 方法:

// 3x5 Tensor with all values set to 0
const zeros = tf.zeros([3, 5]);
// Output: [[0, 0, 0, 0, 0],
//          [0, 0, 0, 0, 0],
//          [0, 0, 0, 0, 0]]

// 2X2 Tensor with all values set to 1
tf.ones([2, 2]).print(); 
// output 
//     [[1, 1],
//     [1, 1]]

在 TensorFlow.js 中,张量值是不可改变的;一旦创建,你就不能改变它的值。相反,如果你执行 operations(ops) 操作,就可以生成新的张量值。

二、变量:variables

variables 是用一个张量值初始化的。不像张量(tensor),值不可改变。你可以使用 assign 方法给一个存在的变量(variable)分配一个新的张量:

const initialValues = tf.zeros([5]);
const biases = tf.variable(initialValues); // 初始化偏差(距离原点的截距或偏移)
biases.print(); // output: [0, 0, 0, 0, 0]

const updatedValues = tf.tensor1d([0, 1, 0, 1, 0]);
biases.assign(updatedValues); // update values of biases
biases.print(); // output: [0, 1, 0, 1, 0]

变量(variable)主要是用于在模型训练时,进行数据的保存和更新。

三、操作:operations(ops)

tensors 可以用保存数据,而 operations 可以操作数据。TensorFlow.js 提供了多种适用于张量的线性代数和机器学习的运算的 operations。由于张量是不可改变的,所以 operations 操作并不会改变 tensors 的值,而是返回新的张量。
1、operations 提供了类似 square 等一元运算:

const x = tf.tensor1d([1, 2, Math.sqrt(2), -1]);
x.square().print();  // or tf.square(x)
// [1, 4, 1.9999999, 1]

const x = tf.tensor1d([1, 2, 4, -1]);
x.sqrt().print();  // or tf.sqrt(x)
// [1, 1.4142135, 2, NaN]

2、operations 提供了类似 add、sub 等二元运算:

const a = tf.tensor1d([1, 2, 3, 4]);
const b = tf.tensor1d([10, 20, 30, 40]);

a.add(b).print();  // or tf.add(a, b)
// [11, 22, 33, 44]

3、支持链式操作:

const e = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
const f = tf.tensor2d([[5.0, 6.0], [7.0, 8.0]])
const sq_sum = e.add(f).square();
sq_sum.print();
// Output: [[36 , 64 ],
//          [100, 144]]

// 所有的操作都暴露在函数的命名空间中,也可以进行下面操作,得到相同的结果
const sq_sum = tf.square(tf.add(e, f));

四、模型和层

从概念上看,一个模型就是一个函数,给定相应输入得到期望的输出。
在 TensorFlow.js 中,有两种创建模型的方式:
1、通过使用 ops 直接创建模型

// Define function
function predict(input) {
  // y = a * x ^ 2 + b * x + c
  return tf.tidy(() => {
    const x = tf.scalar(input);

    const ax2 = a.mul(x.square());
    const bx = b.mul(x);
    const y = ax2.add(bx).add(c);

    return y;
  });
}

// Define constants: y = 2x^2 + 4x + 8
const a = tf.scalar(2);
const b = tf.scalar(4);
const c = tf.scalar(8);

// Predict output for input of 2
const result = predict(2);
result.print() // Output: 24

这是一个二元方程式求解的表示法。
2、也可以使用高级 API tf.model 来构建以层定义的模型,这在深度学习中是一种常用的抽象形式
下面简单的线性回归的定义为例:

const model = tf.sequential();
model.add(
  tf.layers.simpleRNN({
    units: 20,
    recurrentInitializer: 'GlorotNormal',
    inputShape: [80, 4]
  })
);

const optimizer = tf.train.sgd(LEARNING_RATE);
model.compile({optimizer, loss: 'categoricalCrossentropy'});
model.fit({x: data, y: labels)});

上述例子中通过创建一个线性回归模型,调用 simpleRNN 层,通过 sgd 优化算法训练,得到期望效果。
在 TensorFlow.js 中有很多不同类型的层(layers)表示法,例如 tf.layers.simpleRNN, tf.layers.gru, 和tf.layers.lstm等等。

五、内存管理:dispose 和 tf.tidy

由于,tensorFlow.js 使用了 GPU 加速数学运算,在使用张量和变量时,管理 GPU 的内存是必不可少的。
TensorFlow.js 提供了 disposetf.tidy 两个函数来帮助处理内存:
1、dispose
你可以调用一个张量或变量来清除和释放它的 GPU 内存。

const x = tf.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
const x_squared = x.square();

x.dispose();
x_squared.dispose();

2、tf.tidy
在做大量张量操作时,使用 dispose 可能很笨重。TensorFlow.js 提供了另一个功能 tf.tidy,它在 JavaScript 中扮演着类似的角色,除了 gpu 支持的张量。
tf.tidy 会执行一个功能,清除任何创建的中间张量,释放它们的 GPU 内存。但它不会清除内部函数的返回值。

// tf.tidy takes a function to tidy up after
const average = tf.tidy(() => {

// tf.tidy 会清除在这个函数内的张量使用的所有GPU内存,而不是返回的张量。
// 即使在像下面这样的一个简短的操作序列中,也会创建一些中间的张量。所以,把 ops 放在 tidy 函数中是一个好的选择

  const y = tf.tensor1d([1.0, 2.0, 3.0, 4.0]);
  const z = tf.ones([4]);

  return y.sub(z).square().mean();
});

average.print() // Output: 3.5

使用 tf.tidy 将有助于防止应用程序中的内存泄漏。当内存被回收时,它也可以用来更小心地控制。

3、两个注意点

  • 传递给 tf.tidy 函数是同步的,不会返回一个 Promise 对象。建议保留更新UI的代码,或者在tf.tidy之外发出远程请求。
  • tf.tidy 不会清理变量。变量通常贯穿于机器学习模型的整个生命周期中,在 TensorFlow.js 中,即使是在 tf.tidy 里创建,js也不会清理它们;但是,你可以手动调用 dispose。

六、补充

类似还有EnvironmentConstraintsInitializersRegularizers.

戳我博客

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

推荐阅读更多精彩内容