如何连接numpy数组的动态切片?

How to concatenate dynamic slices of numpy array?

提问人:zendevil 提问时间:8/9/2020 最后编辑:zendevil 更新时间:8/11/2020 访问量:259

问:

我有一个 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]))
python numpy tensorflow 切片

评论

0赞 hammi 8/9/2020
您需要提供更多信息,例如,数组的形状是什么?layer
0赞 zendevil 8/9/2020
(2, 188, 621, 32)
1赞 MoRoBe 8/9/2020
您能解释一下您想要实现的目标吗?我很难弄清楚 np.concatenates 的目的是什么。
0赞 zendevil 8/9/2020
我们想连接两个数组(特征):[1 2 3]、[4 5 6] -> [1 2 3 4 5 6]
0赞 RichieV 8/9/2020
请参阅有关如何使用另一个数组/列表对数组进行切片的问题

答:

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对象?如果是这样,那么您需要将其转换为最后两行代码之前的代码layertf.Tensornp.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)”