Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pytorch 使用特定元素自定义批处理_Pytorch_Torch - Fatal编程技术网

Pytorch 使用特定元素自定义批处理

Pytorch 使用特定元素自定义批处理,pytorch,torch,Pytorch,Torch,我是pytorch的新手。Strangley我找不到任何与此相关的东西,尽管它看起来相当简单 我想用具体的例子来构造我的批,就像每个批的所有例子都有相同的标签,或者只用两个类的例子来填充批 我该怎么做?对我来说,它似乎是数据加载器中的正确位置,而不是数据集中的正确位置?因为数据加载器负责批处理而不是数据集 是否有简单的最小示例?TLDR 默认的DataLoader只使用一个,而不是一个批取样器 您可以定义一个采样器,加上一个批次采样器,批次采样器将覆盖采样器 采样器只生成数据集元素的序列,而

我是pytorch的新手。Strangley我找不到任何与此相关的东西,尽管它看起来相当简单

我想用具体的例子来构造我的批,就像每个批的所有例子都有相同的标签,或者只用两个类的例子来填充批

我该怎么做?对我来说,它似乎是数据加载器中的正确位置,而不是数据集中的正确位置?因为数据加载器负责批处理而不是数据集

是否有简单的最小示例?

TLDR

  • 默认的
    DataLoader
    只使用一个,而不是一个批取样器

  • 您可以定义一个采样器,加上一个批次采样器,批次采样器将覆盖采样器

  • 采样器只生成数据集元素的序列,而不是实际批次(这由数据加载器处理,具体取决于
    批次大小


  • 回答您最初的问题:在iterable数据集上使用采样器似乎是不可能的cf.(仍然打开)。另外,请阅读以下关于的注释


    采样器(用于地图样式数据集): 除此之外,如果要切换到地图样式的数据集,下面是有关采样器和批处理采样器工作的一些详细信息。您可以使用索引访问数据集的基础数据,就像使用列表一样(因为
    torch.utils.data.dataset
    实现了
    \uu getitem\uuu
    )。换句话说,您的数据集元素都是
    dataset[i]
    ,对于
    [0,len(dataset)-1]
    中的
    i

    以下是一个玩具数据集:

    class DS(Dataset):
        def __getitem__(self, index):
            return index
            
        def __len__(self):
            return 10
    
    在一般用例中,您只需给出参数
    batch\u size
    shuffle
    。默认情况下,
    shuffle
    设置为
    false
    ,这意味着它将使用
    torch.utils.data.SequentialSampler
    。否则(如果
    shuffle
    true
    torch.utils.data.RandomSampler将被使用。采样器定义数据加载器访问数据集的方式(访问顺序)

    上述数据集(
    DS
    )有10个元素。索引为
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    。它们映射到元素
    0
    10
    20
    30
    40
    50
    60
    70
    80
    90
    。因此,批量大小为2时:

    • SequentialSampler
      DataLoader(ds,batch\u size=2)
      (隐式
      shuffle=False
      ),与
      DataLoader(ds,batch\u size=2,sampler=SequentialSampler(ds))相同。
      。数据加载器将提供
      张量([0,10])
      张量([20,30])
      张量([40,50])
      张量([60,70])
      ,和
      张量([80,90])

    • RandomSampler
      DataLoader(ds,batch\u size=2,shuffle=True)
      ,与
      DataLoader(ds,batch\u size=2,sampler=RandomSampler(ds))相同。
      。每次迭代数据加载器时,它都会随机采样。例如:
      张量([50,40])
      张量([90,80])
      张量([0,60])
      张量([10,20])
      张量([30,70])
      。但是,如果您第二次遍历数据加载器,序列将不同


    分批取样器 提供
    batch\u sampler
    覆盖
    batch\u大小
    shuffle
    sampler
    ,以及
    最后一次下降
    。它旨在准确定义批处理元素及其内容。例如:

    >>> DataLoader(ds, batch_sampler=[[1,2,3], [6,5,4], [7,8], [0,9]])` 
    
    将产生
    张量([10,20,30])
    张量([60,50,40])
    张量([70,80])
    ,和
    张量([0,90])


    课堂上的批量抽样 假设我只想在批处理中有每个类的2个元素(不同或不不同),并且必须排除每个类的更多示例。因此,确保批次中没有3个示例

    假设您有一个包含四个类的数据集。我会这样做的。首先,跟踪每个类的数据集索引

    class DS(Dataset):
        def __init__(self, data):
            super(DS, self).__init__()
            self.data = data
    
            self.indices = [[] for _ in range(4)]
            for i, x in enumerate(data):
                if x > 0 and x % 2: self.indices[0].append(i)
                if x > 0 and not x % 2: self.indices[1].append(i)
                if x < 0 and x % 2: self.indices[2].append(i)
                if x < 0 and not x % 2: self.indices[3].append(i)
    
        def classes(self):
            return self.indices
    
        def __getitem__(self, index):
            return self.data[index]
    
    将提供:

    >>> ds.classes()
    [[0, 2, 8, 10, 13], [1, 4, 6, 7, 17], [3, 9, 11, 12, 16], [5, 14, 15]]
    
    然后对于批处理采样器,最简单的方法是创建一个可用的类索引列表,并且具有与dataset元素一样多的类索引

    在上面定义的数据集中,我们有5项来自类
    0
    ,5项来自类
    1
    ,5项来自类
    2
    ,3项来自类
    3
    。因此,我们要构造
    [0,0,0,0,0,1,1,1,1,2,2,2,2,3]
    。我们将洗牌。然后,从该列表和数据集类内容(
    ds.classes()
    )中,我们将能够构建批处理

    class Sampler():
        def __init__(self, classes):
            self.classes = classes
    
        def __iter__(self):
            classes = copy.deepcopy(self.classes)
            indices = flatten([[i for _ in range(len(klass))] for i, klass in enumerate(classes)])
            random.shuffle(indices)
            grouped = zip(*[iter(indices)]*2)
    
            res = []
            for a, b in grouped:
                res.append((classes[a].pop(), classes[b].pop()))
            return iter(res)
    
    注意-需要深度复制列表,因为我们正在从列表中弹出元素

    该采样器的可能输出为:

    [(15, 14), (16, 17), (7, 12), (11, 6), (13, 10), (5, 4), (9, 8), (2, 0), (3, 1)]
    
    此时,我们可以简单地使用
    torch.data.utils.DataLoader

    >>> dl = DataLoader(ds, batch_sampler=sampler(ds.classes()))
    
    这可能会产生如下结果:

    [tensor([ 4, -4]), tensor([-21,  11]), tensor([-13,   6]), tensor([9, 1]), tensor([  8, -21]), tensor([-3, 10]), tensor([ 6, -2]), tensor([-5,  7]), tensor([-6,  1])]
    

    更简单的方法 这里是另一种更简单的方法,它不能保证从数据集中返回所有元素,平均来说它会

    对于每个批次,首先对每个批次的
    class\u进行采样,然后对这些选定类别中的
    batch\u size
    元素进行采样(首先从该类别子集中对类别进行采样,然后从该类别中的数据点进行采样)

    您可以这样尝试:

    >>> s = Sampler(ds.classes(), class_per_batch=2, batch_size=4)
    >>> list(s)
    [[16, 0, 0, 9], [10, 8, 11, 2], [16, 9, 16, 8], [2, 9, 2, 3]]
    
    >>> dl = DataLoader(ds, batch_sampler=s)
    >>> list(iter(dl))
    [tensor([ -5,  -6, -21, -13]), tensor([ -4,  -4, -13, -13]), tensor([ -3, -21,  -2,  -5]), tensor([-3, -5, -4, -6])]
    

    您可能需要查看自定义采样器,它们基本上是数据加载器和数据集之间的中间层,这就是那种逻辑似乎适合的地方。我忘了说我使用的是iterable数据集。谢谢。我想这就是我需要的。您知道默认情况下dataloader是否同时使用采样器和btachsampler吗?因此,在原则上,我必须定制
    class Sampler():
        def __init__(self, classes, class_per_batch, batch_size):
            self.classes = classes
            self.n_batches = sum([len(x) for x in classes]) // batch_size
            self.class_per_batch = class_per_batch
            self.batch_size = batch_size
    
        def __iter__(self):
            classes = random.sample(range(len(self.classes)), self.class_per_batch)
            
            batches = []
            for _ in range(self.n_batches):
                batch = []
                for i in range(self.batch_size):
                    klass = random.choice(classes)
                    batch.append(random.choice(self.classes[klass]))
                batches.append(batch)
            return iter(batches)
    
    >>> s = Sampler(ds.classes(), class_per_batch=2, batch_size=4)
    >>> list(s)
    [[16, 0, 0, 9], [10, 8, 11, 2], [16, 9, 16, 8], [2, 9, 2, 3]]
    
    >>> dl = DataLoader(ds, batch_sampler=s)
    >>> list(iter(dl))
    [tensor([ -5,  -6, -21, -13]), tensor([ -4,  -4, -13, -13]), tensor([ -3, -21,  -2,  -5]), tensor([-3, -5, -4, -6])]