过度拟合-训练和验证准确性之间的巨大差异

时间:2020-07-16 08:48:49

标签: python tensorflow keras conv-neural-network

我有一个包含18万张图像的数据集,我试图对其进行识别(牌照识别)。所有这些车牌均包含七个字符,并且可能包含35个字符,因此输出向量y的形状为(7, 35)。因此,我对每个车牌标签进行了热编码。

我将EfficicentNet-B0模型的底部(https://keras.io/api/applications/efficientnet/#efficientnetb0-function)与定制的顶部一起应用,该顶部被分为7个分支(每个车牌七个字符)。我使用了imagenet的权重并冻结了efnB0_model的底层:

def create_model(input_shape = (224, 224, 3)):
    input_img = Input(shape=input_shape)
    model = efnB0_model (input_img)
    model = GlobalAveragePooling2D(name='avg_pool')(model)
    model = Dropout(0.2)(model)
    backbone = model

    branches = []
    for i in range(7):
        branches.append(backbone)
        branches[i] = Dense(360, name="branch_"+str(i)+"_Dense_16000")(branches[i])
        branches[i] = BatchNormalization()(branches[i])
        branches[i] = Activation("relu") (branches[i])
        branches[i] = Dropout(0.2)(branches[i])
              
        branches[i] = Dense(35, activation = "softmax", name="branch_"+str(i)+"_output")(branches[i])
    
    output = Concatenate(axis=1)(branches)
    output = Reshape((7, 35))(output)
    model = Model(input_img, output)

    return model

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

对于训练和验证模型,由于模型的大小和数据量巨大,我仅使用10.000训练图像和3.000验证图像,这会使我的训练非常非常缓慢。

我使用此DataGenerator将批次供入模型:

class DataGenerator(Sequence):

    def __init__(self, x_set, y_set, batch_size):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size

    def __len__(self):
        return math.ceil(len(self.x) / self.batch_size)

    def __getitem__(self, idx):
        batch_x = self.x[idx*self.batch_size : (idx + 1)*self.batch_size]
        batch_x = np.array([resize(imread(file_name), (224, 224)) for file_name in batch_x])
        batch_x = batch_x * 1./255
        batch_y = self.y[idx*self.batch_size : (idx + 1)*self.batch_size]
        batch_y = np.array(batch_y)

        return batch_x, batch_y

我使用以下代码拟合模型:

model.fit_generator(generator=training_generator,
                    validation_data=validation_generator,
                    steps_per_epoch = num_train_samples // 32,
                    validation_steps = num_val_samples // 32,
                    epochs = 10, workers=6, use_multiprocessing=True)

现在,经过几次培训之后,我发现培训准确性和验证准确性存在很大差异。我认为,原因之一是数据量较小。还有哪些其他因素会影响模型中的过度拟合?您认为我的代码/模型完全出问题了吗?您是否认为该模型又大又复杂,还是因为数据的预处理?

注意:我已经尝试了数据增强,并在没有进行转移学习的情况下尝试了该模型。这导致培训和验证数据的结果不佳。所以,我还能做些什么吗?

accuracy

2 个答案:

答案 0 :(得分:3)

首先免责声明

您确定这是正确的方法吗? EfficientNet是为图像识别而创建的模型,您的任务需要在一张图像中正确定位7个字符,识别每个图像,还要求保持字符顺序。也许像this medium post中那样,先进行检测+细分再进行识别的方法会更有效(双关语)。即使我认为这很可能是您遇到的真正问题,我也会尝试回答您的原始问题。

现在有关过度拟合的一些常规提示

Keras文档中有一个很好的指南here,介绍如何使用EfficientNet进行迁移学习。我将在这里尝试总结一些技巧。

从您的问题看来,您甚至没有在进行微调步骤,这对于网络更好地学习任务至关重要。

现在,经过几次培训,我发现培训准确性和验证准确性存在很大差异。

对于几个,您指的是几个纪元?因为从您提出问题的图像中,我认为第二个完整纪元还为时过早,无法推断出您的模型过度拟合。另外,从代码(10个纪元)到您发布的图像(20个纪元),我会说要训练更多个纪元,例如40个纪元。

增加辍学率。尝试一些配置,例如30%,40%,50%。

实际上,数据增强将增加您拥有的样本数量。但是,您有18万张图像,并且仅使用10K张图像,因此可以很好地进行数据增强,但是当您有更多可用图像时,请先尝试使用它们。从该指南中,我提到,使用此模型和Google colab似乎可以使用更多图像进行训练。因此,请尝试增加火车尺寸。仍然是DA的主题,某些转换可能对您的任务有害,例如过多的旋转或反射,因为您试图识别数字和字母。

将批次大小减小到16可以提供更多的正则化,这有助于防止过度拟合。说到正则化,请尝试将regularization应用于要添加的密集层。

编辑:

在快速阅读了您链接的论文后,我重申了我对历元的观点,因为在论文中显示了100个历元的结果。同样从本文的图表中,我们可以看到无法确认作者也没有过拟合。此外,Xception网络中的​​更改完全不清楚。由于卷积运算的工作方式,更改输入层会对所有其他层的尺寸产生影响,因此本文中不会对此进行讨论。实现该输出尺寸所执行的操作也不清楚。除了您所做的以外,我建议使用池化层来获取所需的输出尺寸。最后,本文没有解释如何保证板的位置。我将尝试获取您尝试复制的有关本文的更多详细信息,以确保您在模型中没有遗漏任何东西。

答案 1 :(得分:2)

我一直在研究用于工业应用的字符检测+识别问题。根据我的经验,仅使用深CNN和密集层来预测字符类别并不是解决此问题的最佳方法。有关场景文本识别问题的研究论文很多,一种常见的设计字符识别问题的方法是---

  1. 任何深层CNN模型(例如VGG,ResNet或EfficientNet)都可以提取图像特征。
  2. 然后在CNN主干网上添加一些RNN层,以从提取的特征中获取字符序列。如果您要预测可变长度的字符,这将是一个不错的选择。
  3. 从RNN层获取字符序列后,下一步是对该字符序列进行解码。为此,您可以使用CTC based methodattention mechanism。这两种方法各有优缺点。基于CTC的方法虽然速度很快,但性能却很差;另一方面,基于注意力的模型却能带来不错的效果,但是速度却很慢。因此,方法的选择取决于您的要求。

下面来自非常著名的文本识别纸CRNN的图片给出了有关上述步骤的一般想法。 [Steps for text recognition from very famous research paper: CRNN ][2]

对于训练模型,@ Hemerson提供了很好的建议。尝试通过多个阶段构建和训练这种类型的模型,我相信您会得到更好的结果:)

最诚挚的问候!