Optimization 矢量化索引识别,加快GPU处理速度
我的输入是一个值列表,Optimization 矢量化索引识别,加快GPU处理速度,optimization,pytorch,gpu,Optimization,Pytorch,Gpu,我的输入是一个值列表,data\u idx。在本例中,值的范围为[0,5] data_idx = [2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0] 我想要的输出,filled\u matrix是一个形状为max(value)bylen(data\u idx)的张量,其中张量的每一行,r包含所有索引,其中data\u idx==r如果匹配的索引数小于len(data\u idx) 例如,在第一行中,r=0,data\u idx==0位于索引[3,11,1
data\u idx
。在本例中,值的范围为[0,5]
data_idx = [2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0]
我想要的输出,filled\u matrix
是一个形状为max(value)
bylen(data\u idx)
的张量,其中张量的每一行,r
包含所有索引,其中data\u idx==r
如果匹配的索引数小于len(data\u idx)
例如,在第一行中,r=0
,data\u idx==0
位于索引[3,11,14]
。完整输出如下所示:
filled_matrix = tensor([[ 3, 11, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 5, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 8, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 4, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 1, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]],
dtype=torch.int8)
我一直在为实现我的目标的循环代码工作
import torch
max_idx = 6
data_idx = torch.tensor([2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0]).cuda()
max_number_data_idx = data_idx.shape[0]
filled_matrix = torch.zeros([max_idx, max_number_data_idx], dtype=torch.int8, device='cuda')
filled_matrix.fill_(-1)
for i in range(max_idx):
same_idx = (data_idx == i).nonzero().flatten()
filled_matrix[i][:same_idx.shape[0]] = same_idx
现在,我想加速这个代码。具体来说,我希望它在GPU上更快。在实际场景中,输入,data\u idx
,可以是一个包含数百万个值的列表。在这种情况下,例如1 M不同的值,GPU将被调用1 M的时间,这使得它非常慢。我的代码是顺序代码,GPU讨厌顺序代码
是否有一个函数可以更有效地产生相同的结果?或者是一种将这个for循环矢量化的方法?免责声明:我还没有分析过这段代码,看看它在GPU上是否真的更快。
一种矢量化解决方案是使用张量视图来广播比较。张量视图不使用额外的内存。您可以在中看到更多详细信息
首先,制作一个矩阵,其中包含要对每行进行比较的值。在这种情况下,它只是行索引
comparison = torch.tensor(range(max_idx))
现在,我们将使用并查看数据\u idx
和比较
,它们的形状与填充矩阵
相同
comparison_view = comparison.unsqueeze(1).expand(max_idx, max_number_data_idx)
print(comparison_view)
# Each row is the index you want to compare to
# tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
data_idx_view = data_idx.expand(max_idx, max_number_data_idx)
print(data_idx_view)
# Each row is a copy of data_idx
# tensor([[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0]])
我们可以比较它们的相等性并使用它们来找到索引
mask = comparison_view == data_idx_view
mask_indices = mask.nonzero()
print(mask_indices)
# tensor([[ 0, 3],
[ 0, 11],
[ 0, 14],
[ 1, 5],
[ 1, 10],
[ 2, 0],
[ 2, 9],
[ 3, 8],
[ 3, 12],
[ 3, 13],
[ 4, 4],
[ 4, 6],
[ 5, 1],
[ 5, 2],
[ 5, 7]])
现在,您只需要将这些结果转换为您想要的输出格式
filled_matrix = torch.zeros([max_idx, max_number_data_idx], dtype=torch.int8)
filled_matrix.fill_(-1)
col_indices = [0, 1, 2, 0, 1, 0, 1, 0, 1, 2, 0, 1, 0, 1, 2]
filled_matrix[mask_indices[:, 0], col_indices] = mask_indices[:, 1].type(torch.int8)
我考虑了几个选项来生成col\u索引
列表,但是如果没有for循环,我就什么都想不出来
col_indices = torch.zeros(mask_indices.shape[0])
for i in range(1, mask_indices.shape[0]):
if mask_indices[i,0] == mask_indices[i-1,0]:
col_indices[i] = col_indices[i-1]+1
您需要进行一些评测,以查看哪些代码实际上更快。免责声明:我还没有对这些代码进行评测,以查看它在GPU上是否确实更快。
一种矢量化解决方案是使用张量视图来广播比较。张量视图不使用额外的内存。您可以在中看到更多详细信息
首先,制作一个矩阵,其中包含要对每行进行比较的值。在这种情况下,它只是行索引
comparison = torch.tensor(range(max_idx))
现在,我们将使用并查看数据\u idx
和比较
,它们的形状与填充矩阵
相同
comparison_view = comparison.unsqueeze(1).expand(max_idx, max_number_data_idx)
print(comparison_view)
# Each row is the index you want to compare to
# tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
data_idx_view = data_idx.expand(max_idx, max_number_data_idx)
print(data_idx_view)
# Each row is a copy of data_idx
# tensor([[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0],
[2, 5, 5, 0, 4, 1, 4, 5, 3, 2, 1, 0, 3, 3, 0]])
我们可以比较它们的相等性并使用它们来找到索引
mask = comparison_view == data_idx_view
mask_indices = mask.nonzero()
print(mask_indices)
# tensor([[ 0, 3],
[ 0, 11],
[ 0, 14],
[ 1, 5],
[ 1, 10],
[ 2, 0],
[ 2, 9],
[ 3, 8],
[ 3, 12],
[ 3, 13],
[ 4, 4],
[ 4, 6],
[ 5, 1],
[ 5, 2],
[ 5, 7]])
现在,您只需要将这些结果转换为您想要的输出格式
filled_matrix = torch.zeros([max_idx, max_number_data_idx], dtype=torch.int8)
filled_matrix.fill_(-1)
col_indices = [0, 1, 2, 0, 1, 0, 1, 0, 1, 2, 0, 1, 0, 1, 2]
filled_matrix[mask_indices[:, 0], col_indices] = mask_indices[:, 1].type(torch.int8)
我考虑了几个选项来生成col\u索引
列表,但是如果没有for循环,我就什么都想不出来
col_indices = torch.zeros(mask_indices.shape[0])
for i in range(1, mask_indices.shape[0]):
if mask_indices[i,0] == mask_indices[i-1,0]:
col_indices[i] = col_indices[i-1]+1
您需要进行一些评测,以查看哪些代码实际上更快。您能再解释一下您的目标是什么,哪些不起作用吗?例如,您想要的输出是什么?你得到了什么?谢谢你的回答,我的输出是“填充矩阵”。我想找到一种方法在GPU上优化这段代码,并获得相同的输出。所以我想澄清一下,这段代码在GPU上做了你想要的事情,现在你想把它移到cpu上?它在这两个方面都起作用。我想优化它只为gpu。下面的代码只是一个例子。在实际场景中,输入data_idx可以是一个包含数百万个值的列表。在这种情况下,例如1 M不同的值,gpu将被调用1 M的时间,这使得它非常慢。我的代码是顺序代码,gpu讨厌顺序代码。因此,对我来说,第一种选择是要么设法避免使用循环(可能有一个隐藏的pytorch函数,我不知道),要么设法并行化循环。再次感谢你基于你的评论,我试着把你的问题写得更清楚一点。希望这能帮助你找到你想要的答案。你能再解释一下你的目标是什么,什么不起作用吗?例如,您想要的输出是什么?你得到了什么?谢谢你的回答,我的输出是“填充矩阵”。我想找到一种方法在GPU上优化这段代码,并获得相同的输出。所以我想澄清一下,这段代码在GPU上做了你想要的事情,现在你想把它移到cpu上?它在这两个方面都起作用。我想优化它只为gpu。下面的代码只是一个例子。在实际场景中,输入data_idx可以是一个包含数百万个值的列表。在这种情况下,例如1 M不同的值,gpu将被调用1 M的时间,这使得它非常慢。我的代码是顺序代码,gpu讨厌顺序代码。因此,对我来说,第一种选择是要么设法避免使用循环(可能有一个隐藏的pytorch函数,我不知道),要么设法并行化循环。再次感谢你基于你的评论,我试着把你的问题写得更清楚一点。希望这能帮助你得到你想要的答案。很抱歉回答太晚了。非常感谢您的帮助,它工作得很好。我在我的真实代码上试用过,速度快了3-4倍。为了生成col_索引,我使用了其他方法,如下所述:。再次感谢你,这真的帮了我很大的忙!对不起,我迟了答复。非常感谢您的帮助,它工作得很好。我在我的真实代码上试用过,速度快了3-4倍。为了生成col_索引,我使用了其他方法,如下所述:。再次感谢你,这真的帮了我很大的忙!