【问题标题】:Overfitting - huge difference between training and validation accuracy过拟合——训练和验证准确率之间的巨大差异
【发布时间】:2020-07-16 08:48:49
【问题描述】:

我有一个包含 180k 图像的数据集,我尝试识别图像上的字符(车牌识别)。所有这些车牌都包含 7 个字符,并且可能有 35 个字符,因此输出向量 y 的形状为 (7, 35)。因此,我对每个车牌标签进行了 onehot 编码。

我应用了 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)

现在,经过几个时期的训练,我发现在训练准确度和验证准确度方面存在很大差异。我认为,其中一个原因是数据量小。还有哪些其他因素会影响我的模型中的这种过度拟合?你认为我的代码/模型有什么问题吗?您是否认为模型也很大很复杂,或者可能是由于数据的预处理?

注意:我已经尝试了数据增强并尝试了没有迁移学习的模型。这导致训练和验证数据的结果不佳。那么,还有什么我可以做的吗?

【问题讨论】:

  • 就像你说的,你的模型很大。如您所见,用这么少的数据集训练这么大的模型很容易导致过度训练。更多的数据从来都不是坏事,只要保持批次大小足够小,就不会压倒你的 GPU。您也没有说明您是否使用过任何图像预处理,这将在这种情况下对您有所帮助。
  • 与 CPU 相比,GPU 上的训练速度较慢可归因于多种原因,从兼容性到驱动程序。您可以尝试将密集层的数量减少到 2。我建议训练一个找到边界框并裁剪车牌的网络,然后使用其他一些网络/算法来识别字母/数字。
  • 试试 10k train 和 2k val ?也许 1k 还不够……对于性能问题,也许可以试试 Google 协作:colab.research.google.com 我建议也试试 CNN :)
  • @Tobitor 将取决于您的 GPU,尝试推送尽可能高的批次。 8/16 会被认为是 mini-batch,这是一种常见的技术,但我认为 8 太小了。
  • 您是否检查过 EfficicentNet-B0 训练是否正确冻结?

标签: python tensorflow keras conv-neural-network


【解决方案1】:

首先是免责声明

您确定这是正确的做法吗? EfficientNet 是为图像识别创建的模型,您的任务需要在一张图像中正确定位 7 个字符,识别每个字符,并要求保持字符的顺序。也许像this medium post 这样的检测+分割然后识别的方法更有效(双关语)。尽管我认为这很可能是您真正的问题,但我会尝试回答您最初的问题。

现在有一些关于过拟合的一般提示

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

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

现在,经过几个 epoch 的训练,我发现在训练准确度和验证准确度方面存在很大差异。

有几个,你的意思是多少个纪元?因为从您提出的问题中的图像来看,我认为第二个完整的时期还为时过早,无法推断您的模型过度拟合。另外,从代码(10 个时期)和您发布的图像(20 个时期)来看,我会说要训练更多时期,比如 40 个。

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

实践中的数据增强会增加您拥有的样本数量。但是,您有 180K 图像并且只使用 10K 图像,数据增强很好,但是当您有更多可用图像时,请先尝试使用它们。从我提到的那个指南来看,使用这个模型和谷歌 colab 似乎可以使用更多图像进行训练。所以,试着增加火车的大小。仍然在 DA 的主题中,一些转换可能对您的任务有害,例如过多的旋转或反射,因为您正在尝试识别数字和字母。

将批量大小减少到 16 可能会提供更多的正则化,这有助于对抗过度拟合。说到正则化,尝试将regularization 应用于您正在添加的密集层。

编辑:

在快速阅读您链接的论文后,我重申我关于时代的观点,因为在论文中显示了 100 个时代的结果。同样从论文中的图表中,我们可以看到无法确认作者也没有过拟合。此外,Xception 网络的变化根本不清楚。由于卷积操作的工作方式,更改输入层会对所有其他层的尺寸产生影响,本文未对此进行讨论。为实现该输出维度而执行的操作也不清楚。除了您所做的之外,我还建议您使用池化层来获得您想要的输出尺寸。最后,论文没有说明如何保证板的定位。我会尝试获取有关您尝试复制的这篇论文的更多详细信息,以确保您的模型中没有遗漏任何内容。

【讨论】:

  • 非常感谢您的全面回答!我会尝试应用这些技巧。您如何看待我使用无分段车牌识别系统的方法?您认为我的方法在理论上正确吗?
  • 嘿@Tobitor 在快速阅读您链接的那些论文后,我已经编辑了我的答案。
  • 感谢您的回答!当然,我们不能排除作者也存在过度拟合的问题。但如图 4 所示,它们仅在几个 epoch 之后就具有非常高的验证准确度。但我认为你是对的,我应该了解有关该论文的更多细节,但这并不容易......而且是的,我尝试以某种方式重现结果,但我使用其他数据和另一种架构(EfficientNet 与Xception;论文中的顶部模型不清楚)。
  • 我去过那里,我知道复制一些论文的困难。祝你好运!
  • 好的,谢谢!既然是攻读硕士学位,希望能有个好结局:-)
【解决方案2】:

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

  1. 任何深度 CNN 模型,例如 VGG、ResNet 或 EfficientNet,用于提取图像特征。
  2. 然后在 CNN 主干之上添加一些 RNN 层,以从提取的特征中获取字符序列。如果您想预测可变长度的字符,这将是一个很大的优势。
  3. 从RNN层得到字符序列后,下一步就是解码这个字符序列。为此,您可以使用CTC based methodattention mechanism。这两种方法都有各自的优缺点。基于 CTC 的方法速度很快,但性能有点差,另一方面,基于注意力的模型给出了很好的结果,但它们非常慢。因此,方法的选择取决于您的要求。

下图来自非常著名的文本识别论文CRNN,给出了上述步骤的总体思路。 [

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

最好的问候!

【讨论】:

    猜你喜欢
    • 2020-03-28
    • 2023-03-24
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    相关资源
    最近更新 更多