简体   繁体   English

在keras中微调预训练模型

[英]Fine tuning pretrained model in keras

I want to use a pretrained imagenet VGG16 model in keras and add my own small convnet on top. 我想在keras中使用预训练的imagenet VGG16模型,并在顶部添加我自己的小型网站。 I am only interested in the features, not the predictions 我只对功能感兴趣,而不是对预测感兴趣

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
import os
from keras.models import Model
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense

load images from directory (the dir contains 4 images) 从目录加载图像(目录包含4个图像)

IF = '/home/ubu/files/png/'
files = os.listdir(IF)

imgs = [img_to_array(load_img(IF + p, target_size=[224,224])) for p in files]
im = np.array(imgs)

load the base model, preprocess input and get the features 加载基础模型,预处理输入并获取功能

base_model = VGG16(weights='imagenet', include_top=False)

x = preprocess_input(aa)
features = base_model.predict(x)

this works, and I get the features for my images on the pretrained VGG. 这是有效的,我在预训练的VGG上获得了我的图像功能。

I now want to finetune the model and add some convolutional layers. 我现在想要微调模型并添加一些卷积层。 I read https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html and https://keras.io/applications/ but cannot quite bring them together. 我阅读了https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.htmlhttps://keras.io/applications/,但无法将它们整合在一起。

adding my model on top: 在顶部添加我的模型:

x = base_model.output
x = Convolution2D(32, 3, 3)(x)
x = Activation('relu')(x)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Convolution2D(32, 3, 3)(x)
x = Activation('relu')(x)
feat = MaxPooling2D(pool_size=(2, 2))(x)

building the complete model 建立完整的模型

model_complete = Model(input=base_model.input, output=feat)

stop base layers from being learned 停止学习基础层

for layer in base_model.layers:
layer.trainable = False

new model 新模型

model_complete.compile(optimizer='rmsprop', 
          loss='binary_crossentropy')

now fit the new model, the model is 4 images and [1,0,1,0] are the class labels. 现在适合新模型,模型是4个图像,[1,0,1,0]是类标签。 But this is obviously wrong: 但这显然是错误的:

model_complete.fit_generator((x, [1,0,1,0]), samples_per_epoch=100, nb_epoch=2)

ValueError: output of generator should be a tuple (x, y, sample_weight) or (x, y). Found: None

How is this done? 这是怎么做到的?

How would I do it if I only wanted to replace the last convolutional block (conv block5 in VGG16) instead of adding something? 如果我只想替换最后一个卷积块(VGG16中的conv block5)而不是添加某些东西,我该怎么办呢?

How would I only train the bottleneck features? 我怎么只训练瓶颈功能?

The features output features has shape (4, 512, 7, 7). 功能输出features具有形状(4,512,7,7)。 There are four images, but what is in the other dimensions? 有四个图像,但其他维度是什么? How would I reduce that to a (1,x) array? 我如何将其减少为(1,x)数组?

Fitting model 拟合模型

The problem with your generator code is that the fit_generator method expects a generator function to generate the data for fitting which you don't provide. 生成器代码的问题在于fit_generator方法需要生成器函数生成适合您未提供的数据。 You can either define a generator as done in the tutorial that you have linked to or create the data and labels yourself and fit your model yourself: 您可以在已链接到的教程中定义生成器,也可以自己创建数据和标签,并自己适合您的模型:

model_complete.fit(images, labels, batch_size=100, nb_epoch=2)

where images are your generated training images and labels are the corresponding labels. 其中图像是您生成的训练图像,标签是相应的标签。

Removing last layer 删除最后一层

Assuming you have a model variable and the "pop" method described below, you can do model = pop(model) to remove the last layer. 假设你有一个模型变量和下面描述的“pop”方法,你可以做model = pop(model)来删除最后一层。

Training only specific layers As you have done in your code, you can do: 仅培训特定图层正如您在代码中所做的那样,您可以执行以下操作:

for layer in base_model.layers:
    layer.trainable = False

Then you can "unfreeze" and layer that you want by changing their trainable property to True . 然后,您可以通过将其trainable属性更改为True来“解冻”并分层。

Changing dimensions 改变尺寸

To change the output to a 1D array you can use the Flatten layer 要将输出更改为1D阵列,可以使用“展平”图层


The pop method 流行方法

def pop(model):
    '''Removes a layer instance on top of the layer stack.
    This code is thanks to @joelthchao https://github.com/fchollet/keras/issues/2371#issuecomment-211734276
    '''
    if not model.outputs:
        raise Exception('Sequential model cannot be popped: model is empty.')
    else:
        model.layers.pop()
        if not model.layers:
            model.outputs = []
            model.inbound_nodes = []
            model.outbound_nodes = []
        else:
            model.layers[-1].outbound_nodes = []
            model.outputs = [model.layers[-1].output]
        model.built = False

    return model

Use model.fit(X, y) to train on your dataset as explained here: https://keras.io/models/model/#fit 使用model.fit(X, y)训练您的数据集,如下所述: httpsmodel.fit(X, y)

Additionally you should add a Flatten layer and a dense layer with an ouput shape of 1 to get the correct result shape. 此外,您应该添加一个Flatten图层和一个输出形状为1的密集图层,以获得正确的结果形状。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM