加权随机采样器 - 过采样还是欠采样?

问题描述

问题

我正在 PyTorch 中训练一个用于二元分类的深度学习模型,我有一个包含不平衡类比例的数据集。我的少数类占给定观察的大约 10%。为了避免模型学习只预测多数类,我想在我的 WeightedRandomSampler 中使用 torch.utils.data 中的 DataLoader

假设我有 1000 个观察值(900 类在 0 类中,100 类在 1 类中),批量大小为 {{1} } 用于我的数据加载器。

如果没有加权随机抽样,我希望每个训练时期包含 10 个批次。

问题

  • 在使用此采样器时,每个时期是否只会采样 10 个批次 - 因此,模型是否会在每个时期“错过”多数类的大部分,因为现在少数类在训练批次中所占比例过高?立>
  • 使用采样器是否会导致每个 epoch 采样超过 10 个批次(意味着相同的少数类观察可能出现多次,而且训练速度会变慢)?

解决方法

这取决于您的追求,请查看 torch.utils.data.WeightedRandomSampler 文档了解详情。

有一个参数 DateTimeOffset 允许您指定当 num_samplesDataset 组合时实际创建的样本数量(假设您正确加权):

  • 如果您将其设置为 torch.utils.data.DataLoader,您将获得第一个案例
  • 如果您将其设置为 len(dataset)(在您的情况下),您将获得第二种情况

使用此采样器时,每个 epoch 将仅采样 10 个批次 - 因此,模型会在每个 epoch 期间“错过”多数类的大部分 [...]

是的,但是这个epoch过去后会返回新的样本

使用采样器是否会导致每个 epoch 采样超过 10 个批次(意味着相同的少数类观察可能出现多次,而且训练速度会变慢)?

训练不会变慢,每个 epoch 会花费更长的时间,但收敛应该大致相同(因为每个 epoch 中的数据更多,因此需要的 epoch 更少)。

,

使用WeightedRandomSampler的一小段代码
首先定义函数:

def make_weights_for_balanced_classes(images,nclasses):                        
    count = [0] * nclasses                                                      
    for item in images:                                                         
        count[item[1]] += 1                                                     
    weight_per_class = [0.] * nclasses                                      
    N = float(sum(count))                                                   
    for i in range(nclasses):                                                   
        weight_per_class[i] = N/float(count[i])                                 
    weight = [0] * len(images)                                              
    for idx,val in enumerate(images):                                          
        weight[idx] = weight_per_class[val[1]]                                  
    return weight                         

                                  

在此之后,以下一种方式使用它:

import torch 
dataset_train = datasets.ImageFolder(traindir)                                                                         
                                                                                
# For unbalanced dataset we create a weighted sampler                       
weights = make_weights_for_balanced_classes(dataset_train.imgs,len(dataset_train.classes))                                                                
weights = torch.DoubleTensor(weights)                                       
sampler = torch.utils.data.sampler.WeightedRandomSampler(weights,len(weights))                     
                                                                                
train_loader = torch.utils.data.DataLoader(dataset_train,batch_size=args.batch_size,shuffle = True,sampler = sampler,num_workers=args.workers,pin_memory=True)