(四)TensorFlow.js的模型和层
机器学习中,一个 model 是一个带有可训练参数的函数。这个函数将输入转化为输出。通俗的来说,这个函数表达了输入和输出之间的变换关系。我们通过在数据集上训练模型来获得最佳参数。训练好的模型可以精确的将输入数据转换为我们想得到的输出。
TensorFlow.js有两种创建机器学习的方法:
- 用 Layers API(用 layers 来创建模型)
- 用 Core API(底端算子,例如
tf.matMul()
或tf.add()
等)来建立模型
我们首先会用高层API:Layers API来建立模型。然后,我们会展示如何用Core API来搭建相同的模型。
用Layers API创建模型
Layers API有两种方式创建模型:第一种是创建 sequential 模型,第二种是创建 functional 模型。下面两段会分别解释这两种模型创建方式。
使用sequential model
最常见的模型是Sequential
模型。Sequential模型将网络的每一层简单的叠在一起。您可以将需要的层按顺序写在一个列表里,然后将列表作为sequential()
函数的输入:
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'}));
注意:模型的第一层需要“输入形状”参数(inputShape)。不要在“输入型状”中包含batch size(批次大小)。假设您要向模型输入一个形状为[B, 784]的张量(B是任意batch size),您只需要将“输入型状”设为[784]。
您可以通过model.layers来使用模型中的每一层。例如,您可以用model.inputLayers和model.outputLayers来调用输入层和输出层。
使用functional model
我们也可以通过tf.model()
来创建LayersModel。tf.model()
和tf.sequential()的主要区别为,您可以用tf.model()来创建任何非闭环的计算图。
以下是一段如何用tf.model()
API 建立和上文相同模型的列子:
// 用apply()方法创建任意计算图
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(类似于张量,但不包含任何数值)
不同于sequential model使用inputShape来定义第一层的输入,我们用tf.input()创建的SymbolicTensor作为第一层的输入
如果您向apply()输入一个数值张量,它会进行计算并返还一个数值张量:
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来调用输入层和输出层。
验证
Sequential model和functional model都属于LayersModel类。使用LayersModels让验证更方便:它要求您定义输入形状,并用您定义的形状来验证您对模型的输入。LayersModel会自动计算模型中所有张量的形状。知道张量的形状后,模型就可以自动创建它所需要的参数。您也可以用形状信息来判断两层相邻的层是否相互兼容。
模型总览
使用model.summary()可以显示很多模型的重要信息,包括:
- 每一层的名字和类型
- 每一层的输出形状
- 每一层的权重数量
- 每一层的输入
- 一个模型拥有的可训练参数总量,和不可训练参数总量
用前面定义的模型来做例子,我们可以在命令行中得到以下信息:

注意:每一层的输出形状中都含有null值。模型的输入形状包含了批次大小,而批次大小是可以灵活更变的,所以批次的值在张量形状中以null显示。
序列化
相对于底端API而言,使用LayersModel的另一个好处是方便存储、加载模型。LayersModel包含如下信息:
- 可用于重建模型的模型架构信息
- 模型的权重
- 训练配置(例如损失函数,优化器和评估方式)
- 优化器的状态(可用于继续训练模型)
存储和加载模型只需要一行代码:
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
, 触发下载到浏览器等等)。
自定义层
层是创建模型的基础。如果您的模型需要定制化计算模块,您可以写一个自定义层并插入模型中。下面的例子是一个计算平方和的自定义层:
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创建模型
本文开头提到了两种在TensorFlow.js中建立模型的方法。最常用的方式是使用 Layers API,因为它的模式是基于广泛应用的Keras API(详情见 best practices and reduces cognitive load)。Layers API提供了大量方便的工具,例如权重初始化,模型序列化,训练监测,可迁移性和安全检查。
当您遇到如下情况时,可能会需要使用Core API:
- 您需要更多灵活性和控制
- 您不需要序列化或可以创造自己的序列化方法
用Core API写的模型包含了一系列的函数。这些函数以一个或多个张量作为输入,并输出另一个张量。我们可以用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中,我们需要自己创建和初始化权重。每个权重都是一个Variable
,TensorFlow.js会把Variable
权重设为可训练张量。您可以用tf.variable()创建Variable
或把一个已存在的张量放到Variable
中。
本文介绍了如何用Layers和Core API创建模型。接下来,请看training models学习如何训练模型。