如何并行化用于 PyTorch 的 for 循环?
How can I parallelize a for loop for use in PyTorch?
我意识到 for
循环通常在 Python
中很慢。我有一些代码会混淆一些张量:
for batch_index, mask_batch in enumerate(mask):
mask_len = torch.sum(mask_batch).int()
if mask_len == 0:
side_input = torch.zeros((max_inp_len, side_input.shape[1])).to(mask.device)
else:
m_nonzero = mask_batch.nonzero().flatten()
first_nonzero = m_nonzero[0]
last_nonzero = m_nonzero[-1]
if side == 'left':
end_index = first_nonzero - 1
start_index = 0
elif side == 'right':
start_index = last_nonzero + 1
end_index = inputs[batch_index].size(1)
side_input = inputs[batch_index][start_index:end_index]
if end_index - start_index < max_inp_len:
pad_zeros = torch.zeros(
(max_inp_len - side_input.shape[0], side_input.shape[1])).to(mask.device)
if side == 'left':
side_input = torch.cat((pad_zeros, side_input), 0)
elif side == 'right':
side_input = torch.cat((side_input, pad_zeros), 0)
side_inputs.append(side_input)
return torch.stack(side_inputs)
我觉得这个循环真的很慢。有什么方法可以不用循环吗?
您应该创建一个包含循环迭代背后的逻辑的函数,并将其作为每个列的线程启动(请参阅 docs here). You could also use asyncio 并发库,但您可能获得的改进较少。
可以阅读为列表的每个元素生成线程的一个很好的例子here。
Python 在任何给定进程中都没有真正的并行性。您必须生成一个 ProcessPool 并在循环内部创建一个采用 batch_index, mask_batch
的函数,然后将该函数映射到当前 for 循环中的 mask
对象上。问题是,我不知道 PyTorch 是否能很好地处理这个问题。
像这样
def f(batch_index, mask_batch):
mask_len = torch.sum(mask_batch).int()
if mask_len == 0:
side_input = torch.zeros((max_inp_len, side_input.shape[1])).to(mask.device)
else:
m_nonzero = mask_batch.nonzero().flatten()
first_nonzero = m_nonzero[0]
last_nonzero = m_nonzero[-1]
if side == 'left':
end_index = first_nonzero - 1
start_index = 0
elif side == 'right':
start_index = last_nonzero + 1
end_index = inputs[batch_index].size(1)
side_input = inputs[batch_index][start_index:end_index]
if end_index - start_index < max_inp_len:
pad_zeros = torch.zeros((max_inp_len - side_input.shape[0], side_input.shape[1])).to(mask.device)
if side == 'left':
side_input = torch.cat((pad_zeros, side_input), 0)
elif side == 'right':
side_input = torch.cat((side_input, pad_zeros), 0)
return side_input
您可以查看的其他内容是进一步向量化代码。 PyTorch 和 Numpy 中的大多数东西都可以通过使用内置函数并在代表 "loop" 维度的张量上添加另一个维度来向量化。这将允许 PyTorch 为您处理并行性。
PyTorch 可能有一个设备的概念,你可以在上面放置不同的循环迭代,同样这将需要你为这个循环创建一个函数,并且可能将它继续运行的设备作为输入。
最后,您可以查看 Numba 或 torch.jit 等即时编译来为您执行自动矢量化。
如果 mask
的长度未知,None 将(最有可能)起作用。如果它的长度已知,我认为矢量化虽然很难,但可能是您的最佳选择。
我意识到 for
循环通常在 Python
中很慢。我有一些代码会混淆一些张量:
for batch_index, mask_batch in enumerate(mask):
mask_len = torch.sum(mask_batch).int()
if mask_len == 0:
side_input = torch.zeros((max_inp_len, side_input.shape[1])).to(mask.device)
else:
m_nonzero = mask_batch.nonzero().flatten()
first_nonzero = m_nonzero[0]
last_nonzero = m_nonzero[-1]
if side == 'left':
end_index = first_nonzero - 1
start_index = 0
elif side == 'right':
start_index = last_nonzero + 1
end_index = inputs[batch_index].size(1)
side_input = inputs[batch_index][start_index:end_index]
if end_index - start_index < max_inp_len:
pad_zeros = torch.zeros(
(max_inp_len - side_input.shape[0], side_input.shape[1])).to(mask.device)
if side == 'left':
side_input = torch.cat((pad_zeros, side_input), 0)
elif side == 'right':
side_input = torch.cat((side_input, pad_zeros), 0)
side_inputs.append(side_input)
return torch.stack(side_inputs)
我觉得这个循环真的很慢。有什么方法可以不用循环吗?
您应该创建一个包含循环迭代背后的逻辑的函数,并将其作为每个列的线程启动(请参阅 docs here). You could also use asyncio 并发库,但您可能获得的改进较少。
可以阅读为列表的每个元素生成线程的一个很好的例子here。
Python 在任何给定进程中都没有真正的并行性。您必须生成一个 ProcessPool 并在循环内部创建一个采用 batch_index, mask_batch
的函数,然后将该函数映射到当前 for 循环中的 mask
对象上。问题是,我不知道 PyTorch 是否能很好地处理这个问题。
像这样
def f(batch_index, mask_batch):
mask_len = torch.sum(mask_batch).int()
if mask_len == 0:
side_input = torch.zeros((max_inp_len, side_input.shape[1])).to(mask.device)
else:
m_nonzero = mask_batch.nonzero().flatten()
first_nonzero = m_nonzero[0]
last_nonzero = m_nonzero[-1]
if side == 'left':
end_index = first_nonzero - 1
start_index = 0
elif side == 'right':
start_index = last_nonzero + 1
end_index = inputs[batch_index].size(1)
side_input = inputs[batch_index][start_index:end_index]
if end_index - start_index < max_inp_len:
pad_zeros = torch.zeros((max_inp_len - side_input.shape[0], side_input.shape[1])).to(mask.device)
if side == 'left':
side_input = torch.cat((pad_zeros, side_input), 0)
elif side == 'right':
side_input = torch.cat((side_input, pad_zeros), 0)
return side_input
您可以查看的其他内容是进一步向量化代码。 PyTorch 和 Numpy 中的大多数东西都可以通过使用内置函数并在代表 "loop" 维度的张量上添加另一个维度来向量化。这将允许 PyTorch 为您处理并行性。
PyTorch 可能有一个设备的概念,你可以在上面放置不同的循环迭代,同样这将需要你为这个循环创建一个函数,并且可能将它继续运行的设备作为输入。
最后,您可以查看 Numba 或 torch.jit 等即时编译来为您执行自动矢量化。
如果mask
的长度未知,None 将(最有可能)起作用。如果它的长度已知,我认为矢量化虽然很难,但可能是您的最佳选择。