CNN是否比预训练的CNN更好?

时间:2020-04-26 10:42:51

标签: python tensorflow keras deep-learning

据我所知。预训练的CNN可以比CNN做得更好。我有855张图像的数据集。我已经应用了CNN并获得了94%的准确度。然后我也使用了预训练模型(VGG16,ResNet50,Inception_V3,MobileNet)进行了微调,但我仍然获得了60%的最高评分,其中两个在分类上做得很差。 CNN真的比预训练的模型好吗,否则我的实现是错误的。我已经将图片转换为100 x 100的尺寸,并遵循keras application的方式。那么问题是什么??

单纯的CNN方法:

def cnn_model():
    size = (100,100,1)
    num_cnn_layers =2
    NUM_FILTERS = 32
    KERNEL = (3, 3)
    MAX_NEURONS = 120

    model = Sequential()

    for i in range(1, num_cnn_layers+1):
        if i == 1:
            model.add(Conv2D(NUM_FILTERS*i, KERNEL, input_shape=size, 
            activation='relu', padding='same'))
        else:
            model.add(Conv2D(NUM_FILTERS*i, KERNEL, activation='relu', 
            padding='same'))

    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(int(MAX_NEURONS), activation='relu'))
    model.add(Dropout(0.25))
    model.add(Dense(int(MAX_NEURONS/2), activation='relu'))
    model.add(Dropout(0.4))
    model.add(Dense(3, activation='softmax'))

    model.compile(loss='categorical_crossentropy', optimizer='adam', 
    metrics=['accuracy'])
    return model

VGG16方法:

def vgg():
`  `vgg_model = keras.applications.vgg16.VGG16(weights='imagenet',include_top=False,input_shape = (100,100,3))
    model = Sequential()
    for layer in vgg_model.layers:
        model.add(layer)

    # Freeze the layers 
    for layer in model.layers:
        layer.trainable = False

    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(3, activation='softmax'))

    model.compile(optimizer=keras.optimizers.Adam(lr=1e-5),
              loss='categorical_crossentropy',
              metrics=['accuracy'])
    return model 

2 个答案:

答案 0 :(得分:2)

在两种情况下,您指的是CNN都在谈论同一件事,这是一种神经网络模型。只是预训练模型已经针对其他一些数据进行了训练,而不是针对您正在尝试进行分类的数据集。

这里通常使用的是转移学习。而不是冻结所有图层,而是尝试使最后几层保持打开状态,以便可以使用您的 own 数据对它们进行重新训练,从而使预训练的模型可以编辑其权重和偏差来满足您的需求。您可能要分类的数据集可能与预训练的模型无关。

这是我自己的工作中的一个示例,还有其他代码段,但您可以使其与自己的代码一起使用,逻辑保持不变

#You extract the layer which you want to manipulate, usually the last few.
last_layer = pre_trained_model.get_layer(name_of_layer)

# Flatten the output layer to 1 dimension
x = layers.Flatten()(last_output)
# Add a fully connected layer with 1,024 hidden units and ReLU activation
x = layers.Dense(1024,activation='relu')(x)
# Add a dropout rate of 0.2
x = layers.Dropout(0.2)(x)                  
# Add a final sigmoid layer for classification
x = layers.Dense(1,activation='sigmoid')(x)           

#Here we combine your newly added layers and the pre-trained model.
model = Model( pre_trained_model.input, x) 

model.compile(optimizer = RMSprop(lr=0.0001), 
              loss = 'binary_crossentropy', 
              metrics = ['accuracy'])

答案 1 :(得分:0)

除了@Ilknur Mustafa提到的内容外,由于您的数据集可能对用于预训练的图像不熟悉,因此您可以尝试重新训练预训练模型的最后几个层,而不是添加一个全新的层。下面的示例代码除了输出层之外没有添加任何其他可训练层。这样,您可以通过重新训练现有权重的最后几层而不是从头开始训练而受益。如果您没有要训练的大型数据集,这可能会有所帮助。

# load model without classifier layers 
vgg = VGG16(include_top=False, input_shape=(100, 100, 3), weights='imagenet', pooling='avg')
# make only last 2 conv layers trainable 
for layer in vgg.layers[:-4]:
    layer.trainable = False
# add output layer  
out_layer = Dense(3, activation='softmax')(vgg.layers[-1].output)
model_pre_vgg = Model(vgg.input, out_layer)
# compile model 
opt = SGD(lr=1e-5) 
model_pre_vgg.compile(optimizer=opt, loss=keras.losses.categorical_crossentropy, metrics=['accuracy'])