是否可以从中间层开始训练 CNN(通常和 Keras)?

Is it possible to train a CNN starting at an intermediate layer (in general and in Keras)?

我正在使用 mobilenet v2 在我的图像上训练模型。除了几层之外,我已经冻结了所有层,然后添加了额外的层用于训练。我希望能够从中间层而不是从头开始训练。我的问题:

  1. 是否可以提供最后一个冻结层的输出作为 训练输入(它将是 (?, 7,7,1280) 的张量)?
  2. 如何指定训练从第一个可训练的开始 (非冻结)层?在这种情况下,mbnetv2_conv.layer[153].
  3. 在这种情况下 y_train 是什么?我不太明白y_train 在训练过程中被使用——一般来说,什么时候 CNN 参考 y_train?

加载 mobilenet v2

image_size = 224
mbnetv2_conv = MobileNetV2(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))

    # Freeze all layers except the last 3 layers
    for layer in mbnetv2_conv.layers[:-3]:
        layer.trainable = False

    # Create the model
    model = models.Sequential()
    model.add(mbnetv2_conv)
    model.add(layers.Flatten())
    model.add(layers.Dense(16, activation='relu')) 
    model.add(layers.Dropout(0.5)) 
    model.add(layers.Dense(3, activation='softmax')) 
    model.summary()

    # Build an array (?,224,224,3) from images
    x_train = np.array(all_images)

    # Get layer output
    from keras import backend as K
    get_last_frozen_layer_output = K.function([mbnetv2_conv.layers[0].input],
                                  [mbnetv2_conv.layers[152].output])
    last_frozen_layer_output = get_last_frozen_layer_output([x_train])[0]

    # Compile the model
    from keras.optimizers import SGD
    sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
    model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['acc'])

    # how to train from a specific layer and what should y_train be?
    model.fit(last_frozen_layer_output, y_train, batch_size=2, epochs=10)

是的,你可以。两种不同的方式。

首先,困难的方法让您构建两个新模型,一个包含所有冻结层,一个包含所有可训练层。将 Flatten() 层添加到 frozen-layers-only 模型。并且您将逐层复制 mobilenet v2 中的权重以填充 frozen-layers-only 模型的权重。然后,您将通过 frozen-layers-only 模型 运行 输入图像,以 CSV 或 pickle 形式将输出保存到磁盘。现在这是您的 trainable-layers 模型的输入,您可以像上面那样使用 model.fit() 命令对其进行训练。完成训练后保存重量。然后你将不得不用两组层构建原始模型,并将权重加载到每一层中,并保存整个过程。大功告成!

但是,更简单的方法是将模型的权重与架构分开保存:

model.save_weights(filename)

然后在将其添加到新的空模型之前修改 MobileNetV2 中层的 layer.trainable 属性:

mbnetv2_conv = MobileNetV2(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))
for layer in mbnetv2_conv.layers[:153]:
    layer.trainable = False
model = models.Sequential() 
model.add(mbnetv2_conv) 

然后用

重新加载权重
newmodel.load_weights(filename)

这让您可以调整 mbnetv2_conv 模型中的哪些层将在运行中训练,然后只需调用 model.fit() 即可继续训练。