python - resnet50 迁移学习期间的大量过拟合

标签 python tensorflow keras conv-neural-network resnet

这是我第一次尝试使用 CNN 做一些事情,所以我可能在做一些非常愚蠢的事情 - 但无法弄清楚我错在哪里......

模型似乎学习得很好,但验证准确性并没有提高(甚至在第一个 epoch 之后),而且验证损失实际上随着时间的推移而增加。看起来我没有过度拟合(在 1 个时期之后?)——我们必须以其他方式关闭。

typical network behaviour

我正在训练 CNN 网络 - 我有大约 100k 种不同植物的图像(1000 个类别)并且想要微调 ResNet50 以创建多类分类器。图片大小不一,我是这样加载的:

from keras.preprocessing import image                  

def path_to_tensor(img_path):
    # loads RGB image as PIL.Image.Image type
    img = image.load_img(img_path, target_size=(IMG_HEIGHT, IMG_HEIGHT))
    # convert PIL.Image.Image type to 3D tensor with shape (IMG_HEIGHT, IMG_HEIGHT, 3)
    x = image.img_to_array(img)
    # convert 3D tensor to 4D tensor with shape (1, IMG_HEIGHT, IMG_HEIGHT, 3) and return 4D tensor
    return np.expand_dims(x, axis=0)

def paths_to_tensor(img_paths):
    list_of_tensors = [path_to_tensor(img_path) for img_path in img_paths] #can use tqdm(img_paths) for data
    return np.vstack(list_of_tensors)enter code here

数据库很大(无法放入内存)并且必须创建我自己的生成器来提供从磁盘读取和扩充。 (我知道 Keras 有 .flow_from_directory() - 但我的数据不是以这种方式构建的 - 它只是混合了 100k 元数据文件的 100k 图像的转储)。我可能应该创建一个脚本来更好地构建它们而不是创建我自己的生成器,但问题可能出在其他地方。

下面的生成器版本暂时不做任何增强——只是重新缩放:

def generate_batches_from_train_folder(images_to_read, labels, batchsize = BATCH_SIZE):    

    #Generator that returns batches of images ('xs') and labels ('ys') from the train folder
    #:param string filepath: Full filepath of files to read - this needs to be a list of image files
    #:param np.array: list of all labels for the images_to_read - those need to be one-hot-encoded
    #:param int batchsize: Size of the batches that should be generated.
    #:return: (ndarray, ndarray) (xs, ys): Yields a tuple which contains a full batch of images and labels. 

    dimensions = (BATCH_SIZE, IMG_HEIGHT, IMG_HEIGHT, 3)

    train_datagen = ImageDataGenerator(
        rescale=1./255,
        #rotation_range=20,
        #zoom_range=0.2, 
        #fill_mode='nearest',
        #horizontal_flip=True
    )

    # needs to be on a infinite loop for the generator to work
    while 1:
        filesize = len(images_to_read)

        # count how many entries we have read
        n_entries = 0
        # as long as we haven't read all entries from the file: keep reading
        while n_entries < (filesize - batchsize):

            # start the next batch at index 0
            # create numpy arrays of input data (features) 
            # - this is already shaped as a tensor (output of the support function paths_to_tensor)
            xs = paths_to_tensor(images_to_read[n_entries : n_entries + batchsize])

            # and label info. Contains 1000 labels in my case for each possible plant species
            ys = labels[n_entries : n_entries + batchsize]

            # we have read one more batch from this file
            n_entries += batchsize

            #perform online augmentation on the xs and ys
            augmented_generator = train_datagen.flow(xs, ys, batch_size = batchsize)

        yield  next(augmented_generator)

这就是我定义模型的方式:

def get_model():

    # define the model
    base_net = ResNet50(input_shape=DIMENSIONS, weights='imagenet', include_top=False)

    # Freeze the layers which you don't want to train. Here I am freezing all of them
    for layer in base_net.layers:
        layer.trainable = False

    x = base_net.output

    #for resnet50
    x = Flatten()(x)
    x = Dense(512, activation="relu")(x)
    x = Dropout(0.5)(x)
    x = Dense(1000, activation='softmax', name='predictions')(x)

    model = Model(inputs=base_net.input, outputs=x)

    # compile the model 
    model.compile(
        loss='categorical_crossentropy',
        optimizer=optimizers.Adam(1e-3),
        metrics=['acc'])

    return model

因此,我有 1,562,088 个可训练参数,用于大约 70,000 张图像

然后我使用 5 折交叉验证,但该模型不适用于任何折叠,因此我不会在此处包括完整代码,相关部分是这样的:

trial_fold = temp_model.fit_generator(
                train_generator,
                steps_per_epoch = len(X_train_path) // BATCH_SIZE,
                epochs = 50,
                verbose = 1,
                validation_data = (xs_v,ys_v),#valid_generator,
                #validation_steps= len(X_valid_path) // BATCH_SIZE,
                callbacks = callbacks,
                shuffle=True)

我做了很多事情 - 确保我的生成器确实在工作,尝试通过减少全连接层的大小来玩网络的最后几层,尝试增强 - 没有任何帮助......

我不认为网络中的参数数量太多 - 我知道其他人也做了几乎相同的事情并且准确度接近 0.5,但我的模型似乎疯狂地过拟合。非常感谢任何关于如何解决这个问题的想法!

更新 1:

我已决定停止重新发明内容并按文件排序以使用 .flow_from_directory() 过程。为了确保我正在导入正确的格式(由下面的 Ioannis Nasios 评论触发)- 我确保从 keras 的 resnet50 应用程序导入 preprocessing_unit()。

我还决定检查该模型是否真的产生了有用的东西 - 我计算了我的数据集的瓶颈特征,然后使用随机森林来预测类别。它确实有效,我得到了大约 0.4 的准确度

所以,我想我的图像输入格式肯定有问题。下一步,我将微调模型(使用新的顶层)以查看问题是否仍然存在...

更新 2:

我认为问题在于图像预处理。 最后我没有微调,只是提取了瓶颈层并训练了 linear_SVC() - 得到了大约 60% 的训练和大约 45% 的测试数据集的准确率。

最佳答案

您需要在 ImageDataGenerator 中使用 preprocessing_function 参数。

 train_datagen = ImageDataGenerator(preprocessing_function=keras.applications.resnet50.preprocess_input)

这将确保您的图像按照您正在使用的预训练网络的预期进行预处理。

关于python - resnet50 迁移学习期间的大量过拟合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50364706/

相关文章:

python - 如何知道是否发生欠拟合或过拟合?

python - 同步图内复制需要多少个 session 对象?

python - 按目录/文件夹合并 pdf

python - 使用 selenium python 截取整个页面截图

python - 将一个 tf.Dataset 与另一个 tf.Dataset 随机交错

python - 如何遍历各种训练和测试拆分

tensorflow - 我的模型训练中 val_acc 大幅下降,原因是什么?

python - keras 启动时间 (_make_train_function()) 在 Tesla V100-SXM2-16GB GPU 上非常慢,与功能较弱的 GPU 相比

python - Matlab Engine Python - OSx Anaconda Segfault 或 iPython 的 DYLD_LIBRARY_PATH 错误

python - 如何降低 argparse 中参数帮助的缩进级别?