Python Pytorch Dataloader如何处理可变大小的数据?

Python Pytorch Dataloader如何处理可变大小的数据?,python,pytorch,tensor,variable-length,Python,Pytorch,Tensor,Variable Length,我有一个如下所示的数据集。也就是说,第一个项目是用户id,后面是用户单击的项目集 0 24104 27359 6684 0 24104 27359 1 16742 31529 31485 1 16742 31529 2 6579 19316 13091 7181 6579 19316 13091 2 6579 19316 13091 7181 6579 19316 2 6579 19

我有一个如下所示的数据集。也就是说,第一个项目是用户id,后面是用户单击的项目集

0   24104   27359   6684
0   24104   27359
1   16742   31529   31485
1   16742   31529
2   6579    19316   13091   7181    6579    19316   13091
2   6579    19316   13091   7181    6579    19316
2   6579    19316   13091   7181    6579    19316   13091   6579
2   6579    19316   13091   7181    6579
4   19577   21608
4   19577   21608
4   19577   21608   18373
5   3541    9529
5   3541    9529
6   6832    19218   14144
6   6832    19218
7   9751    23424   25067   12606   26245   23083   12606
我定义了一个自定义数据集来处理单击日志数据

导入torch.utils.data作为数据
类ClickLogDataset(data.Dataset):
定义初始化(自身,数据路径):
self.data\u path=数据路径
self.uids=[]
self.streams=[]
打开(self.data_路径,'r')作为fdata:
对于fdata中的行:
行=行.strip('\n').split('\t'))
self.uids.append(int(行[0]))
self.streams.append(列表(映射(int,行[1:]))
定义(自我):
返回len(self.uids)
def uu getitem uu(self,idx):
uid,stream=self.uids[idx],self.streams[idx]
返回uid,流
然后,我使用数据加载器从数据中检索小批量以进行培训

从torch.utils.data.dataloader导入dataloader
clicklog\u dataset=ClickLogDataset(数据路径)
clicklog\u data\u loader=DataLoader(数据集=clicklog\u数据集,批量大小=16)
对于uid\U批,流\U数据\U加载器中的流\U批:
打印(uid\u批)
打印(流式打印)
上面的代码返回的结果与我预期的不同,我希望
stream\u batch
是长度为
16
的整数类型的2D张量。然而,我得到的是一个长度为16的一维张量列表,该列表只有一个元素,如下所示。为什么呢

#stream_batch
[tensor([24104, 24104, 16742, 16742,  6579,  6579,  6579,  6579, 19577, 19577,
        19577,  3541,  3541,  6832,  6832,  9751])]

那么,您如何处理样本长度不同的事实呢?具有
collate\u fn
参数,用于将样本列表转换为批次。当然,它也适用于列表。您可以编写自己的
collate\u fn
,例如
0
-填充输入,将其截断到某个预定义的长度,或应用您选择的任何其他操作。

正如@Jatentaki所建议的,我编写了自定义的collate函数,它运行良好

def get_max_长度(x):
返回长度(最大值(x,键=长度))
def pad_顺序(顺序):
def垫(_it,_max_len):
返回[0]*(\u max\u len-len(\u it))+\u it
返回[_pad(it,get_max_length(seq))用于序列中的它]
def自定义_校对(批次):
转置=压缩(*批次)
lst=[]
对于转置的样本:
如果isinstance(样本[0],int):
一级附加(火炬长传感器(样品))
elif isinstance(样本[0],浮点):
一级附加(火炬双张量(样本))
elif isinstance(示例[0],collections.Sequence):
一级附加(火炬长传感器(pad_序列(样本)))
返回lst
stream\u dataset=StreamDataset(数据路径)
stream\u data\u loader=torch.utils.data.dataloader.dataloader(dataset=stream\u dataset,
批次大小=批次大小,
collate\u fn=自定义\u collate,
洗牌(错误)

我就是这样做的:

def collate_fn_padd(batch):
    '''
    Padds batch of variable length

    note: it converts things ToTensor manually here since the ToTensor transform
    assume it takes in images rather than arbitrary tensors.
    '''
    ## get sequence lengths
    lengths = torch.tensor([ t.shape[0] for t in batch ]).to(device)
    ## padd
    batch = [ torch.Tensor(t).to(device) for t in batch ]
    batch = torch.nn.utils.rnn.pad_sequence(batch)
    ## compute mask
    mask = (batch != 0).to(device)
    return batch, lengths, mask
然后我将其作为一个
collate\u fn
传递给dataloader类


pytorch论坛上似乎有一个巨大的不同帖子列表。让我链接到它们。他们都有自己的答案和讨论。在我看来,似乎没有一个“标准的方法来做它”,但如果有来自权威参考,请分享

如果理想答案中提到

  • 效率,例如,如果使用Corlate函数中的torch与numpy中的torch在GPU中进行处理
诸如此类的事情

名单:

扣件:
-

交叉张贴:如果我不想填写额外的数字怎么办?我的意思是,如果我有一个完全卷积的神经网络,我不需要相同大小的输入,特别是我不想通过填充来改变输入(我正在做一个可以解释的人工智能实验)?@RedFloyd这一切都很好,只是你需要做一些调整,并且会失去一些性能。在PyTorch(以及几乎所有其他框架)中,CNN操作(如
Conv2d
)以“矢量化”方式在第一维度(通常称为批处理维度)上执行。在你的例子中,你只需要让这个维度等于1,并在你有图像的时候调用你的网络,而不是把它们叠加成一个大张量,然后在所有图像上执行一次你的网络。这可能会影响您的性能,但仅此而已。感谢您的回复。只是澄清一下,这样做本质上是SGD,这将是嘈杂和麻烦的训练(即,可能不会很好地收敛)?是否习惯将张量放在GPU上进行比较?我的印象是,这意味着如果您这样做,就不能在数据加载器中使用多个worker。我很想知道哪种方法通常性能更好。@Pinocchio为什么要计算序列长度和掩码?如果我理解正确,一旦批量进入网络,网络就无法使用掩码或修剪输入,对吗?如果有人无意中发现了这一点,我认为David Ng提供的答案是最好的方法