Tensorflow.js 模型

2020-09-04 10:25 更新

機器學習中,一個 model 是一個帶有可訓練參數(shù)的函數(shù)。這個函數(shù)將輸入轉(zhuǎn)化為輸出。通俗的來說,這個函數(shù)表達了輸入和輸出之間的變換關(guān)系。我們通過在數(shù)據(jù)集上訓練模型來獲得最佳參數(shù)。訓練好的模型可以精確的將輸入數(shù)據(jù)轉(zhuǎn)換為我們想得到的輸出。

TensorFlow.js 有兩種創(chuàng)建機器學習的方法:

  1. 用 Layers API(用 layers 來創(chuàng)建模型)
  2. 用 Core API(底端算子,例如 tf.matMul() 或 tf.add() 等)來建立模型

我們首先會用高層API:Layers API來建立模型。然后,我們會展示如何用Core API來搭建相同的模型。

用Layers API創(chuàng)建模型

Layers API有兩種方式創(chuàng)建模型:第一種是創(chuàng)建 sequential 模型,第二種是創(chuàng)建 functional 模型。下面兩段會分別解釋這兩種模型創(chuàng)建方式。

使用sequential model

最常見的模型是 Sequential 模型。Sequential 模型將網(wǎng)絡(luò)的每一層簡單的疊在一起。您可以將需要的層按順序?qū)懺谝粋€列表里,然后將列表作為 sequential() 函數(shù)的輸入:

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

或用 add() 方法:

const model = tf.sequential();
model.add(tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}));
model.add(tf.layers.dense({units: 10, activation: 'softmax'}));
注意:模型的第一層需要“輸入形狀”參數(shù)(inputShape)。不要在“輸入型狀”中包含 batch size(批次大小)。假設(shè)您要向模型輸入一個形狀為[B, 784]的張量(B 是任意batch size),您只需要將“輸入型狀”設(shè)為[784]。

您可以通過model.layers來使用模型中的每一層。例如,您可以用 model.inputLayers 和 model.outputLayers 來調(diào)用輸入層和輸出層。

使用functional model

我們也可以通過 tf.model() 來創(chuàng)建 LayersModel。tf.model() 和 tf.sequential() 的主要區(qū)別為,您可以用 tf.model() 來創(chuàng)建任何非閉環(huán)的計算圖。

以下是一段如何用 tf.model() API 建立和上文相同模型的列子:

// 用apply()方法創(chuàng)建任意計算圖
const input = tf.input({shape: [784]});
const dense1 = tf.layers.dense({units: 32, activation: 'relu'}).apply(input);
const dense2 = tf.layers.dense({units: 10, activation: 'softmax'}).apply(dense1);
const model = tf.model({inputs: input, outputs: dense2});

我們在每一層用 apply() 將上一層的輸出作為本層的輸入。apply() 返回一個 SymbolicTensor(類似于張量,但不包含任何數(shù)值)

不同于 sequential model 使用 inputShape 來定義第一層的輸入,我們用 tf.input() 創(chuàng)建的 SymbolicTensor 作為第一層的輸入

如果您向 apply() 輸入一個數(shù)值張量,它會進行計算并返還一個數(shù)值張量:

const t = tf.tensor([-2, 1, 0, 5]);
const o = tf.layers.activation({activation: 'relu'}).apply(t);
o.print(); // [0, 1, 0, 5]

這個方式適用于單獨測試每一層并檢查它們的輸出。

和 sequential model 一樣,您可以通過 model.layers 來使用模型中的每一層。例如,您可以用 model.inputLayers 和 model.outputLayers 來調(diào)用輸入層和輸出層。

驗證

Sequential model和functional model都屬于 LayersModel類。使用 LayersModels 讓驗證更方便:它要求您定義輸入形狀,并用您定義的形狀來驗證您對模型的輸入。LayersModel 會自動計算模型中所有張量的形狀。知道張量的形狀后,模型就可以自動創(chuàng)建它所需要的參數(shù)。您也可以用形狀信息來判斷兩層相鄰的層是否相互兼容。

模型總覽

使用 model.summary() 可以顯示很多模型的重要信息,包括:

  • 每一層的名字和類型
  • 每一層的輸出形狀
  • 每一層的權(quán)重數(shù)量
  • 每一層的輸入
  • 一個模型擁有的可訓練參數(shù)總量,和不可訓練參數(shù)總量

用前面定義的模型來做例子,我們可以在命令行中得到以下信息:

Layer (type)Output shapeParam #
dense_Dense1 (Dense)[null,32]25120
dense_Dense2 (Dense)[null,10]330
Total params: 25450
Trainable params: 25450
Non-trainable params: 0

注意:每一層的輸出形狀中都含有 null 值。模型的輸入形狀包含了批次大小,而批次大小是可以靈活更變的,所以批次的值在張量形狀中以 null 顯示。

序列化

相對于底端API而言,使用 LayersModel的另一個好處是方便存儲、加載模型。LayersModel 包含如下信息:

  • 可用于重建模型的模型架構(gòu)信息
  • 模型的權(quán)重
  • 訓練配置(例如損失函數(shù),優(yōu)化器和評估方式)
  • 優(yōu)化器的狀態(tài)(可用于繼續(xù)訓練模型)

存儲和加載模型只需要一行代碼:

const saveResult = await model.save('localstorage://my-model-1');
const model = await tf.loadLayersModel('localstorage://my-model-1');

在這個例子中,模型被存儲在瀏覽器的本地存儲里。請訪問 model.save() 和 save and load 了解如何把模型保存在不同的媒介中(例如 file storage, IndexedDB, 觸發(fā)下載到瀏覽器等等)。

自定義層

層是創(chuàng)建模型的基礎(chǔ)。如果您的模型需要定制化計算模塊,您可以寫一個自定義層并插入模型中。下面的例子是一個計算平方和的自定義層:

class SquaredSumLayer extends tf.layers.Layer {
 constructor() {
   super({});
 }
 // In this case, the output is a scalar.
 computeOutputShape(inputShape) { return []; }

 // call() is where we do the computation.
 call(input, kwargs) { return input.square().sum();}

 // Every layer needs a unique name.
 getClassName() { return 'SquaredSum'; }
}

可以用 apply() 方法在一個張量上測試這個自定義層

const t = tf.tensor([-2, 1, 0, 5]);
const o = new SquaredSumLayer().apply(t);
o.print(); // prints 30
注意:如果您在模型中包含了自定義層,模型將不能序列化

用 Core API 創(chuàng)建模型

本文開頭提到了兩種在 TensorFlow.js 中建立模型的方法。最常用的方式是使用 Layers API,因為它的模式是基于廣泛應(yīng)用的 Keras API(詳情見 best practices and reduces cognitive load)。Layers API 提供了大量方便的工具,例如權(quán)重初始化,模型序列化,訓練監(jiān)測,可遷移性和安全檢查。

當您遇到如下情況時,可能會需要使用 Core API:

  • 您需要更多靈活性和控制
  • 您不需要序列化或可以創(chuàng)造自己的序列化方法

用 Core API 寫的模型包含了一系列的函數(shù)。這些函數(shù)以一個或多個張量作為輸入,并輸出另一個張量。我們可以用 Core API 來重寫之前定義的模型:

// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));

function model(x) {
  return x.matMul(w1).add(b1).relu().matMul(w2).add(b2).softmax();
}

在 Core API 中,我們需要自己創(chuàng)建和初始化權(quán)重。每個權(quán)重都是一個 Variable,TensorFlow.js 會把 Variable 權(quán)重設(shè)為可訓練張量。您可以用 tf.variable() 創(chuàng)建 Variable 或把一個已存在的張量放到 Variable 中。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號