【问题标题】:keras flow_from_directory over or undersample a classkeras flow_from_directory 对类进行过度或欠采样
【发布时间】:2017-06-08 11:51:53
【问题描述】:

我正在尝试用 Keras 做一个二元分类问题,使用ImageDataGenerator.flow_from_directory 方法来生成批次。但是,我的类非常不平衡,比如一个类比另一个类多 8 倍或 9 倍,导致模型无法为每个示例预测相同的输出类。有没有办法将flow_from_directory 设置为在每个时期从我的小班进行过采样或从我的大班进行欠采样?目前,我刚刚在我的小班中创建了每个图像的多个副本,但我希望有更多的灵活性。

【问题讨论】:

    标签: python machine-learning neural-network deep-learning keras


    【解决方案1】:

    使用当前版本的 Keras - 仅使用 Keras 内置方法无法平衡您的数据集。 flow_from_directory 只是构建所有文件及其类的列表,对其进行洗牌(如果需要),然后对其进行迭代。

    但是你可以做一个不同的技巧——通过编写你自己的生成器来实现python内部的平衡:

    def balanced_flow_from_directory(flow_from_directory, options):
        for x, y in flow_from_directory:
             yield custom_balance(x, y, options)
    

    这里的custom_balance 应该是一个函数,给定一个批处理(x, y) 正在平衡它并返回一个平衡的批处理(x', y')。对于大多数应用程序,批处理的大小不需要相同 - 但有一些奇怪的用例(例如 stateful RNN) - 其中批处理大小应该具有固定大小)。

    【讨论】:

      【解决方案2】:

      您可以做的一件事是在调用model.fit()model.fit_generator() 时设置class_weight 参数。

      您还可以使用 sklearnnumpy 库轻松计算您的 class_weights,如下所示:

      from sklearn.utils import class_weight
      import numpy as np
      
      class_weights = class_weight.compute_class_weight(
                 'balanced',
                  np.unique(train_generator.classes), 
                  train_generator.classes)
      

      然后,它变得像设置你的class_weights等于class_weight参数一样简单:

      model.fit_generator(..., class_weight=class_weights) 
      

      【讨论】:

      • 你如何保证np.unique(train_generator.classes) 会以正确的顺序返回课程?
      【解决方案3】:

      还可以计算每个类的文件个数,对class_weights进行归一化

      files_per_class = []
      for folder in os.listdir(input_foldr):
          if not os.path.isfile(folder):
                  files_per_class.append(len(os.listdir(input_foldr + '/' + folder)))
      total_files = sum(files_per_class)
      class_weights = {}
      for i in xrange(len(files_per_class)):
          class_weights[i] = 1 - (float(files_per_class[i]) / total_files)
      print (class_weights)
      ...
      ...
      ...
      model.fit_generator(... ,class_weight=class_weights)
      

      【讨论】:

      • 嘿,我知道这是一个旧答案,但我遇到了这个并喜欢这个解决方案。上面有一个问题: os.listdir 不能保证按字母顺序返回,但 flow_from_directory 可以;我使用的解决方案是: lst = os.lisdir(input_foldr); lst.sort();然后按照与 flow_from_directory 相同的顺序(希望)对这些权重进行排序。
      • 我仍然担心个别批次的例如将平衡 32 个样本。如果所有样本都来自一个类(可能是非常不平衡的数据集),那么权重只会被推动以在超权类方向上对这些样本进行分类。如果批次恰好有稀有样本,class_weight 如何增加该批次中该样本的效果?我怀疑它比想象的更棘手。
      猜你喜欢
      • 2019-09-03
      • 2023-01-29
      • 2020-04-28
      • 2020-08-30
      • 2021-08-20
      • 2020-09-19
      • 2018-06-21
      • 2015-05-26
      • 2020-09-06
      相关资源
      最近更新 更多