pytorch - 如何在pytorch中处理这种情况?
问题描述
我有以下两种相关的张量data
和mask
. is的大小和data
is1x2x24x2
的大小。在中,意味着对应的数据是有效的,应该是梯度反向传播的。mask
1x2x24
mask
True
data
data:
tensor([[[[ 1.0663e+03, 5.5993e+02],
[ 1.0612e+03, 7.2023e+02],
[ 1.0831e+03, 7.2179e+02],
[ 1.0945e+03, 5.6083e+02],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10]],
[[ 6.9314e+02, 1.9700e+02],
[ 6.3300e+02, 2.6924e+02],
[ 6.3300e+02, 3.4165e+02],
[ 7.7515e+02, 4.6000e+02],
[ 8.2805e+02, 4.6000e+02],
[ 9.0900e+02, 3.6276e+02],
[ 9.0900e+02, 2.9035e+02],
[ 7.9688e+02, 1.9700e+02],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10],
[-1.0000e+10, 1.0000e+10]]]])
torch.Size([1, 2, 24, 2])
mask:
tensor([[[ True, True, True, True, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False, False,
False, False, False, False],
[ True, True, True, True, True, True, True, True, False, False,
False, False, False, False, False, False, False, False, False, False,
False, False, False, False]]])
torch.Size([1, 2, 24])
基于data
and mask
,我需要进一步处理。例如,我需要做这种for
循环:
B, N = data.shape[0:2]
result = torch.zeros((B, N), dtype=torch.float32)
for b in range(B):
for n in range(N):
tmp_data = data[b,n] # 24 x 2
tmp_mask = mask[b,n] # 24
selected = tmp_data[tmp_mask]
selected = torch.cat([selected, selected[0][None]], dim=0)
total = selected[0:-1, 0] * selected[1:, 1] - selected[0:-1, 1] * selected[1:, 0] # do cross product
total = torch.sum(total, dim=0)
result[b,n] = torch.abs(total) / 2
然后,result
张量被送入后续处理,例如损失计算。我的问题是,有没有什么加速方法可以摆脱for-loop
?主要难点在于对于每个b
and , inn
的个数不相等,有时是 3,有时是 5,但是每个样本中的最大个数是 8。True
mask
True
所以,在 中for-loop
,需要处理每个一个一个的案例。有什么矢量化的方法吗?
另一个困难在于梯度反向传播,我需要进一步调查以检查该例程是否可以正确地用于梯度反向传播。
我期待有一种优雅的方式来处理 pytorch 中的这种张量处理。提前致谢!
更新:
和由上一个例程排序data
,mask
例如:
sorted_inds = ... # B x N x 24
data = torch.gather(data_original, dim=2, index=sorted_indices.unsqueeze(-1).repeat(1,1,1,2)) # B x N x 24 x 2
mask= torch.gather(mask_original, dim=2, index=sorted_indices) # B x N x 24
# then the data and mask are obtained
# continue processing in this post
...
解决方案
您正在寻找使用张量操作对两个 for 循环进行矢量化。一般来说,这可以通过忽略前两个轴并在后两个轴上执行操作来实现。但是,在这种特殊情况下,我认为这是无法实现的。
原因在于(通过索引)发生的data
掩蔽。此操作只会返回一个展平的张量:。mask
data[mask]
tensor([[1066.3000, 559.9300],
[1061.2000, 720.2300],
[1083.1000, 721.7900],
[1094.5000, 560.8300],
[ 693.1400, 197.0000],
[ 633.0000, 269.2400],
[ 633.0000, 341.6500],
[ 775.1500, 460.0000],
[ 828.0500, 460.0000],
[ 909.0000, 362.7600],
[ 909.0000, 290.3500],
[ 796.8800, 197.0000]])
如您所见,保留了正确的值,但未保留所需的形状。这就是问题所在。这就是我们希望拥有的(为了继续使用矢量化形式)。这是不可能的,因为一个维度上的所有张量都必须具有相同的长度:该维度上的大小。
tensor([[[1066.3000, 559.9300],
[1061.2000, 720.2300],
[1083.1000, 721.7900],
[1094.5000, 560.8300]],
[[ 693.1400, 197.0000],
[ 633.0000, 269.2400],
[ 633.0000, 341.6500],
[ 775.1500, 460.0000],
[ 828.0500, 460.0000],
[ 909.0000, 362.7600],
[ 909.0000, 290.3500],
[ 796.8800, 197.0000]])
关于叉积。PyTorch 为此提供了一个函数:torch.cross
,但它只能用于 3D 张量。在此之上,无法使用它。我认为你的实现很好。
一些建议,这些不是开创性的改进,但可以提供帮助:
索引有一个技巧可以避免在单元素张量上做
x.unsqueeze(0)
(或像你做的那样):通过 slicing 。x[None]
x[:1]
参数
dim
通常默认为0
. 因为.sum()
您不需要它,因为您正在寻找总和而不是每个轴的总和。您可以展平前两个轴,执行一个循环并在最后重塑。
在这里,我冒昧地调整了您的代码:
B, N, *_ = data.shape
data_ = data.reshape(B*N, -1, 2)
mask_ = mask.reshape(B*N, -1)
result = []
for i in range(B*N):
selected = data_[i][mask_[i]]
looped = torch.cat([selected, selected[:1]])
cross = looped[:-1, 0]*looped[1:, 1] - looped[:-1, 1]*looped[1:, 0]
result.append(cross.sum().abs() / 2)
torch.tensor(result).reshape(B, N)
推荐阅读
- java - 使用 GLSL、lwjgl 将原始数据写入纹理
- r - 是否可以根据简单的数据框信息在 RStudio 中创建气泡图?
- html - 使用对象拟合:cover 和 srcset
- php - nodejs续集中的月份(createdAt)
- linux - Azure DevOps 部署管道 - 如何找到用于 Linux 映像名称的价值?
- python - 如何递归检索json数组中的嵌套值?
- sql - 从 SQL Server 中的多个表中按顺序获取行
- java - Java HashMap 添加新条目的方法(如果还没有的话)
- kotlin - Kotlin 类型差异
- javascript - 加入两个正则表达式,用于嵌套引号支持