在机器学习中,模型是一个具有可学习 参数 的函数,它将输入映射到输出。通过在数据上训练模型来获得最佳参数。经过良好训练的模型将提供从输入到所需输出的准确映射。
在 TensorFlow.js 中,有两种方法可以创建机器学习模型
- 使用层 API,您使用层构建模型。
- 使用核心 API,使用更低级别的运算,例如
tf.matMul()
、tf.add()
等。
首先,我们将介绍层 API,它是一个用于构建模型的更高级别的 API。然后,我们将展示如何使用核心 API 构建相同的模型。
使用层 API 创建模型
有两种方法可以使用层 API 创建模型:顺序模型和函数式模型。接下来的两节将更详细地介绍每种类型。
顺序模型
最常见的模型类型是 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
。在提供inputShape
时,请确保排除批次大小。例如,如果您计划向模型馈送形状为[B, 784]
的张量,其中B
可以是任何批次大小,请在创建模型时将inputShape
指定为[784]
。
您可以通过 model.layers
访问模型的层,更具体地说,是 model.inputLayers
和 model.outputLayers
。
函数式模型
创建 LayersModel
的另一种方法是通过 tf.model()
函数。tf.model()
和 tf.sequential()
之间的关键区别在于,tf.model()
允许您创建层的任意图,只要它们没有循环。
以下代码片段使用 tf.model()
API 定义了与上面相同的模型
// Create an arbitrary graph of layers, by connecting them
// via the apply() method.
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
,它类似于 Tensor
,但没有具体的值。
请注意,与顺序模型不同,我们通过 tf.input()
创建一个 SymbolicTensor
,而不是向第一层提供 inputShape
。
apply()
也可以为您提供一个具体的 Tensor
,如果您向其传递一个具体的 Tensor
const t = tf.tensor([-2, 1, 0, 5]);
const o = tf.layers.activation({activation: 'relu'}).apply(t);
o.print(); // [0, 1, 0, 5]
这在单独测试层并查看其输出时很有用。
就像在顺序模型中一样,您可以通过 model.layers
访问模型的层,更具体地说,是 model.inputLayers
和 model.outputLayers
。
验证
顺序模型和函数式模型都是 LayersModel
类的实例。使用 LayersModel
的主要优势之一是验证:它强制您指定输入形状,并将在以后使用它来验证您的输入。LayersModel
还会在数据流经层时进行自动形状推断。提前知道形状允许模型自动创建其参数,并且可以告诉您两个连续层是否彼此不兼容。
模型摘要
调用 model.summary()
以打印模型的有用摘要,其中包括
- 模型中所有层的名称和类型。
- 每层的输出形状。
- 每层的权重参数数量。
- 如果模型具有通用拓扑结构(将在下面讨论),则每层接收的输入
- 模型的可训练参数和不可训练参数的总数。
对于我们上面定义的模型,我们在控制台上得到以下输出
层 (类型) | 输出形状 | 参数数量 |
dense_Dense1 (Dense) | [null,32] | 25120 |
dense_Dense2 (Dense) | [null,10] | 330 |
总参数: 25450 可训练参数: 25450 不可训练参数: 0 |
注意层输出形状中的 null
值:提醒模型期望输入在最外层维度具有批次大小,在本例中,由于 null
值,批次大小可以灵活调整。
序列化
使用 LayersModel
相对于低级 API 的主要优势之一是能够保存和加载模型。 LayersModel
了解
- 模型的架构,允许您重新创建模型。
- 模型的权重
- 训练配置(损失、优化器、指标)。
- 优化器的状态,允许您恢复训练。
保存或加载模型只需一行代码
const saveResult = await model.save('localstorage://my-model-1');
const model = await tf.loadLayersModel('localstorage://my-model-1');
上面的示例将模型保存到浏览器中的本地存储。请参阅 model.save() 文档
和 保存和加载 指南,了解如何保存到不同的介质(例如文件存储、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
重要:如果您添加自定义层,您将失去序列化模型的能力。
使用核心 API 创建模型
在本指南的开头,我们提到过在 TensorFlow.js 中创建机器学习模型有两种方法。
一般经验法则是始终尝试首先使用层 API,因为它模仿了广为采用的 Keras API,该 API 遵循 最佳实践并减少认知负担。层 API 还提供各种现成的解决方案,例如权重初始化、模型序列化、监控训练、可移植性和安全检查。
您可能希望在以下情况下使用核心 API
- 您需要最大程度的灵活性和控制。
- 您不需要序列化,或者可以实现自己的序列化逻辑。
核心 API 中的模型只是接受一个或多个 Tensors
并返回一个 Tensor
的函数。使用核心 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();
}
请注意,在核心 API 中,我们负责创建和初始化模型的权重。每个权重都由一个 Variable
支持,它向 TensorFlow.js 信号这些张量是可学习的。您可以使用 tf.variable() 并传入现有的 Tensor
来创建一个 Variable
。
在本指南中,您已经熟悉了使用层 API 和核心 API 创建模型的不同方法。接下来,请参阅 训练模型 指南,了解如何训练模型。