Keras:微调 Inception 时精度下降

Posted

技术标签:

【中文标题】Keras:微调 Inception 时精度下降【英文标题】:Keras: Accuracy Drops While Finetuning Inception 【发布时间】:2019-02-16 07:45:59 【问题描述】:

我无法使用 Keras 微调 Inception 模型。

我已经设法使用教程和文档来生成一个完全连接的顶层模型,该模型使用 Inception 的瓶颈特征将我的数据集分类到适当的类别中,准确率超过 99%。

import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications


# dimensions of our images.
img_width, img_height = 150, 150

#paths for saving weights and finding datasets
top_model_weights_path = 'Inception_fc_model_v0.h5'
train_data_dir = '../data/train2'
validation_data_dir = '../data/train2' 

#training related parameters?
inclusive_images = 1424
nb_train_samples = 1424
nb_validation_samples = 1424
epochs = 50
batch_size = 16


def save_bottlebeck_features():
    datagen = ImageDataGenerator(rescale=1. / 255)

    # build bottleneck features
    model = applications.inception_v3.InceptionV3(include_top=False, weights='imagenet', input_shape=(img_width,img_height,3))

    generator = datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='categorical',
        shuffle=False)

    bottleneck_features_train = model.predict_generator(
        generator, nb_train_samples // batch_size)

    np.save('bottleneck_features_train', bottleneck_features_train)

    generator = datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='categorical',
        shuffle=False)

    bottleneck_features_validation = model.predict_generator(
        generator, nb_validation_samples // batch_size)

    np.save('bottleneck_features_validation', bottleneck_features_validation)

def train_top_model():
    train_data = np.load('bottleneck_features_train.npy')
    train_labels = np.array(range(inclusive_images))

    validation_data = np.load('bottleneck_features_validation.npy')
    validation_labels = np.array(range(inclusive_images))

    print('base size ', train_data.shape[1:])

    model = Sequential()
    model.add(Flatten(input_shape=train_data.shape[1:]))
    model.add(Dense(1000, activation='relu'))
    model.add(Dense(inclusive_images, activation='softmax'))
    model.compile(loss='sparse_categorical_crossentropy',
             optimizer='Adam',
             metrics=['accuracy'])

    proceed = True

    #model.load_weights(top_model_weights_path)

    while proceed:
        history = model.fit(train_data, train_labels,
              epochs=epochs,
              batch_size=batch_size)#,
              #validation_data=(validation_data, validation_labels), verbose=1)
        if history.history['acc'][-1] > .99:
            proceed = False

    model.save_weights(top_model_weights_path)


save_bottlebeck_features()
train_top_model()

50/50 纪元 1424/1424 [===============================] - 17 秒 12 毫秒/步 - 损耗:0.0398 - 加速度:0.9909

我还能够将此模型堆叠在 inception 之上以创建我的完整模型并使用该完整模型对我的训练集进行成功分类。

from keras import Model
from keras import optimizers
from keras.callbacks import EarlyStopping

img_width, img_height = 150, 150

top_model_weights_path = 'Inception_fc_model_v0.h5'
train_data_dir = '../data/train2'
validation_data_dir = '../data/train2' 

#how many inclusive examples do we have?
inclusive_images = 1424
nb_train_samples = 1424
nb_validation_samples = 1424
epochs = 50
batch_size = 16

# build the complete network for evaluation
base_model = applications.inception_v3.InceptionV3(weights='imagenet', include_top=False, input_shape=(img_width,img_height,3))

top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(1000, activation='relu'))
top_model.add(Dense(inclusive_images, activation='softmax'))

top_model.load_weights(top_model_weights_path)

#combine base and top model
fullModel = Model(input= base_model.input, output= top_model(base_model.output))

#predict with the full training dataset
results = fullModel.predict_generator(ImageDataGenerator(rescale=1. / 255).flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='categorical',
        shuffle=False))

对该完整模型的处理结果的检查与瓶颈生成的全连接模型的准确性相匹配。

import matplotlib.pyplot as plt
import operator

#retrieve what the softmax based class assignments would be from results
resultMaxClassIDs = [ max(enumerate(result), key=operator.itemgetter(1))[0] for result in results]

#resultMaxClassIDs should be equal to range(inclusive_images) so we subtract the two and plot the log of the absolute value 
#looking for spikes that indicate the values aren't equal 
plt.plot([np.log(np.abs(x)+10) for x in (np.array(resultMaxClassIDs) - np.array(range(inclusive_images)))])

问题出在: 当我采用这个完整的模型并尝试对其进行训练时,即使验证保持在 99% 以上,准确率也会下降到 0。

model2 = fullModel

for layer in model2.layers[:-2]:
    layer.trainable = False

# compile the model with a SGD/momentum optimizer
# and a very slow learning rate.
#model.compile(loss='binary_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),  metrics=['accuracy'])

model2.compile(loss='categorical_crossentropy',
             optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), 
             metrics=['accuracy'])

train_datagen = ImageDataGenerator(rescale=1. / 255)

test_datagen = ImageDataGenerator(rescale=1. / 255)

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
    validation_data_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='categorical')

callback = [EarlyStopping(monitor='acc', min_delta=0, patience=3, verbose=0, mode='auto', baseline=None)]
# fine-tune the model
model2.fit_generator(
    #train_generator,
    validation_generator,
    steps_per_epoch=nb_train_samples//batch_size,
    validation_steps = nb_validation_samples//batch_size,
    epochs=epochs,
    validation_data=validation_generator)

纪元 1/50 89/89 [==============================] - 388s 4s/step - 损失:13.5787 - acc: 0.0000e+ 00 - val_loss:0.0353 - val_acc:0.9937

随着事情的发展,情况会变得更糟

21/50 纪元 89/89 [==============================] - 372s 4s/step - loss: 7.3850 - acc: 0.0035 - val_loss : 0.5813 - val_acc: 0.8272

我唯一能想到的是,不知何故,最后一列火车上的训练标签分配不正确,但我之前使用 VGG16 用类似的代码成功地做到了这一点。

我搜索了代码,试图找到一个差异来解释为什么一个模型在 99% 的时间内做出准确预测会降低其训练准确度,同时在微调期间保持验证准确度,但我无法弄清楚。任何帮助将不胜感激。

关于代码和环境的信息:

会显得很奇怪,但本来就是这样的事情:

每个班级只有一张图片。该NN旨在分类 环境和方向条件为 受控。他们只是每个班级的一个可接受的图像 对应正确的环境和旋转情况。 测试集和验证集相同。这个NN是唯一的 设计用于正在接受培训的课程。图像 它将处理类示例的副本。这是我的 意图将模型过度拟合到这些类中

我正在使用:

Windows 10 Anaconda客户端1.6.14下的Python 3.5.6 Keras 2.2.2 Tensorflow 1.10.0 作为后端 CUDA 9.0 CuDNN 8.0

我已签出:

    Keras accuracy discrepancy in fine-tuned model VGG16 Keras fine tuning: low accuracy Keras: model accuracy drops after reaching 99 percent accuracy and loss 0.01 Keras inception v3 retraining and finetuning error How to find which version of TensorFlow is installed in my system?

但它们似乎无关。

【问题讨论】:

你为什么要阻止最后 2 层的训练,在迁移学习中,当你训练模型时,这 2 层应该是最重要的。它要么是模型正在改变,但不允许对最后两层进行更改,你的模型无法正确学习,要么你以某种方式过度拟合批次。 我不是。 model2.layers[:-2] 返回所有但最后两层。因此,初始基础模型保持静止。我意识到 inception 的一些顶层应该解冻以进行微调,但它不应该导致这个问题。 Sry 将其位置误读为 [-2:] @SemicolonsandDuctTape 训练目录的结构如何?每张图片都在自己的文件夹中吗? 是 train2/image1/image1.bmp , train2/image2/image2.bmp 等 【参考方案1】:

和之前的回复一样,我会尝试分享一些想法,看看是否有帮助。

有几件事引起了我的注意(也许值得回顾)。注意:其中一些也应该给您带来单独模型的问题。

如果我错了,请纠正,但您似乎在第一次训练中使用了sparse_categorical_crossentropy,而在第二次训练中使用了categorical_crossentropy。这是正确的吗?因为我相信他们假设标签的方式不同(sparse 假设整数,而另一个假设 one-hot)。 您是否尝试将最后添加的图层设置为trainable = True?我知道您已经将其他设置为 trainable = False,但也许这也值得检查。 数据生成器似乎没有使用 Inception v3 中使用的默认预处理功能,该功能使用平均通道。 您是否尝试过使用函数式 API 而不是顺序式 API 的任何实验?

希望对你有帮助。

【讨论】:

【参考方案2】:

注意:由于您的问题有点奇怪并且在没有经过训练的模型和数据集的情况下难以调试,因此在考虑了许多可能出错的事情之后,这个答案只是一个(最好的)猜测。请提供您的反馈,如果它不起作用,我将删除此答案。

由于 inception_V3 包含BatchNormalization 层,当您将trainable 参数设置为False(1、2、@987654323 @, 4)。

现在,让我们看看这是否是问题的根源:as suggested by @fchollet,在定义模型时设置学习阶段以进行微调:

from keras import backend as K

K.set_learning_phase(0)

base_model = applications.inception_v3.InceptionV3(weights='imagenet', include_top=False, input_shape=(img_width,img_height,3))

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

K.set_learning_phase(1)

top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(1000, activation='relu'))
top_model.add(Dense(inclusive_images, activation='softmax'))

top_model.load_weights(top_model_weights_path)

#combine base and top model
fullModel = Model(input= base_model.input, output= top_model(base_model.output))

fullModel.compile(loss='categorical_crossentropy',
             optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), 
             metrics=['accuracy'])


#####################################################################
# Here, define the generators and then fit the model same as before #
#####################################################################

旁注:这不会对您的情况造成任何问题,但请记住,当您使用 top_model(base_model.output) 时,整个 Sequential 模型(即 top_model)存储为一层fullModel。您可以使用fullModel.summary()print(fullModel.layers[-1]) 来验证这一点。因此,当您使用时:

for layer in model2.layers[:-2]:
    layer.trainable = False 

您实际上也没有冻结base_model 的最后一层。但是,由于它是Concatenate 层,因此没有可训练的参数,因此不会出现任何问题,并且会按照您的预期运行。

【讨论】:

以上是关于Keras:微调 Inception 时精度下降的主要内容,如果未能解决你的问题,请参考以下文章

VGG16 Keras微调:精度低

精度随着时代的增加而降低

微调 keras .h5 模型到 C++ 中使用的 .pb 模型会导致运行模型失败错误

训练准确性增加,然后偶尔突然下降。使固定? [Keras] [TensorFlow 后端]

inception模型和卷积层的残差连接的keras实现

Keras深度学习实战——基于Inception v3实现性别分类