我正在使用预训练的模型对图像进行分类。我的问题是在我的模型中使用预训练的模型结构后,我必须添加什么样的层,以及为什么这两种实现方式不同。具体来说:
考虑两个示例,一个使用cats and dogs数据集:
here是一个实现,关键点在于基础模型:
# Create the base model from the pre-trained model MobileNet V2
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
base_model.trainable = False
在添加最终的tf.keras.layers.Dense(1)之前,冻结并添加GlobalAveragePooling 2D()。因此,模型结构如下所示:
model = tf.keras.Sequential([
base_model,
global_average_layer,
prediction_layer
])
其等效于:
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D()
tf.keras.layers.Dense(1)
])
因此,他们不仅添加了最终的dense(1)图层,还在之前添加了GlobalAveragePooling 2D()图层。
另一个使用tf flowers数据集:
在这个implementation中是不同的。没有添加一个全局平均池2D()。
feature_extractor_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/2"
feature_extractor_layer = hub.KerasLayer(feature_extractor_url,
input_shape=(224,224,3))
feature_extractor_layer.trainable = False
model = tf.keras.Sequential([
feature_extractor_layer,
layers.Dense(image_data.num_classes)
])
其中image_data.num_classes为5,表示不同的花卉分类。因此,在本例中,不添加GlobalAveragePooling 2D()图层。
我不明白这一点。为什么这是不同的?何时添加一个GlobalAveragePooling 2D()或没有?什么是更好的/我应该做什么?
我不确定原因是因为在一种情况下数据集cats and dogs是二元分类问题,而在另一种情况下是多类分类问题。或者区别是在一种情况下tf.keras.applications.MobileNetV2
用于加载MobileNetV 2,而在另一种实现中hub.KerasLayer
用于获取feature_extractor。当我检查第一种实现中的模型时:
我可以看到最后一层是一个relu激活层。
当我检查feature_extractor时:
model = tf.keras.Sequential([
feature_extractor,
tf.keras.layers.Dense(1)
])
model.summary()
输出如下:
也许原因还在于我不明白tf.keras.applications.MobileNetV2
与hub.KerasLayer
之间的区别。hub.KerasLayer只是给了我特征提取器。我知道这一点,但我仍然认为我没有理解这两种方法之间的区别。
我无法检查feature_extractor本身的图层。因此feature_extractor.summary()或feature_extractor.layers不起作用。我如何检查这里的图层?我如何知道我是否应该添加GlobalAveragePooling 2D?
3条答案
按热度按时间vcirk6k61#
摘要
为什么这是不同的?何时添加一个GlobalAveragePooling 2D()或不?什么是更好的/我应该做什么?
第一种情况下,它输出的4维Tensor是最后一个卷积层的原始输出。因此,你需要以某种方式将它们展平,在本例中,你使用的是GlobalAveragePooling 2D(但你可以使用任何其他策略)。我不知道哪个更好:这取决于您的问题,取决于
hub.KerasLayer
版本如何实现flatten,它们可能完全相同。也就是说,我只选择其中一个,然后继续:我看不出他们之间有很大的差别,长答案:了解Keras实施
差异在于两个基本模型的输出:在Keras示例中,输出的形状为
(bz, hh, ww, nf)
,其中bz
是批量大小,hh
和ww
是模型中最后一个卷积层的高度和重量,nf
是在该最后一层中应用的滤波器(或卷积)的数量。因此:这将输出基础模型的最后卷积(或滤波器)的输出。
因此,您需要将这些输出(您可以将其视为图像)转换为
(bz, n_feats)
形状的矢量,其中n_feats
是基础模型正在计算的特征数。转换完成后,您可以堆叠分类层(或任意数量的层),因为此时您已经拥有了矢量。如何计算这个转换?一些常见的替代方法是取卷积输出的平均值或最大值(这会减小大小),或者您可以将它们重新整形为一行,或者添加更多的卷积层,直到您得到一个矢量作为输出(我强烈建议遵循通常的做法,如平均值或最大值)。
在第一个示例中,当调用
tf.keras.applications.MobileNetV2
时,您使用的是与去年相关的默认策略,因此,最后一个卷积层“按原样”:您可以使用param pooling修改此行为,如here:合并:include_top为False时用于特征提取的可选池模式。
None
(默认)表示模型的输出将是最后一个卷积块的4DTensor输出。avg
意味着全局平均汇集将被应用于最后一个卷积块的输出,并且因此模型的输出将是2DTensor。max
表示将应用全局最大池。总之,在第一个示例中,您在构建基础模型时没有明确告知如何处理最后一层,模型会不断返回4维Tensor,您可以立即使用平均池将其转换为向量,因此如果您告诉Keras这样做,您可以避免这种显式平均池:
TFHub实现
最后,当您使用TensorFlow Hub实现时,当您选择
feature_vector
版本的模型时,它已经实现了某种类型的池(我还没有找到如何实现的),以确保模型输出向量而不是4维Tensor。因此,您不需要显式添加层来转换它们,因为它已经完成了。在我看来,我更喜欢Keras的实现,因为它给了你更多的自由来选择你想要的策略(事实上,你可以继续堆叠任何你想要的)。
bejyjqdl2#
假设有一个模型采用[1,208,208,3]个图像,并具有6个具有核[2,2,2,2,2,7]的池化层,这将导致在最后一个conv层中针对2048个过滤器的图像[1,1,1,2048]的特征列。
如果我们放松对输入图像的约束(这通常是对象检测模型的情况),而在大小为[1,104,208,3]的同一组汇集层图像之后,将产生[1,4,7,2024]的前最后汇集输出,并且[1,256,408,3]将产生[1,8,13,2048]。该Map将具有与原始[1,7,7,2048]大致相同的信息量,但是原始池化层将不产生具有[1,1,1,N]的特征列。这就是为什么我们切换到全局池化层。
简而言之,如果我们对输入图像大小没有严格的限制(并且在模型中的第一个操作时不调整图像大小),全局池层就很重要。
dly7yett3#
我认为模型“www.example.com“的输出差异https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/2是1d vector * batch_size,您无法对其应用Conv2D。
tf.keras.applications.MobileNetV2的输出可能更复杂,因此您有更多的能力来转换输出。