趋近智
Keras 的 Sequential 和 Functional API 提供了便捷的方法来构建各种常见的模型架构,但你可能会遇到需要更大灵活性的情形。例如,你可能正在实现一篇研究论文中描述的新颖层,或者你需要一个具有复杂内部状态的层,再或者你的模型的前向传播逻辑无法很好地适应 Functional API 的标准有向无环图结构。
对于这些情况,TensorFlow 允许你通过继承 Keras 提供的基本类来创建 自定义层 和 自定义模型。这种面向对象的方法使你能够完全控制组件的行为。
自定义层本质上是一个继承自 tf.keras.layers.Layer 的 Python 类。通过继承 Layer,你的自定义组件可以与 Keras 生态系统的其余部分顺畅地集成。你可以像使用任何内置层(例如 Dense、Conv2D)一样,在 Sequential 或 Functional 模型中使用它。
要创建自定义层,你通常需要实现三个方法:
__init__(self, **kwargs): 这是构造函数。使用它来定义不依赖于输入形状的层特定属性。这包括超参数,例如单元数量、激活函数或正则化强度。首先调用 super().__init__(**kwargs)。此处应接受配置所需的任何参数。build(self, input_shape): 这个方法是定义层权重(可训练变量)的地方。它会在层第一次使用时自动调用,因为权重形状通常取决于输入数据的形状,而输入数据的形状在层实例化时是未知的。在 build 方法内部使用 self.add_weight() 方法来创建权重。input_shape 参数(一个 tf.TensorShape 对象)提供了必要的信息。最佳做法是在此方法结束时设置 self.built = True。call(self, inputs, **kwargs): 这个方法定义了层的前向传播逻辑。它接收输入张量作为参数(以及可选的关键字参数,如 training=None,用于在训练和推理期间行为不同的层,例如 Dropout),并返回输出张量。所有涉及输入和权重的计算都在这里进行。下面是自定义层结构的草图:
import tensorflow as tf
class CustomLayer(tf.keras.layers.Layer):
def __init__(self, config_param1, config_param2=None, **kwargs):
super().__init__(**kwargs)
# 存储不依赖于输入形状的配置参数
self.config_param1 = config_param1
self.config_param2 = config_param2
# ... 其他初始化
def build(self, input_shape):
# 首次使用层时调用一次。
# 使用 input_shape 来确定权重维度。
# 示例:创建一个可训练的权重矩阵 'w'
self.w = self.add_weight(
name='kernel', # 一个有意义的名称
shape=(input_shape[-1], self.config_param1), # 形状取决于输入特征和一个配置参数
initializer='random_normal', # 如何初始化权重
trainable=True # 该权重应在训练期间更新
)
# 示例:创建一个不可训练的偏置 'b'(不太常见,仅用于说明)
self.b = self.add_weight(
name='bias',
shape=(self.config_param1,),
initializer='zeros',
trainable=False # 该权重不会被更新
)
# 将层标记为已构建
self.built = True
def call(self, inputs, training=None):
# 使用 self.w、self.b 和 inputs 定义前向传播逻辑
# 示例:一个简单的线性变换
output = tf.matmul(inputs, self.w) + self.b
# 如果在 __init__ 中指定了激活函数,则应用
# if self.activation: output = self.activation(output)
# 如果需要在训练与推理期间处理行为差异
# if training:
# # 应用 dropout 等
# else:
# # 使用推理行为
return output
# 可选:为序列化实现 get_config 方法
def get_config(self):
config = super().get_config()
config.update({
"config_param1": self.config_param1,
"config_param2": self.config_param2,
})
return config
正如你可以通过继承 tf.keras.layers.Layer 来创建自定义层一样,你也可以通过继承 tf.keras.Model 来创建自定义模型。当你需要比 Sequential 或 Functional API 所提供的对模型架构或训练循环有更多控制时,这会很有用。
过程与创建自定义层相似:
__init__(self, **kwargs): 将模型将要使用的层定义为类实例的属性。这些可以是标准的 Keras 层,也可以是你自己的自定义层。call(self, inputs, **kwargs): 定义整个模型的前向传播。你将在此处调用在 __init__ 中定义的层,指定数据如何流经它们。继承 tf.keras.Model 提供了最大的灵活性。你本质上是将模型的前向传播定义为一个 Python 函数。虽然你仍然可以将标准的 model.compile() 和 model.fit() 方法用于自定义模型,但继承 Model 也为编写完全自定义的训练循环提供了可能(尽管这是一个更高级的话题)。
下面是草图:
class CustomModel(tf.keras.Model):
def __init__(self, num_units_l1, num_units_l2, num_classes, **kwargs):
super().__init__(**kwargs)
# 定义模型将使用的层
self.layer1 = tf.keras.layers.Dense(num_units_l1, activation='relu')
self.layer2 = CustomLayer(num_units_l2) # 使用我们的自定义层
self.classifier = tf.keras.layers.Dense(num_classes, activation='softmax')
def call(self, inputs, training=None):
# 使用这些层定义前向传播
x = self.layer1(inputs)
x = self.layer2(x, training=training) # 如果层需要训练标志,则传递
outputs = self.classifier(x)
return outputs
# 实例化自定义模型
# model = CustomModel(num_units_l1=128, num_units_l2=64, num_classes=10)
# 然后你可以像往常一样编译和训练这个模型
虽然在可能的情况下,通常应优先选择 Sequential 和 Functional API 的直接性,但在以下情况可以考虑创建自定义层或模型:
本简介展示了 Keras 继承所提供的灵活性。虽然在本入门课程中我们不会实现复杂的自定义组件,但理解存在这种能力在你遇到更高级的机器学习架构时是有价值的。对于大多数常见任务,Sequential 和 Functional API 将足够使用且通常更易于操作。
这部分内容有帮助吗?
tf.keras.layers.Layer实现自定义Keras层,以及通过继承tf.keras.Model实现自定义模型,涵盖了__init__、build、call和get_config等核心方法。© 2026 ApX Machine Learning用心打造