据我了解,PyTorch的强度应该是它与动态计算图一起使用。在NLP的上下文中,这意味着具有可变长度的序列不一定需要填充到相同的长度。但是,如果我想使用PyTorch DataLoader,我需要填充我的序列,因为DataLoader只需要张量 - 假设我作为一个初学者不想构建一些自定义的collate_fn。
现在这让我想知道 - 在这种背景下,这不会消除动态计算图的整体优势吗? 另外,如果我将我的序列填充到DataLoader作为张量,并且在末尾有很多零作为填充标记(在单词ID的情况下),它会对我的训练产生任何负面影响,因为PyTorch可能没有针对使用填充序列进行计算(因为整个前提是它可以在动态图中使用可变序列长度),还是只是没有任何区别?
我也会在PyTorch论坛上发布这个问题......
谢谢!
答案 0 :(得分:4)
在NLP的上下文中,这意味着具有可变长度的序列不一定需要填充到相同的长度。
这意味着您不需要填充序列,除非您正在进行数据批处理,这是目前在PyTorch中添加并行性的唯一方法。 DyNet有一个名为autobatching的方法(详细描述in this paper),它对图操作而不是数据进行批处理,因此这可能是您想要查看的内容。
但是,如果我想使用PyTorch DataLoader,我需要填充我的序列,因为DataLoader只需要张量 - 假设我作为一个初学者不想构建一些自定义的collate_fn。
如果您编写自己的DataLoader
课程,并且使用Dataset
,则可以使用batch_size=1
。扭曲是为你的可变长度序列使用numpy数组(否则default_collate
会给你带来困难):
from torch.utils.data import Dataset
from torch.utils.data.dataloader import DataLoader
class FooDataset(Dataset):
def __init__(self, data, target):
assert len(data) == len(target)
self.data = data
self.target = target
def __getitem__(self, index):
return self.data[index], self.target[index]
def __len__(self):
return len(self.data)
data = [[1,2,3], [4,5,6,7,8]]
data = [np.array(n) for n in data]
targets = ['a', 'b']
ds = FooDataset(data, targets)
dl = DataLoader(ds, batch_size=1)
print(list(enumerate(dl)))
# [(0, [
# 1 2 3
# [torch.LongTensor of size 1x3]
# , ('a',)]), (1, [
# 4 5 6 7 8
# [torch.LongTensor of size 1x5]
# , ('b',)])]
现在这让我想知道 - 在这种情况下,这不会消除动态计算图的整体优势吗?
公平点,但动态计算图的主要优势(至少目前)主要是使用像pdb这样的调试工具的可能性,这会迅速缩短开发时间。使用静态计算图表进行调试会更加困难。 PyTorch也没有理由不在未来实施进一步的即时优化或类似于DyNet自动批处理的概念。
另外,如果我将我的序列填充到DataLoader作为张量,并且在末尾有很多零作为填充标记,它会对我的训练产生负面影响吗? / p>
是的,无论是在运行时还是在渐变中。 RNN将像普通数据一样遍历填充,这意味着您必须以某种方式处理它。 PyTorch为您提供处理填充序列和RNN的工具,即pad_packed_sequence
和pack_padded_sequence
。这些将允许您在RNN执行期间忽略填充元素,但要注意:这不适用于您自己实现的RNN(或者至少如果您不手动添加对它的支持)。