Keras 函数式 API

参考: tensorflow 文档

深度学习库 Tensorflow 2 里的 Keras 模块提供了函数式风格的 应用程序接口 (API)。这让我们可以用相当不同的风格,构建出同样的神经网络模型。

面向对象 API

Keras 里我们可以用下面的代码创建模型。

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Input(5, ),
    tf.keras.layers.Dense(2, activation="relu", name="layer1"),
    tf.keras.layers.Dense(3, activation="relu", name="layer2"),
    tf.keras.layers.Dense(4, name="layer3"),
])

通过创建 tf.keras.layers 里的对象(Dense),我们得到了不同的三个「层」。之后 Sequential 函数把这些「层」依序连接起来,得到了模型。

函数式 API

Keras 同时也允许我们把 同样的代码 用函数式风格写出:

import tensorflow as tf

inputs = tf.keras.Input(shape=(5,))
x = tf.keras.layers.Dense(2, activation="relu", name="layer1")(inputs)
x = tf.keras.layers.Dense(3, activation="relu", name="layer2")(x)
outputs = tf.keras.layers.Dense(4, activation="relu", name="layer3")(x)

model = tf.keras.Model(inputs=inputs, outputs=outputs)

这会得到同样的模型。

深入理解

在面向对象 API 里,我们的使用的语法如下

model = tf.keras.Sequential(
  [输入, 第一层, 第二层, 第三层,...]
)

其中,我们使用函数得到了不同「层」,我把我得到的东西想象成对象。下面是我们得到「第一层」的语句。

第一层 = tf.keras.layers.Dense(2, activation="relu", name="layer1")

这样的想象是对的,不过 tf.keras.layers 里的函数返回给我们的实际上是,另一个函数。下面的代码解释了这个行为。

import tensorflow as tf

l1 = tf.keras.layers.Dense(2)
l2 = tf.keras.layers.Dense(3)
l3 = tf.keras.layers.Dense(4)

x = tf.ones((1, 5))
y = l3(l2(l1(x)))  # shape 1, 4

我们可以用 数学公式 表示最后一行代码

\[\begin{aligned} x_1 &= l_1(x)\\ x_2 &= l_2(x_1)\\ y &= l_3(x_2) \end{aligned}\]

没有输入的模型

在我创建模型的时候,我通常会指定输入数据的形状。譬如,下面的代码 将 输入数据 固定为 5 个数字。

tf.keras.layers.Input(5, )

但是,我也可以创造一个没有输入的模型。一个最简单的例子如下,

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(2)
])

此时,我们不能直接使用 model.summary() 来得到模型的描述。因为我们不知道 输入数据的结构,因而无法确定 模型中 参数的数目。同时我会得到这样的错误警告:

ValueError: This model has not yet been built. Build the model
first by calling `build()` or calling `fit()` with some data, or
specify an `input_shape` argument in the first layer(s) for automatic build.

当我“使用”过一次模型之后,模型的输入就会被确定。譬如,下面的代码片段可以顺利执行。

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(2)
])

x = tf.ones((1, 5))
model(x)
model.summary()

我们「不能」将模型套用在「形状不同的输入」上。譬如,下面的代码会产生错误。

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(2)
])

x = tf.ones((1, 5))
model(x)  #  顺利执行,模型的输入被固定为 5

x = tf.ones((1, 8))
model(x)  #  程序报错