在Keras的CNN模型中,训练和损失值没有变化

14

我正在运行CNN来分类左右鞋印。我有190,000个训练图像,使用其中10%进行验证。我的模型设置如下。我获取所有图像的路径,读取并调整它们的大小。我对图像进行归一化处理,然后将其适配到模型中。问题在于,我的训练准确率停留在62.5%左右,损失约为0.6615-0.6619。我是否有做错的地方?我该如何避免这种情况发生?

以下是一些有趣的要点:

  1. 我最初在10张图片上测试了这个方法,但是同样遇到了同样的问题,将优化器更改为Adam,批量大小改为4就能解决。

  2. 然后我测试了更多的图片,但每次都需要改变批量大小才能提高准确性和损失。在使用10,000张图像时,我需要使用批量大小为500和优化器RMSProp。然而,准确度和损失在第10轮之后才真正开始变化。

  3. 现在我正在使用190,000张图像进行训练,由于GPU已经达到最大值,我无法增加批量大小。

    imageWidth = 50
    imageHeight = 150
    
    def get_filepaths(directory):
        file_paths = []
        for filename in files:
            filepath = os.path.join(root, filename)
            file_paths.append(filepath) # Add it to the list.
        return file_paths
    
    def cleanUpPaths(fullFilePaths):
        cleanPaths = []
        for f in fullFilePaths:
            if f.endswith(".png"):
                cleanPaths.append(f)
        return cleanPaths
    
    def getTrainData(paths):
        trainData = []
        for i in xrange(1,190000,2):
            im = image.imread(paths[i])
            im = image.imresize(im, (150,50))
            im = (im-255)/float(255)
            trainData.append(im)
        trainData = np.asarray(trainData)
        right = np.zeros(47500)
        left = np.ones(47500)
        trainLabels = np.concatenate((left, right))
        trainLabels = np_utils.to_categorical(trainLabels)
        return (trainData, trainLabels)

    #create the convnet
    model = Sequential()
    
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(imageWidth,imageHeight,1),strides=1))#32
    model.add(Conv2D(32, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    
    model.add(Conv2D(64, (3, 3), activation='relu',strides=1))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(1, 3)))
    model.add(Dropout(0.25))
    
    model.add(Conv2D(64, (1, 2), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 1)))
    model.add(Dropout(0.25))
    
    model.add(Flatten())
    model.add(Dense(256, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(2, activation='softmax'))
    
    sgd = SGD(lr=0.01)
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=['accuracy'])
    
    #prepare the training data*/
    
    trainPaths = get_filepaths("better1/train")
    trainPaths = cleanUpPaths(trainPaths)
    (trainData, trainLabels) = getTrainData(trainPaths)
    trainData = np.reshape(trainData,(95000,imageWidth,imageHeight,1)).astype('float32')
    trainData = (trainData-255)/float(255)
    
    #train the convnet***
    model.fit(trainData, trainLabels, batch_size=500, epochs=50, validation_split=0.2)
    
    #/save the model and weights*/
    model.save('myConvnet_model5.h5');
    model.save_weights('myConvnet_weights5.h5');
5个回答

26

我已经多次遇到这个问题,因此想做一个小结并提供可能的解决方案等来帮助未来的人。

问题:模型针对其所看到的所有数据预测两个或更多可能的类别中的其中一个*

确认问题是否发生方法1:模型的准确率在训练时保持在0.5左右(或1/n,其中n是类的数量)。方法2:获取预测中每个类别的计数,并确认它正在预测所有一个类别。

修复/检查(按某种顺序):

  • 双重检查模型架构: 使用model.summary()检查模型。
  • 检查数据标签:确保您的训练数据的标签在预处理等过程中没有混淆(这种情况确实会发生!)。
  • 检查随机训练数据喂养:确保您不是一次将训练数据按一个类别馈送给模型。例如,如果使用ImageDataGenerator().flow_from_directory(PATH),请检查参数shuffle=Truebatch_size大于1。
  • 检查预训练的层不可训练:**如果使用预训练模型,请确保任何使用预训练权重的层在初始时都是不可训练的。对于前几轮,只有新添加的(随机初始化)层应该是可训练的;for layer in pretrained_model.layers: layer.trainable = False应该出现在您的代码中。
  • 逐渐降低学习率:不断将学习率减小到10的倍数并重试。请注意,每次尝试新的学习率时,您都必须完全重新初始化要训练的层。 (例如,我曾经遇到过这个问题,只有当我降到lr=1e-6时才得以解决,因此请继续尝试!)

如果你知道更多可以帮助模型训练的修复或检查方法,请贡献出来,我会尝试更新列表。

请注意,在新层被初始化训练“足够”之后,通常可将预训练模型设置为更加可训练。

*其他与此问题相关的名称,以便于搜索到这里... keras tensorflow theano CNN 卷积神经网络 坏的训练 固定不变 被卡住 修复 不静态 已打破 bug 只有0.5的准确度 不改变 只预测单一类别 无法训练 模型卡在类别处 模型在epochs之间重置 keras CNN 相同输出


4
你好,DBCerigo。欢迎来到SO。请勿在不同的帖子中反复发布相同的答案,否则很可能会被删除。尽量根据具体问题调整你的建议。谢谢。 - petezurich

7
你可以尝试在MaxPooling2D()后添加一个BatchNormalization()层。这对我很有用。

4
我会尝试几个方法。较低的学习率应该有助于处理更多的数据。通常,调整优化器应该有所帮助。此外,您的网络似乎非常小,您可能需要通过添加层或增加层中的过滤器数量来增加模型的容量。
如何在实践中应用深度学习的更好描述,请参见此处

所以我通过在每个卷积层后添加批量归一化层来让模型学习。现在我得到了低的训练损失和验证损失,以及高的训练和验证准确率。然而,当我将测试数据输入模型时,我只得到了50%的准确率。这是一个二元分类任务,所以这并不比随机猜测好。除了增加模型的容量,还有其他什么可以做的吗? - TriniPhantom

4

我只有两件事要补充到DBCerigo的伟大列表中。

  • 检查激活函数:一些层默认使用线性激活函数,如果你没有在模型中插入一些非线性,它就无法推广,因此网络将尝试学习如何线性分离非线性特征空间。确保设置了非线性是一个好的检查点。
  • 检查模型复杂度:如果你有一个相对简单的模型,并且它仅学习到第1或第2个时期然后停止,可能是因为它试图学习某些太复杂的东西。尝试使模型更深。当使用仅有1或2个未冻结层的冻结模型时,通常会发生这种情况。

虽然第二个可能是显而易见的,但我曾经遇到过这个问题,花费了很多时间检查所有事情(数据,批次,LR...)才能找出问题所在。

希望这有所帮助。


谢谢,我几乎和你在第二点描述的一样做了。你有没有找到任何速查表或类似的东西,可以快速查看什么时候使用最佳? - Naveen Reddy Marthala
1
很遗憾,我们不能这样做,但是我们可以从这篇帖子的答案中汇集所有的知识。 - JVGD

-4

在我的情况下,激活函数很重要。我从“sgd”更改为“a”


SGD是一个优化器而不是激活函数!你的意思是你可能要改变优化器? - JVGD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接