删除Keras中预先训练的VGG16模型中的中间层

删除Keras中预先训练的VGG16模型中的中间层,keras,Keras,各位, 我有一个关于如何修改Keras中预先培训的VGG16网络的问题。我尝试删除最后三个卷积层末尾的最大池层,并在每个卷积层末尾添加批处理规范化层。同时,我想保留参数。这意味着整个修改过程不仅包括删除一些中间层、添加一些新层,还包括将修改后的层与其余层连接起来 我在凯拉斯还是个新手。我能找到的唯一方法如中所示 因此,我编辑的代码如下所示: from keras import applications from keras.models import Model from keras.laye

各位,

我有一个关于如何修改Keras中预先培训的VGG16网络的问题。我尝试删除最后三个卷积层末尾的最大池层,并在每个卷积层末尾添加批处理规范化层。同时,我想保留参数。这意味着整个修改过程不仅包括删除一些中间层、添加一些新层,还包括将修改后的层与其余层连接起来

我在凯拉斯还是个新手。我能找到的唯一方法如中所示

因此,我编辑的代码如下所示:

from keras import applications
from keras.models import Model
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers.normalization import BatchNormalization
vgg_model = applications.VGG16(weights='imagenet',
                           include_top=False,
                           input_shape=(160, 80, 3))
# Disassemble layers
layers = [l for l in vgg_model.layers]

# Defining new convolutional layer.
# Important: the number of filters should be the same!
# Note: the receiptive field of two 3x3 convolutions is 5x5.
layer_dict = dict([(layer.name, layer) for layer in vgg_model.layers])
x = layer_dict['block3_conv3'].output

for i in range(11, len(layers)-5):
    # layers[i].trainable = False
    x = layers[i](x)

for j in range(15, len(layers)-1):
    # layers[j].trainable = False
    x = layers[j](x)

x = Conv2D(filters=128, kernel_size=(1, 1))(x)
x = BatchNormalization()(x)
x = Conv2D(filters=128, kernel_size=(1, 1))(x)
x = BatchNormalization()(x)
x = Conv2D(filters=128, kernel_size=(1, 1))(x)
x = BatchNormalization()(x)
x = Flatten()(x)
x = Dense(50, activation='softmax')(x)


custom_model = Model(inputs=vgg_model.input, outputs=x)
for layer in custom_model.layers[:16]:
    layer.trainable = False

custom_model.summary()
然而,块4和块5中卷积层的输出形状是多重的。我试图通过添加一个图层MaxPool2D(batch_size=(1,1),stride=none)来纠正它,但输出形状仍然是多个。就这样,

Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 160, 80, 3)        0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 160, 80, 64)       1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 160, 80, 64)       36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 80, 40, 64)        0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 80, 40, 128)       73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 80, 40, 128)       147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 40, 20, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 40, 20, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 40, 20, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 40, 20, 256)       590080    
_________________________________________________________________
block4_conv1 (Conv2D)        multiple                  1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        multiple                  2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        multiple                  2359808   
_________________________________________________________________
block5_conv1 (Conv2D)        multiple                  2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        multiple                  2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        multiple                  2359808   
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 40, 20, 128)       65664     
_________________________________________________________________
batch_normalization_1 (Batch (None, 40, 20, 128)       512       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 40, 20, 128)       16512     
_________________________________________________________________
batch_normalization_2 (Batch (None, 40, 20, 128)       512       
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 40, 20, 128)       16512     
_________________________________________________________________
batch_normalization_3 (Batch (None, 40, 20, 128)       512       
_________________________________________________________________
flatten_1 (Flatten)          (None, 102400)            0         
_________________________________________________________________
dense_1 (Dense)              (None, 50)                5120050   
=================================================================
Total params: 19,934,962
Trainable params: 5,219,506
Non-trainable params: 14,715,456
_________________________________________________________________
有人能提供一些关于如何实现我的目标的建议吗


非常感谢。

有多个输出形状,因为这些层被调用了两次,所以它们有两个输出形状。 您可以看到,如果调用
layer.output\u shape
引发AttributeError,则打印的输出形状将是“多个”

如果调用
custom\u model.layers[10]。output\u shape
,则会出现以下错误:
AttributeError:层“block4\u conv1”有多个入站节点,具有不同的输出形状。因此,该层的“输出形状”概念定义不正确。请改用`get\u output\u shape\u at(node\u index)`来代替。

然后,如果调用
自定义模型.layers[10]。在(0)
处获取输出形状,您将获得与初始网络对应的输出形状,对于
自定义模型.layers[10]。在(1)
处获取输出形状,您将获得所需的输出形状

让我来说明一下,我怀疑您的修改意图:如果您删除了最大池层,并且将下一层(编号11)应用于最大池层之前的输出,那么学习到的过滤器“期望”的图像分辨率将降低两倍,因此它们可能无法工作

让我们假设一个过滤器正在“寻找”眼睛,而眼睛通常是10像素宽,您需要一个20像素宽的眼睛来触发层中的相同激活。

我的例子显然过于简单化和不精确,但它只是显示出原来的想法是错误的,你应该重新训练模型的顶部/保持最大池层/定义一个全新的模型在顶层Bux3Vang3。ew模型和导入预训练权重?@kosnik,我已经重新编辑了我的问题,希望这对你来说是清楚的。@mpariente,我正在考虑……谢谢。嗨,@mpariente,谢谢你的回答,但是我对你关于我为什么称这些层的解释有点困惑。我如何从我构建的模型中找到它?我试图添加cod在代码“custom\u model=model(inputs=vgg\u model.input,outputs=x)”之后,直接使用“custom\u model.layers[10]。获取(1)的\u output\u shape\u(1)”(不确定是否正确),然后我获得了这个值错误:ValueError:要求在节点1获取输出形状,但该层只有1个入站节点。然后我将其更改为“custom\u model.layers[10].get_output_shape_at(1)”,没有错误,但仍有相同的“倍数””“在那儿。你能给我多解释一下吗?至于这个网络的意图,它来自于一篇发表论文中的一种方法。由于没有可用的代码,我尝试重建它,以将其性能与其他方法进行比较。作者删除了最大池层以增加输出的大小,以便更准确地定位目标,因为他们使用的图像非常小。我不确定这一步骤是否真的能为最终结果带来好处,我必须实施它以确认其性能。再次感谢:)关于我的第一条评论的一些更正:1。我对您的解释有点困惑,为什么我两次调用这些层2。将其更改为“custom_model.layers[10]。在(0)处获取_output_shape_”