Tensorflow.js 模型

2020-09-04 10:25 更新

机器学习中,一个 model 是一个带有可训练参数的函数。这个函数将输入转化为输出。通俗的来说,这个函数表达了输入和输出之间的变换关系。我们通过在数据集上训练模型来获得最佳参数。训练好的模型可以精确的将输入数据转换为我们想得到的输出。

TensorFlow.js 有两种创建机器学习的方法:

  1. 用 Layers API(用 layers 来创建模型)
  2. 用 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() 可以显示很多模型的重要信息,包括:

  • 每一层的名字和类型
  • 每一层的输出形状
  • 每一层的权重数量
  • 每一层的输入
  • 一个模型拥有的可训练参数总量,和不可训练参数总量

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

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 包含如下信息:

  • 可用于重建模型的模型架构信息
  • 模型的权重
  • 训练配置(例如损失函数,优化器和评估方式)
  • 优化器的状态(可用于继续训练模型)

存储和加载模型只需要一行代码:

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 中。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号