You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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模型精度更高、速度稍慢的其他原因?


解答

核心结构差异(精度/速度差的根本原因)

这两个模型完全不等价,结构上的多处差异直接导致了结果差距:

  1. 卷积与池化的特征压缩逻辑完全不同

    • 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模型。
  2. Flatten层输入尺寸差异巨大
    以输入224x224x3为例:

    • Sequential模型经过4组Conv+Pool后,特征图尺寸最终为12x12x128,Flatten后得到18432个特征,能保留大量图像细节。
    • Functional API模型经过4个Mini_Block后,特征图尺寸最终为1x1x128,Flatten后仅128个特征,几乎丢失了所有空间细节,特征提取能力被严重削弱,这是精度偏低的核心原因。
  3. 计算量与参数差异
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:20:46