提问人:zendevil 提问时间:8/9/2020 最后编辑:zendevil 更新时间:8/11/2020 访问量:259
如何连接numpy数组的动态切片?
How to concatenate dynamic slices of numpy array?
问:
我有一个 TensorFlow 层,我用它来创建一个名为“cost_volume”的 4d 张量。
我的代码完成了工作。但是,由于嵌套的 for 循环而不是使用 numpy 内置函数,它相当慢。我需要它至少快 300 倍。如何将其转换为使用 numpy 内置函数而不是 for 循环的更有效的代码?
max_disparity = 10
layer = np.random.rand(2, 188, 621, 32)
cost_volume = np.random.rand(layer.shape[0], layer.shape[1], layer.shape[2],\
max_disparity + 1, feature_size * 2)
for i in range(layer.shape[0]):
for y in range(layer.shape[1]):
for x in range(layer.shape[2]):
for d in range(max_disparity + 1):
if i == 0:
cost_volume[i][y][x][d] = np.concatenate((layer[0][y][x], \
layer[1][y][min(x + d, layer.shape[2] - 1)]))
else:
cost_volume[i][y][x][d] = np.concatenate((layer[0][y][max(0, x - d)], \
layer[1][y][x]))
答:
0赞
hammi
8/9/2020
#1
好的,所以尝试矢量化这个代码,到目前为止,我想出了这个
# just renaming some variables
Z = layer.shape[0]
Y = layer.shape[1]
X = layer.shape[2]
D = max_disparity + 1
F = feature_size
cost_volume = np.empty([Z, Y, X, D, F * 2])
实际代码:
cost_volume[0, ..., :F] = layer[0, :, :, None] # i == 0 and 1st half of concatenate
cost_volume[0, ..., F:] = layer[1, :, -1, None, None] # i == 0 and 2nd half of concatenate, default min(x + d, X) == X
cost_volume[1, ..., F:] = layer[1, :, :, None] # i == 1 and 2nd half of concatenate
cost_volume[1, ..., :F] = layer[0, :, 0, None, None] # i == 1 and 1st half of concatenate, default max(x - d, 0) == 0
Xi, Di = np.ogrid[0:X, 0:D] # indices used in 2nd and 3rd axis
m1 = Xi + Di < X # positions where min(x + d, X) == x + d ie where default doesnt apply
m2 = Xi - Di > 0 # positions where max(x - d, 0) == x - d ie where default doesnt apply
cost_volume[0, :, m1, F:] = layer[1, :, (Xi + Di)[m1]] # updating cost values where defaults should not apply
cost_volume[1, :, m2, :F] = layer[0, :, (Xi - Di)[m2]]
我已经尽力使代码不言自明,如果它不起作用,请告诉我
评论
0赞
zendevil
8/10/2020
此代码给出: cost_volume[0, ..., :F] = layer[0] # i == 0 和连接 ValueError 的第一半部分:无法将输入数组从形状 (188,621,32) 广播到形状 (188,621,11,32)
0赞
zendevil
8/10/2020
这给出了: TypeError: 只有整数、切片 ()、省略号 ()、tf.newaxis () 和标量 tf.int32/tf.int64 张量是有效的索引,得到数组([ 0, 1, 2, ..., 619, 620, 620]):
...
None
0赞
hammi
8/10/2020
@zendevil对象?如果是这样,那么您需要将其转换为最后两行代码之前的代码layer
tf.Tensor
np.array
0赞
zendevil
8/10/2020
此代码的运行速度提高了 >300 倍,尽管 ogrid 索引为 0:D+1。你能给出更详细的解释吗?
0赞
hammi
8/10/2020
@zendevil我很乐意解释更多,如果我的答案对您有帮助,请选择旁边的绿色勾号来接受它
0赞
RichieV
8/11/2020
#2
这是我使用 numpy 的高级索引的解决方案。它的优点是直到最后一行才复制数据。
获取数组
max_disparity = 10
feature_size = 2
np.random.seed(123)
layer = np.random.rand(2, 188, 621, 32)
和代码
I, Y, X, D, F = layer.shape[:-1] + (max_disparity + 1, feature_size)
left = ( ### tuple of index-arrrays for left side of concat
np.zeros((I, Y, X, D), dtype=int), # index for axis 0
np.array([[[[y for d in range(D)] for x in range(X)]
for y in range(Y)] for i in range(I)]), # index for axis 1
np.array([[[[x if i==0 else max(0, x-d) for d in range(D)] for x in range(X)]
for y in range(Y)] for i in range(I)]), # index for axis 2
)
right = ( ### tuple of index-arrrays for right side of concat
np.ones((I, Y, X, D), dtype=int), # index for axis 0
np.array([[[[y for d in range(D)] for x in range(X)]
for y in range(Y)] for i in range(I)]), # index for axis 1
np.array([[[[min(x+d, X-1) if i==0 else x for d in range(D)] for x in range(X)]
for y in range(Y)] for i in range(I)]), # index for axis 2
)
### now slice layer with both tuples and concatenate inner-most dim
cost_volume = np.concatenate([layer[left], layer[right]], axis=-1)
在我的笔记本电脑上花了 41.2 秒,配备 2.16 GHz 双核赛扬和 4 GB
评论
0赞
RichieV
8/11/2020
无法与您的代码进行比较,因为它在第一行 concat 上引发“ValueError:无法将输入数组从形状 (64) 广播到形状 (4)”
评论
layer