2. 函数式模型
两种方式 | 优点 | 缺点 |
---|---|---|
顺序模型 | 单输入单输出,搭建比较简单,是多个网络层的线性堆叠,不发生分叉,编译速度快 | 不能定义复杂模型 |
函数式模型 | 灵活,层与层之间可以任意连接可以定义复杂模型(如多输出模型、有向无环图,或具有共享层的模型) | 搭建复杂,编译速度慢 |
顺序模型也可看做是函数式模型的一种特殊情况。
以下以mnist为例分别进行说明:
顺序模型也即一层叠一层,所以模型不发生分叉,单输入单输出,这意味着顺序模型不支持共享图层或多输入多输出模型。
第0讲顺序模型搭建mnist的代码如下:
方式1:采用model.add 一层层添加
import tensorflow as tf
import tensorflow.keras as keras
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)
# step1: use sequential
model = keras.models.Sequential()
# step2: add layer
model.add(keras.layers.Flatten(input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(keras.layers.Dense(units=784, activation="relu", input_dim=784))
model.add(keras.layers.Dense(units=10, activation="softmax"))
# step3: compile model
model.compile(optimizer="Adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])
print("model:")
model.summary()
# step4: train
model.fit(x_train, y_train, batch_size=64, epochs=5)
# step5: evaluate model
model.Evaluate (x_valid, y_valid)
# save model
model.save('keras_mnist.h5')
方式2:初始化Sequential时同时定义层
import tensorflow as tf
import tensorflow.keras as keras
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)
# step1, step2: Init sequential
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=(x_train.shape[1], x_train.shape[2])),
keras.layers.Dense(units=784, activation="relu", input_dim=784),
keras.layers.Dense(units=10, activation="softmax")
])
# step3: compile model
model.compile(optimizer="Adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])
print("model:")
model.summary()
# step4: train
model.fit(x_train, y_train, batch_size=64, epochs=5)
# step5: evaluate model
model.evaluate(x_valid, y_valid)
# save model
model.save('keras_mnist.h5')
顺序模型允许逐层创建模型以解决许多问题,但是有时我们需要创建更加复杂的模型,比如具有共享图层或多输入多输出的模型,这时我们可以使用keras提供的函数式API模型,它定义了每一层的输入输出,像函数调用一样,用上一层的输出作为这一层的入参,这一层的输出作为函数返回值,这就是函数式API的由来,(这一点不同与顺序模型,顺序模型每层的输入输出是一定的,不需要专门指定)。
同样的,利用函数式API模型搭建与之前等价的mnist模型,代码如下:
import tensorflow as tf
import tensorflow.keras as keras
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)
# step1: Model structure
# 层的实例是可调用的,它以张量为参数,并且返回一个张量
input = keras.Input(shape=(x_train.shape[1], x_train.shape[2]))
x = keras.layers.Flatten()(input)
x = keras.layers.Dense(units=784, activation="relu", input_dim=784)(x)
output = keras.layers.Dense(units=10, activation="softmax")(x)
# step2: define Model
model = keras.Model(inputs=input, outputs=output)
# step3: compile model
model.compile(optimizer="Adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])
print("model:")
model.summary()
# step4: train
model.fit(x_train, y_train, batch_size=64, epochs=5)
# step5: evaluate model
model.evaluate(x_valid, y_valid)
# save model
model.save('keras_mnist.h5')
由这个例子可见:函数式API可以搭建顺序模型Sequential,所以顺序模型也可看做是函数式模型的一种特殊情况。
还有另外一种Model子类的搭建方法,这是利用python call方法的一种写法,我觉得只是写法上的区别,本质也是函数式API,代码如下:
import tensorflow as tf
import tensorflow.keras as keras
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)
# step1: Model structure
class MnistModel(tf.keras.Model):
def __init__(self):
super(MnistModel, self).__init__()
self.x0 = keras.layers.Flatten()
self.x1 = keras.layers.Dense(units=784, activation="relu", input_dim=784)
self.x2 = keras.layers.Dense(units=10, activation="softmax")
def call(self, input):
x = self.x0(input)
x = self.x1(x)
x = self.x2(x)
return x
# step2: define Model
model = MnistModel()
# step3: compile model
model.compile(optimizer="Adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# step4: train
model.fit(x_train, y_train, batch_size=64, epochs=5)
# 要放到model.fit之后
print("model:")
model.summary()
# step5: evaluate model
model.evaluate(x_valid, y_valid)
# save model (不能使用)
# model.save('keras_mnist.h5')
采用model子类方法有几个问题需要注意:
1. 采用model子类方法时,model.summary方法需要放到model.fit之后才能调用,否则报如下错误:
ValueError: This model has not yet been built. Build the model first by calling `build()` or by calling the model on a batch of data.
2. 采用model子类方法时,调用model.save会失败:
NotImplementedError: Saving the model to HDF5 format requires the model to be a Functional model or a Sequential model. It does not work for subclassed models, because such models are defined via the body of a Python method, which isn't safely serializable. Consider saving to the Tensorflow SavedModel format (by setting save_format="tf") or using `save_weights`.
参考: