迁移学习resnet_resnet50迁移学习期间的大量过拟合
这是我第一次尝试使用CNN做某事,因此我可能做的很愚蠢-但无法弄清楚我错了...该模型似乎学习得很好,但是验证准确性并没有提高(甚至-在第一个时期之后),并且验证损失实际上随着时间而增加。看起来我不太适合(1个时期后?)-我们必须以其他方式关闭。我正在训练一个CNN网络-我有约100k种各种植物(1000个类)的图像,并想对ResNet50进行微调以创建一个多类分类器。图片大小各异,我像这样加载它
这是我第一次尝试使用CNN做某事,因此我可能做的很愚蠢-但无法弄清楚我错了...
该模型似乎学习得很好,但是验证准确性并没有提高(甚至-在第一个时期之后),并且验证损失实际上随着时间而增加。看起来我不太适合(1个时期后?)-我们必须以其他方式关闭。
我正在训练一个CNN网络-我有约100k种各种植物(1000个类)的图像,并想对ResNet50进行微调以创建一个多类分类器。图片大小各异,我像这样加载它们:
fromkeras.preprocessingimportimagedefpath_to_tensor(img_path):# loads RGB image as PIL.Image.Image typeimg=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 tensorreturnnp.expand_dims(x,axis=0)defpaths_to_tensor(img_paths):list_of_tensors=[path_to_tensor(img_path)forimg_pathinimg_paths]#can use tqdm(img_paths) for datareturnnp.vstack(list_of_tensors)enter code here
数据库很大(不适合内存),必须创建自己的生成器才能提供从磁盘读取和扩充的功能。(我知道Keras具有.flow_from_directory()-但我的数据不是以这种方式结构化的-它只是将100k图像与100k元数据文件混合在一起的转储)。我可能应该创建一个脚本来更好地构建它们,而不是创建自己的生成器,但是问题可能出在其他地方。
下面的生成器版本暂时不做任何扩充-只是重新缩放:
defgenerate_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 workwhile1:filesize=len(images_to_read)# count how many entries we have readn_entries=0# as long as we haven't read all entries from the file: keep readingwhilen_entries
这是我定义模型的方式:
defget_model():# define the modelbase_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 themforlayerinbase_net.layers:layer.trainable=Falsex=base_net.output#for resnet50x=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 modelmodel.compile(loss='categorical_crossentropy',optimizer=optimizers.Adam(1e-3),metrics=['acc'])returnmodel
因此,作为结果,我对大约70k图像具有1,562,088个可训练参数
然后,我使用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()。
我还决定检查模型是否确实在产生有用的东西-我为数据集计算了botleneck特征,然后使用随机森林来预测类。它确实有效,我的准确度约为0.4
因此,我想我的图像输入格式肯定有问题。下一步,我将对模型进行微调(带有一个新的顶层),以查看问题是否仍然存在...
更新2:
我认为问题在于图像预处理。最后,我最终没有进行微调,只是提取了botleneck层并训练linear_SVC()-获得了大约60%的训练和大约45%的测试数据集的准确性。
解决方案
您有没有解决问题的办法?如果不是,那么这可能是您的resnet中的批处理规范层的问题。我也遇到过类似的问题,例如在keras批处理规范层中,在培训和测试期间的行为有很大不同。因此,您可以通过以下方式冻结所有bn层:
BatchNorm()(training=False)
然后尝试在相同的数据集上重新训练您的网络。还有一件事情要记住,在训练过程中,您应该将训练标志设置为
import keras.backend as K
K.set_learning_phase(1)
并在测试过程中将此标志设置为0。我认为在进行上述更改后,它应该可以工作。
如果您找到其他解决问题的方法,请在此处发布,以便其他人可以从中受益。
谢谢。
更多推荐
所有评论(0)