PyTorch:数据读取2 - Dataloader

-柚子皮-

dataloader的使用

torch.utils.data.DataLoader中的参数:

  • dataset (Dataset) – dataset from which to load the data.

  • batch_size (int, optional) – how many samples per batch to load (default: 1).
  • shuffle (bool, optional) – set to True to have the data reshuffled at every epoch (default: False).
  • sampler (Sampler, optional) – defines the strategy to draw samples from the dataset. If specified, shuffle must be False.
  • batch_sampler (Sampler, optional) – like sampler, but returns a batch of indices at a time. Mutually exclusive with batch_size, shuffle, sampler, and drop_last.
  • num_workers (int, optional) – how many subprocesses to use for data loading. 0 means that the data will be loaded in the main process. (default: 0)
  • collate_fn (callable*, *optional) – merges a list of samples to form a mini-batch.
  • pin_memory (bool, optional) – If True, the data loader will copy tensors into CUDA pinned memory before returning them. 如果pin_memory=True,那么Pytorch会采取一系列操作把数据拷贝到GPU,总之就是为了加速。
  • drop_last (bool, optional) – set to True to drop the last incomplete batch, if the dataset size is not divisible by the batch size. If False and the size of dataset is not divisible by the batch size, then the last batch will be smaller. (default: False)
  • timeout (numeric, optional) – if positive, the timeout value for collecting a batch from workers. Should always be non-negative. (default: 0)
  • worker_init_fn (callable, optional) – If not None, this will be called on each worker subprocess with the worker id (an int in [0, num_workers - 1]) as input, after seeding and before data loading. (default: None)

返回值

      返回值是一个实现了__iter__的对象,可以使用for循环进行迭代,或者转换成迭代器取第一条batch数据查看。

for循环进行迭代时返回的每条数据就是(batch_size,*)大小的。

示例1:

self.data_loader = torch.utils.data.DataLoader(
            dataset=self.dataset, collate_fn=self.collate_fn,
            batch_size=batch_size, shuffle=if_shuffle, num_workers=args.num_workers)

示例2:

DataLoader和TensorDataset结合使用

import torch
from torch.utils.data import DataLoader, TensorDataset

a = torch.tensor([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]])
b = torch.tensor([1, 2, 3, 4])
train_data = TensorDataset(a, b)
data = DataLoader(train_data, batch_size=2, shuffle=True)
for i, j in enumerate(data):
    x, y = j
    print(' batch:{0} x:{1}  y: {2}'.format(i, x, y))
 # batch:0 x:tensor([[4, 4, 4],
 #        [1, 1, 1]])  y: tensor([4, 1])
 # batch:1 x:tensor([[3, 3, 3],
 #        [2, 2, 2]])  y: tensor([3, 2])

DataLoader数据查看

batch数目

batch_num = len(train_dataloader)

获取dataset中的第一条数据

train_dataloader.dataset[0]    # 完全等价于原始dataset=self.dataset的self.dataset[0]

获取dataloader中batch中的第一条数据

def get_one_data(item_dict, i):
    return {k: v[i] for k, v in item_dict.items()}

print(get_one_data(next(iter(train_data_loader)), 1))

或者

    for item_dict in train_data_loader:
        print(get_one_data(item_dict, 1))
        break

自定义dataloader

Dataloader的处理逻辑是先通过Dataset类里面的 __getitem__ 函数获取单个数据,然后组合成batch,再使用collate_fn所指定的函数对这个batch做一些操作(比如每个batch中实际lengths,padding,cuda之类的)。

自定义collate_fn

data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True,
        num_workers=num_worker, collate_fn=collate_fn, pin_memory=True)

因为dataloader是有batch_size参数的,我们可以通过自定义参数collate_fn来设计数据收集的方式,意思是已经通过上面的Dataset类中的__getitem__函数采样了batch_size数据,以一个包的形式传递给collate_fn所指定的函数。

自动的输入

batch:是一个batch_size大小的list。其中的元素就是dataset中定义的__getitem__返回的一样。

示例

示例1:实现一个Collator类,实例化后作为参数输入到collate_fn。

class Collator(object):
    def __init__(self, conf):
        self.device = conf.device

    def __call__(self, batch):
        # print(batch)
        # raise NotImplementedError
        ...
        # id特征再处理
        # label_id再处理(onehot/multihot)
        batch_map = {
            'label': tensor_labels,
            'tokens1': torch.tensor(tokens1),
            'tokens2': torch.tensor(tokens2),
            'tokens1_mask': torch.tensor(tokens1).gt(0).float(),
            'tokens2_mask': torch.tensor(tokens2).gt(0).float(),
            'token_max_len': torch.tensor([token_max_len], dtype=torch.float32)}
        return batch_map

collate_fn = Collator(conf)

示例2:通过collate_fn进行解包

def collate_fn(data):
    A,B,path,hop=zip(*data)
    print('A:',A," B:",B," path:",path," hop:",hop)
    raise Exception('utils collate_fun 147')
    return A,B,path,hop

示例3:nlp任务中,经常在collate_fn指定的函数里面做padding,将同一个batch中不一样长的句子padding成一样长

def collate_fn(data):
    src, tgt, original_src, original_tgt = zip(*data)

    src_len = [len(s) for s in src]
    src_pad = torch.zeros(len(src), max(src_len)).long()
    for i, s in enumerate(src):
        end = src_len[i]
        src_pad[i, :end] = torch.LongTensor(s[end-1::-1])

    tgt_len = [len(s) for s in tgt]
    tgt_pad = torch.zeros(len(tgt), max(tgt_len)).long()
    for i, s in enumerate(tgt):
        end = tgt_len[i]
        tgt_pad[i, :end] = torch.LongTensor(s)[:end]

    return src_pad, tgt_pad, \
           torch.LongTensor(src_len), torch.LongTensor(tgt_len), \
           original_src, original_tgt

测试collate_fn

想要在collate_fn函数内部测试,需要在外面对dataloaders进行for调用,后再断点或者exit(),否则不会真正执行collate_fn,这样collate_fn函数中的print就不会执行了。

测试时,最好num_workers=0,这样print(batch)才不会输出太多。

for index, item in enumerate(data_loader):
    A = item
    exit()


 

一些问题

[为什么pytorch DataLoader在numpy数组和列表上的行为有所不同?]

1 import问题

使用torch.utils.data.DataLoader时,pycharm中无法直接点击进入代码。

[python模块导入及属性:import]

2 num_workers设置过大问题

num_workers如果设置过大,资源不够,会出错:Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
[Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)]

[https://github.com/pytorch/pytorch/issues/41794]

from: -柚子皮-

ref: 

PyTorch中,数据读取是构建深度学习模型的重要一环。为了高效处理大规模数据集,PyTorch提供了三个主要的工具:Dataset、DataLoader和TensorDataset。 Dataset是一个抽象类,用于自定义数据集。我们可以继承Dataset类,并重写其中的__len__和__getitem__方法来实现自己的数据加载逻辑。__len__方法返回数据集的大小,而__getitem__方法根据给定的索引返回样本和对应的标签。通过自定义Dataset类,我们可以灵活地处理各种类型的数据集。 DataLoader数据加载器,用于对数据集进行批量加载。它接收一个Dataset对象作为输入,并可以定义一些参数例如批量大小、是否乱序等。DataLoader能够自动将数据集划分为小批次,将数据转换为Tensor形式,然后通过迭代器的方式供模型训练使用。DataLoader数据准备和模型训练的过程中起到了桥梁作用。 TensorDataset是一个继承自Dataset的类,在构造时将输入数据和目标数据封装成Tensor。通过TensorDataset,我们可以方便地处理Tensor格式的数据集。TensorDataset可以将多个Tensor按行对齐,即将第i个样本从各个Tensor中取出,构成一个新的Tensor作为数据集的一部分。这对于处理多输入或者多标签的情况非常有用。 总结来说,Dataset提供了自定义数据集的接口,DataLoader提供了批量加载数据集的能力,而TensorDataset则使得我们可以方便地处理Tensor格式的数据集。这三个工具的配合使用可以使得数据处理变得更加方便和高效。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值