1 概述
1.1创建模型的方法
在Keras框架中,创建模型主要有三种方式:
-
Sequential模型:这是一种非常直接的方法,它由一个简单的层列表组成。这种模型非常适合初学者,因为它的构建过程非常直观。然而,Sequential模型有一个限制,那就是它只能用于单输入和单输出的层堆叠。
-
Functional API:这是一种易于使用且功能齐全的API,它支持任意模型架构。对于大多数人和大多数用例来说,这是你应该选择的方式。Functional API是Keras的"工业级"模型,它允许你构建更复杂的模型,比如多输入多输出的模型。
-
模型子类化(Model subclassing):这种方式允许你从头开始实现一切,如果你有复杂的、非标准的研究用例,可以选择这种方式。模型子类化提供了最大的灵活性,但同时也需要更多的工作量和对Keras框架的深入理解。
每种方法都有其适用场景,选择合适的方法取决于你的具体需求和偏好。如果你正在开始学习Keras,可能会从Sequential模型开始,随着对框架的熟悉,你可能会转向Functional API来构建更复杂的模型。而当你需要进行高级研究或开发时,模型子类化可能是一个更好的选择。
1.2模型API概述
1.2.1Model 类
Model
类是Keras中用于构建和训练深度学习模型的基础类。它允许你定义模型的层、连接这些层、以及配置模型的训练过程。
- summary 方法
summary
方法用于打印模型的概述,包括每层的名称、输出形状、参数数量等。这对于理解和调试模型非常有用。
- get_layer 方法
get_layer
方法用于通过名称获取模型中的某一层。这在需要直接访问特定层或对其进行操作时非常有用。
1.2.2Sequential 类
Sequential
类是Model
的一个子类,用于构建线性堆叠的层(即每一层的输出都是下一层的输入)。它提供了一种简1.2.2单快捷的方式来定义模型。
add 方法
在Sequential
模型中,add
方法用于将新层添加到模型中。每次调用add
都会将新层添加到模型的最顶层。
pop 方法
pop
方法用于从Sequential
模型中移除顶层。这在需要修改模型结构时可能很有用。
1.2.3模型训练API
Keras提供了一系列用于模型训练的API。
compile
方法:配置模型的学习过程,包括优化器、损失函数和评估指标。fit
方法:用于训练模型。它接受训练数据、验证数据和其他训练参数,并迭代更新模型的权重以最小化损失。evaluate
方法:用于评估模型在测试集上的性能。它返回损失值和评估指标的值。predict
方法:使用模型对新的、未见过的数据进行预测。train_on_batch
方法:在单个批次上训练模型。这在需要更细粒度的控制训练过程时可能很有用。test_on_batch
方法:在单个批次上评估模型。predict_on_batch
方法:在单个批次上使用模型进行预测。
1.2.4保存与序列化
Keras提供了多种保存和加载模型的方法。
- 整个模型保存与加载:你可以将整个模型(包括其结构、权重和训练配置)保存为一个文件,并在需要时重新加载。
- 仅保存权重:如果你只需要保存和加载模型的权重,而不需要保存其结构或训练配置,你可以使用这种方法。
- 模型配置序列化:你可以将模型的配置(包括其结构和训练配置,但不包括权重)序列化为JSON或YAML格式的文件。这可以用于在不同的环境或机器之间共享模型的结构。
- 模型导出用于推理:Keras还支持将模型导出为TensorFlow SavedModel格式或TensorFlow Lite格式,以便在TensorFlow Serving或移动设备上进行推理。
序列化工具
Keras还提供了一些用于序列化和反序列化模型的辅助工具函数和类。这些工具可以帮助你在不同的环境或机器之间轻松地共享和重用模型。
2 模型类
典型的模型类如下
keras.Model()
2.1使用Functional API
使用“Functional API”时,程序员从输入开始,通过链式调用层来指定模型的前向传播,最后从输入和输出中创建模型。
这里是“Functional API”的一个简单概述,它允许你以一种更灵活和模块化的方式构建神经网络模型。相比于Sequential API(它只适用于层的线性堆叠),Functional API 允许程序员定义更复杂的模型,包括多输入、多输出以及共享层的模型。
在使用Functional API时,程序员可以:
- 使用
Input
类来定义输入张量的形状和类型。 - 调用层(如
Dense
,Conv2D
,MaxPooling2D
等)并将它们应用于输入张量。 - 通过链接多个层来定义前向传播路径。
- 使用
Model
类并传入输入和输出张量来实例化模型。
这样,程序员就可以通过编写一个类似于函数定义的前向传播过程来构建模型,并且可以很容易地重用和组合层来创建复杂的网络结构。
模型的输入和输出
inputs = keras.Input(shape=(37,))
x = keras.layers.Dense(32, activation="relu")(inputs)
outputs = keras.layers.Dense(5, activation="softmax")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
注意:仅支持字典、列表和元组的输入张量。不支持嵌套输入(例如列表的列表或字典的字典)。
使用中间张量也可以创建新的Functional API模型。这允许程序员快速提取模型的子组件。
在使用Keras的Functional API构建神经网络模型时,程序员需要定义输入和输出张量,并且这些输入必须是以字典、列表或元组的形式提供。然而,Keras不支持更复杂的嵌套结构作为输入,例如列表的列表或字典的字典。
此外,Functional API的一个特点是程序员可以通过中间张量(在模型构建过程中创建的张量)来创建新的模型或模型的一部分。这是通过将输入张量传递给一个或多个层,然后将这些层的输出作为新模型的输入或输出来实现的。这种方法允许程序员轻松地构建复杂的模型结构,并可以方便地提取和使用模型的子组件。
inputs = keras.Input(shape=(None, None, 3))
processed = keras.layers.RandomCrop(width=128, height=128)(inputs)
conv = keras.layers.Conv2D(filters=32, kernel_size=3)(processed)
pooling = keras.layers.GlobalAveragePooling2D()(conv)
feature = keras.layers.Dense(10)(pooling)
full_model = keras.Model(inputs, feature)
backbone = keras.Model(processed, conv)
activations = keras.Model(conv, feature)
请注意,骨干网络(backbone)和激活模型(activations)不是通过直接使用keras.Input
对象创建的,而是使用源自keras.Input
对象的张量来创建的。在内部,这些模型之间的层和权重是共享的,因此用户可以训练完整的模型(full_model),并使用骨干网络或激活模型来进行特征提取。模型的输入和输出也可以是张量的嵌套结构,并且创建的模型是标准的Functional API模型,支持所有现有的API。
在深度学习模型构建中,尤其是在迁移学习或特征提取的上下文中,我们经常使用预训练的模型作为骨干网络(backbone),并在其上添加自定义层来构建完整的模型。使用Keras的Functional API时,这些骨干网络和激活模型(即网络中的中间层)并不是通过直接定义输入层来创建的,而是使用从原始输入层(keras.Input
对象)流经网络并产生的中间张量来创建的。由于这些张量是在同一个计算图中定义的,因此它们引用的层和权重在骨干网络和激活模型中也是共享的。
这种设计使得用户能够:
- 训练完整的模型,该模型包括骨干网络和任何附加的层。
- 使用骨干网络或其中的特定层来进行特征提取,而不必重新训练整个模型。
同时,模型的输入和输出也可以是张量的复杂嵌套结构,这增加了模型设计的灵活性。无论输入输出的结构如何,使用Functional API创建的模型都是标准的,可以支持Keras提供的所有现有API和工具。
2.2继承Model类
通过继承Model
类,在这种情况下,程序员应该在__init__()
方法中定义自己层,并且程序员应该在call()
方法中实现模型的前向传播。
在Keras中,除了使用Functional API来构建模型外,程序员还可以通过继承Model
基类来定义自定义的模型。当程序员选择这种方式时,需要创建一个新的类,该类继承自tensorflow.keras.models.Model
(在TensorFlow 2.x中)或keras.models.Model
(在纯Keras或TensorFlow 1.x中)。
在自定义的模型类中,程序员需要在__init__()
方法中定义模型的层。这通常涉及创建Layer
类的实例,并将它们作为属性存储在模型类中。
然后,程序员需要实现call()
方法,该方法定义了模型的前向传播过程。当模型接收到输入数据并被调用时(例如,使用model(inputs)
或model.predict(data)
),call()
方法将被执行。在这个方法中,程序员应该编写将数据传递给各个层以及可能进行任何必要处理的代码,以计算模型的输出。
这种方法允许程序员更灵活地控制模型的结构和行为,因为它允许定义自己的初始化逻辑和自定义的前向传播过程。然而,这也需要更多的编程工作,因为它需要程序员从头开始构建模型的逻辑。
class MyModel(keras.Model):
def __init__(self):
super().__init__()
self.dense1 = keras.layers.Dense(32, activation="relu")
self.dense2 = keras.layers.Dense(5, activation="softmax")
def call(self