【问题标题】:Vectorized way to add multiple overlapping cubes添加多个重叠立方体的矢量化方法
【发布时间】:2019-02-02 06:36:24
【问题描述】:

我正在使用滑动窗口对大矩形图像进行深度学习。图像具有形状(高度、宽度)。

预测输出是一个形状(高度、宽度、预测概率)的ndarray。我的预测在重叠窗口中输出,我需要将这些窗口加在一起以获得整个输入图像的逐像素预测。窗口在(高度、宽度)上重叠超过 2 个像素。

我以前在 C++ 中做过这样的事情,创建一个大的结果索引,然后将所有 ROI 相加。

#include <opencv2/core/core.hpp>
using namespace std;  

template <int numberOfChannels>
static void AddBlobToBoard(Mat& board, vector<float> blobData,
                                            int blobWidth, int blobHeight,
                                            Rect roi) {
 for (int y = roi.y; y < roi.y + roi.height; y++) {
    auto vecPtr = board.ptr< Vec <float, numberOfChannels> >(y);
    for (int x = roi.x; x < roi.x + roi.width; x++) {
      for (int channel = 0; channel < numberOfChannels; channel++) {
          vecPtr[x][channel] +=
            blobData[(band * blobHeight + y - roi.y) * blobWidth + x - roi.x];}}}

在 Python 中是否有一种矢量化的方式来执行此操作?

【问题讨论】:

  • 投票结束,因为过于广泛。使用 numpy ndarrays 来保存图像:有许多使用 Numpy as_strided 步幅技巧的滑动窗口实现,可以通过搜索找到。 Scikit 有一个提取补丁方法/功能 - 它曾经使用 as_strided - 不知道它是否仍然如此。
  • @Kevin,在审阅者关闭之前,您可能希望在问题的结尾处进行类似于我上面的评论的简介。并尽量避免在问题中使用“最快”或“最佳”之类的词,因为它们只是接近投票的诱饵。您想要一种快速的方法来执行当前需要 for 循环的事情。要求一个“矢量化”解决方案(这个问题你不会得到它,但你也会避免接近投票)。
  • 还要检查this,了解为什么有人会说“建议尽可能避免使用as_strided”。
  • 我知道,@kevinkayaks,提问者也叫凯文。 :P
  • 已编辑以防止审查队列关闭。如果我误解了这个问题,请随时回复。

标签: python numpy opencv


【解决方案1】:

编辑:

@Kevin IMO 如果您无论如何都在训练网络,那么您应该使用全连接层来执行此步骤。那就是说..

如果您想要使用某些东西,我有一个非矢量化的解决方案。任何解决方案都会占用大量内存。在我的笔记本电脑上,它对于 CIFAR 大小的灰色图像 (32x32) 的运行速度有点快。也许关键步骤可以由聪明的人矢量化。

首先使用skimage 将测试数组arr 拆分为窗口win。这是测试数据。

>>> import numpy as np
>>> from skimage.util.shape import view_as_windows as viewW
>>> arr = np.arange(20).reshape(5,4)
>>> win = viewW(arr, (3,3))
>>> arr # test data 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19]])
>>> win[0,0]==arr[:3,:3] # it works. 
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]])

现在重新组合,生成一个形状为(5,4,6) 的输出数组out6win 中的窗口数,(5,4)arr.shape。我们将在沿-1 轴的每个切片中通过一个窗口填充此数组。

# the array to be filled
out = np.zeros((5,4,6)) # shape of original arr stacked to the number of windows 

# now make the set of indices of the window corners in arr 
inds = np.indices((3,2)).T.reshape(3*2,2)

# and generate a list of slices. each selects the position of one window in out 
slices = [np.s_[i[0]:i[0]+3:1,i[1]:i[1]+3:1,j] for i,j in zip(inds,range(6))] 

# this will be the slow part. You have to loop through the slices. 
# does anyone know a vectorized way to do this? 
for (ii,jj),slc in zip(inds,slices):
    out[slices] = win[ii,jj,:,:]

现在out 数组包含了所有在其正确位置但跨-1 轴分隔成窗格的窗口。要提取原始数组,您可以平均该轴上不包含零的所有元素。

>>> out = np.true_divide(out.sum(-1),(out!=0).sum(-1))
>>> # this can't handle scenario where all elements in an out[i,i,:] are 0
>>> # so set nan to zero 

>>> out = np.nan_to_num(out)
>>> out 
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.],
       [ 8.,  9., 10., 11.],
       [12., 13., 14., 15.],
       [16., 17., 18., 19.]])

你能想出一种方法来以矢量化的方式对切片数组进行操作吗?

大家一起:

def from_windows(win):
    """takes in an arrays of windows win and returns the original array from which they come"""
    a0,b0,w,w = win.shape # shape of window
    a,b = a0+w-1,b0+w-1 # a,b are shape of original image 
    n = a*b # number of windows 
    out = np.zeros((a,b,n)) # empty output to be summed over last axis 
    inds = np.indices((a0,b0)).T.reshape(a0*b0,2) # indices of window corners into out 
    slices = [np.s_[i[0]:i[0]+3:1,i[1]:i[1]+3:1,j] for i,j in zip(inds,range(n))] # make em slices 
    for (ii,jj),slc in zip(inds,slices): # do the replacement into out 
        out[slc] = win[ii,jj,:,:]
    out = np.true_divide(out.sum(-1),(out!=0).sum(-1)) # average over all nonzeros 
    out = np.nan_to_num(out) # replace any nans remnant from np.alltrue(out[i,i,:]==0) scenario
    return out # hope you've got ram 

和测试:

>>> arr = np.arange(32**2).reshape(32,32)
>>> win = viewW(arr, (3,3))
>>> np.alltrue(arr==from_windows(win))
True
>>> %timeit from_windows(win)
6.3 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

实际上,这对你训练来说不够快

【讨论】:

    猜你喜欢
    • 2016-06-21
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多