TensorFlow中Sequential与函数式API实现网络的区别及Inception块实现问题
两种TensorFlow模型实现的核心区别
- 第一种使用的是Keras顺序API(Sequential API):仅支持线性堆叠的单输入单输出网络,层与层的连接严格按照添加顺序,每一层只能接收上一层的输出作为输入,写法简单但灵活性极低,无法实现分支、多输入输出等复杂结构。
- 第二种使用的是Keras函数式API(Functional API):是基于计算图的通用构建方式,支持自定义任意层连接关系,可实现多分支、跳跃连接、多输入输出、层共享等所有复杂网络结构,灵活性远高于顺序API。
你使用的Inception结构包含多分支并行计算逻辑,天然无法用纯线性堆叠的顺序API直接实现,需要通过封装自定义层的方式适配顺序API的调用规则。
适配Sequential API的Inception实现方案
你可以将Inception块封装为自定义Keras层,层内部实现分支逻辑,上层就可以直接用add()方法将其加入Sequential模型,示例实现如下:
import tensorflow as tf from tensorflow.keras import layers class InceptionBlock(tf.keras.layers.Layer): def __init__(self, filter_map, **kwargs): super().__init__(**kwargs) self.filter_map = filter_map # 分支1的线性堆叠用Sequential封装 self.path1 = tf.keras.Sequential([ layers.Conv2D(filter_map[0], (1, 1), padding='same', activation='relu') ]) # 分支2的线性堆叠用Sequential封装 self.path2 = tf.keras.Sequential([ layers.Conv2D(filter_map[1], (1, 1), padding='same', activation='relu'), layers.Conv2D(filter_map[2], (1, 1), padding='same', activation='relu') ]) def call(self, inputs): path1_out = self.path1(inputs) path2_out = self.path2(inputs) return tf.concat([path1_out, path2_out], axis=3) # 实现get_config支持模型序列化保存 def get_config(self): config = super().get_config() config.update({"filter_map": self.filter_map}) return config
之后你就可以完全通过Sequential+add()的方式构建整个模型:
model = tf.keras.Sequential() # 输入层+预处理层 model.add(layers.Input(shape=(32, 32, 3))) model.add(layers.experimental.preprocessing.Resizing(224, 224, interpolation="bilinear")) # 前置基础卷积层 model.add(layers.Conv2D(64, 7, strides=2, padding='same', activation='relu')) model.add(layers.MaxPooling2D(3, strides=2)) model.add(layers.Conv2D(64, 1, strides=1, padding='same', activation='relu')) model.add(layers.Conv2D(192, 3, strides=1, padding='same', activation='relu')) model.add(layers.MaxPooling2D(3, strides=2)) # 直接添加自定义Inception块,用法和原生层完全一致 model.add(InceptionBlock([64, 64, 192])) model.add(layers.MaxPooling2D(3, strides=2))
内容的提问来源于stack exchange,提问作者Vigneshwaran
相关产品推荐
相关产品推荐

