TensorFlow.js 是一個(gè)用于機(jī)器智能的開源基于 WebGL 加速的 JavaScript 庫(kù)。 它將高性能機(jī)器學(xué)習(xí)構(gòu)建塊帶到您的指尖,使您能夠在瀏覽器中訓(xùn)練神經(jīng)網(wǎng)絡(luò)或在推理模式下運(yùn)行預(yù)先訓(xùn)練的模型。 有關(guān)安裝/配置TensorFlow.js的指南,請(qǐng)參閱 Tensorflow.js 安裝。
TensorFlow.js 為機(jī)器學(xué)習(xí)提供低級(jí)構(gòu)建模塊,以及構(gòu)建神經(jīng)網(wǎng)絡(luò)的高級(jí) Keras 啟發(fā)式 API。 我們來看看庫(kù)的一些核心組件。
tensor 是 TensorFlow.js 的數(shù)據(jù)中心單元:由一組數(shù)值組成的一維或多維數(shù)組。Tensor 實(shí)例的 shape 屬性定義了這個(gè)數(shù)組的形狀(例如:數(shù)組的每個(gè)維度有多少個(gè)值)。
最主要的 Tensor 構(gòu)造函數(shù)是 tf.tensor 函數(shù)
// 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]]
但是,在構(gòu)建低階張量時(shí),為了提高代碼的可讀性,我們推薦使用下列的函數(shù):
// 0階張量,即標(biāo)量
tf.scalar(3.14).print(); // 3.140000104904175, 默認(rèn)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個(gè)低階張量的表示方法,除了 scalar 和 tensor1d 兩方法沒有 shape 屬性外,其它的都會(huì)傳入values、shape、dtype 三個(gè)參數(shù),注意有無 shape 傳入時(shí),values 的表示方式。 TensorFlow.js 也提供了把 Tensor 實(shí)例中的所有元素的值重置為 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 中,張量值是不可改變的;一旦創(chuàng)建,你就不能改變它的值。相反,如果你執(zhí)行 operations(ops) 操作,就可以生成新的張量值。
variables 是用一個(gè)張量值初始化的。不像張量(tensor),值不可改變。你可以使用 assign 方法給一個(gè)存在的變量(variable)分配一個(gè)新的張量:
const initialValues = tf.zeros([5]);
const biases = tf.variable(initialValues); // 初始化偏差(距離原點(diǎn)的截距或偏移)
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)主要是用于在模型訓(xùn)練時(shí),進(jìn)行數(shù)據(jù)的保存和更新。
tensors 可以用保存數(shù)據(jù),而 operations 可以操作數(shù)據(jù)。TensorFlow.js 提供了多種適用于張量的線性代數(shù)和機(jī)器學(xué)習(xí)的運(yùn)算的 operations。由于張量是不可改變的,所以 operations 操作并不會(huì)改變 tensors 的值,而是返回新的張量。
1、operations 提供了類似 square 等一元運(yùn)算:
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 等二元運(yùn)算:
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、支持鏈?zhǔn)讲僮鳎?/p>
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]]
// 所有的操作都暴露在函數(shù)的命名空間中,也可以進(jìn)行下面操作,得到相同的結(jié)果
const sq_sum = tf.square(tf.add(e, f));
從概念上看,一個(gè)模型就是一個(gè)函數(shù),給定相應(yīng)輸入得到期望的輸出。 在 TensorFlow.js 中,有兩種創(chuàng)建模型的方式:
1、通過使用 ops 直接創(chuàng)建模型
// 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
這是一個(gè)二元方程式求解的表示法。
2、也可以使用高級(jí) API tf.model 來構(gòu)建以層定義的模型,這在深度學(xué)習(xí)中是一種常用的抽象形式
下面簡(jiǎn)單的線性回歸的定義為例:
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)});
上述例子中通過創(chuàng)建一個(gè)線性回歸模型,調(diào)用 simpleRNN 層,通過 sgd 優(yōu)化算法訓(xùn)練,得到期望效果。
在 TensorFlow.js 中有很多不同類型的層(layers)表示法,例如 tf.layers.simpleRNN, tf.layers.gru, 和 tf.layers.lstm 等等。
由于,tensorFlow.js 使用了 GPU 加速數(shù)學(xué)運(yùn)算,在使用張量和變量時(shí),管理 GPU 的內(nèi)存是必不可少的。 TensorFlow.js 提供了 dispose 和 tf.tidy 兩個(gè)函數(shù)來幫助處理內(nèi)存:
1、dispose
你可以調(diào)用一個(gè)張量或變量來清除和釋放它的 GPU 內(nèi)存。
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
在做大量張量操作時(shí),使用 dispose 可能很笨重。TensorFlow.js 提供了另一個(gè)功能 tf.tidy,它在 JavaScript 中扮演著類似的角色,除了 gpu 支持的張量。
tf.tidy 會(huì)執(zhí)行一個(gè)功能,清除任何創(chuàng)建的中間張量,釋放它們的 GPU 內(nèi)存。但它不會(huì)清除內(nèi)部函數(shù)的返回值。
// tf.tidy takes a function to tidy up after
const average = tf.tidy(() => {
// tf.tidy 會(huì)清除在這個(gè)函數(shù)內(nèi)的張量使用的所有GPU內(nèi)存,而不是返回的張量。
// 即使在像下面這樣的一個(gè)簡(jiǎn)短的操作序列中,也會(huì)創(chuàng)建一些中間的張量。所以,把 ops 放在 tidy 函數(shù)中是一個(gè)好的選擇
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 將有助于防止應(yīng)用程序中的內(nèi)存泄漏。當(dāng)內(nèi)存被回收時(shí),它也可以用來更小心地控制。
3、兩個(gè)注意點(diǎn)
更多建議: