tf.keras Sequential与Functional API模型性能差异原因探究
类VGG架构:Sequential与Functional API模型的精度/速度差异问题
我对比了两个自认为等价的类VGG架构模型,分别用tf.keras.Models.Sequential和TensorFlow Functional API构建,用于cats_vs_dogs数据集分类任务。使用TensorFlow 2.10.0、TensorFlow_Datasets 4.7.0+nightly,数据集为Kaggle下载的猫狗数据集,预处理方式一致。
训练结果
Sequential模型训练结果
Epoch 10/10 703/703 [==============] - 16s 23ms/step - accuracy: 0.9271 - val_accuracy: 0.8488
Functional API模型训练结果
Epoch 10/10 703/703 [==============] - 15s 22ms/step - accuracy: 0.8483 - val_accuracy: 0.8072
模型代码
Sequential模型代码
def seq_model(): model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activation = 'relu', input_shape = (224, 224, 3)), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(64, (3, 3), activation = 'relu'), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Conv2D(128, (3, 3), activation = 'relu'), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(128, (3, 3), activation = 'relu'), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Flatten(), tf.keras.layers.Dense(512, activation = 'relu'), tf.keras.layers.Dense(1, activation = 'sigmoid'), ]) model.compile(optimizer = RMSprop(learning_rate = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy']) return model model = seq_model() history = model.fit(dataset, validation_data=d2, epochs=10)
Functional API模型代码
class Mini_Block(tf.keras.Model): def __init__(self, filters, kernel_size, pool_size=2, strides=2): super().__init__() self.filters = filters self.kernel_size = kernel_size self.conv2D_0 = tf.keras.layers.Conv2D(filters=filters, kernel_size=kernel_size, activation='relu', strides=strides, padding='same') self.max_pool = tf.keras.layers.MaxPooling2D(pool_size=pool_size, strides=strides, padding='same') def call(self, inputs): x = self.conv2D_0(inputs) max_pool = self.max_pool(x) return max_pool class MiniVGG(tf.keras.Model): def __init__(self, num_classes): super().__init__() self.block_a = Mini_Block(filters=32, kernel_size=3) self.block_b = Mini_Block(filters=64, kernel_size=3) self.block_c = Mini_Block(filters=128, kernel_size=3) self.block_d = Mini_Block(filters=128, kernel_size=3) self.flatten = tf.keras.layers.Flatten() self.fc = tf.keras.layers.Dense(512, activation='relu') self.classifier = tf.keras.layers.Dense(1, activation='sigmoid') def call(self, inputs): x = self.block_a(inputs) x = self.block_b(x) x = self.block_c(x) x = self.block_d(x) x = self.flatten(x) x = self.fc(x) x = self.classifier(x) return x vgg = MiniVGG(num_classes=1) vgg.compile(optimizer=RMSprop(learning_rate = 1e-4), loss='binary_crossentropy', metrics=['accuracy']) hist = vgg.fit(dataset, validation_data=d2, epochs=10)
问题
经排查发现,Sequential模型使用valid填充和步长1,而Functional API模型使用same填充和步长2,但这并非全部原因,还发现flatten层存在异常。现询问:这两个模型是否存在结构差异,或是Sequential模型精度更高、速度稍慢的其他原因?
解答
核心结构差异(精度/速度差的根本原因)
这两个模型完全不等价,结构上的多处差异直接导致了结果差距:
卷积与池化的特征压缩逻辑完全不同
- Sequential模型:每一组
Conv2D(strides=1, padding='valid')仅提取特征,不改变特征图尺寸;之后用MaxPooling2D(strides=2)将尺寸减半,每一组操作后特征图变为原来的1/2。 - Functional API的Mini_Block:
Conv2D(strides=2, padding='same')直接把特征图尺寸减半,随后又接MaxPooling2D(strides=2)再次减半——每一个Mini_Block会把特征图压缩到原来的1/4,特征丢失速度远快于Sequential模型。
- Sequential模型:每一组
Flatten层输入尺寸差异巨大
以输入224x224x3为例:- Sequential模型经过4组Conv+Pool后,特征图尺寸最终为12x12x128,Flatten后得到18432个特征,能保留大量图像细节。
- Functional API模型经过4个Mini_Block后,特征图尺寸最终为1x1x128,Flatten后仅128个特征,几乎丢失了所有空间细节,特征提取能力被严重削弱,这是精度偏低的核心原因。
计算量与参数差异
Functional API模型的特征图尺寸更小,后续Dense层的计算量也更小,整体参数和浮点运算量远低于Sequential模型,因此训练速度更快。
其他潜在次要因素
- 自定义
tf.keras.Model类的权重初始化时机与Sequential模型略有不同:Sequential在定义时就确定输入形状并初始化权重,而自定义Model需第一次调用后才构建权重。不过这对最终精度的影响远小于结构差异。 - 你提到的"flatten层异常",本质就是上述结构差异导致的特征图尺寸悬殊。
修正建议
要让两个模型等价,需修改Mini_Block中的Conv2D参数,与Sequential保持一致:
self.conv2D_0 = tf.keras.layers.Conv2D(filters=filters, kernel_size=kernel_size, activation='relu', strides=1, # 改为1 padding='valid') # 改为valid
同时MaxPooling2D的参数也可同步Sequential的默认值(padding='valid',不过对结果影响较小)。
内容的提问来源于stack exchange,提问作者user1245262
相关产品推荐
相关产品推荐

