【问题标题】:Speeding up double for loop for downsampling a numpy array加速双循环以对 numpy 数组进行下采样
【发布时间】:2015-10-27 09:58:00
【问题描述】:

我正在尝试找到将任意形状的 2d numpy 数组下采样为更小(或可能更大)的方形数组的最有效方法 - 我想取每个子数组的最大值并将其放入新数组中。这是我的代码:

import numpy as np

def downSampleMax(inputArray, numFrames):

    newArray = np.zeros([numFrames, numFrames], dtype = np.uint8)
    filterSize = (int(np.ceil(float(inputArray.shape[0]) / numFrames)), 
                  int(np.ceil(float(inputArray.shape[1]) / numFrames)))
    rowArr = np.linspace(0, inputArray.shape[0] - filterSize[0], numFrames, dtype = np.int)
    colArr = np.linspace(0, inputArray.shape[1] - filterSize[1], numFrames, dtype = np.int)

    for iRow in range(numFrames):
        for iCol in range(numFrames):
            newArray[iRow, iCol] = np.max(inputArray[rowArr[iRow]: rowArr[iRow] + filterSize[0], 
                                                     colArr[iCol]: colArr[iCol] + filterSize[1]])

    return newArray 

关于如何显着加快速度的任何想法?我认为从我读到的内容来看,矢量化或切片可能是前进的方向,但不知道该怎么做。

【问题讨论】:

  • 而不是float(a) / b,最好在脚本顶部添加from __future__ import division,然后简单地执行a/b
  • 很酷,谢谢 Bas - 你知道我是否还需要在 Python 3 中这样做吗?我在这个项目中使用 Python 2,因为我必须与 Theano *** 编辑接口 - 刚刚尝试过,似乎没有! ***
  • from __future__ 在 Python2 中是必需的,在 Python3 中这是默认值,参见 PEP 238。如果您出于某种原因仍在使用 Python2,添加该行将使您以后更容易移植代码。

标签: arrays performance numpy vectorization downsampling


【解决方案1】:

这是一种矢量化方法,它可以按块进行 max 以尽可能多的 NumPythonic 方式查找计算 -

# Get shape of input array
M,N = inArr.shape

# Reshape 2D input array to break it down a 4D array with rows and columns 
# being divided by the number of frames. Then, use `max` along the divided axes.
out = (inArr.reshape(nFrames,M/nFrames,nFrames,N/nFrames)).max(axis=(1,3))

示例运行 -

In [107]: inArr
Out[107]: 
array([[ 37,  47,  35,  96,  84,  55,  36, 218],
       [  4, 199, 104, 246, 136, 123, 215, 237],
       [ 21,  50,  21, 151, 243, 130,  69, 166],
       [242, 233, 161,  57,  20, 122, 189, 120],
       [175,  52, 114, 202,  13, 134,  30,  29],
       [117, 128,  88, 108,  97, 249,  87,  37],
       [246, 237, 230, 166, 157, 215, 254, 219],
       [156,  41,  71,  94, 114, 174, 223,  25]], dtype=uint8)

In [108]: nFrames = 4

In [109]: downSampleMax(inArr, nFrames)
Out[109]: 
array([[199, 246, 136, 237],
       [242, 161, 243, 189],
       [175, 202, 249,  87],
       [246, 230, 215, 254]], dtype=uint8)

In [110]: M,N = inArr.shape

In [111]: (inArr.reshape(nFrames,M/nFrames,nFrames,N/nFrames)).max(axis=(1,3))
Out[111]: 
array([[199, 246, 136, 237],
       [242, 161, 243, 189],
       [175, 202, 249,  87],
       [246, 230, 215, 254]], dtype=uint8)

运行时测试 -

In [112]: inArr = np.random.randint(0,255,(512,512)).astype('uint8')

In [113]: nFrames = 32

In [114]: def vectorized_downSampleMax(inArr, nFrames):
     ...:   M,N = inArr.shape
     ...:   return (inArr.reshape(nFrames,M/nFrames,nFrames,N/nFrames)).max(axis=(1,3))
     ...: 
     ...: 
     ...: def downSampleMax(inArr, nFrames):
     ...: 
     ...:   newArray = np.zeros([nFrames, nFrames], dtype = np.uint8)
     ...:   filterSize = (int(np.ceil(float(inArr.shape[0]) / nFrames)), 
     ...:                 int(np.ceil(float(inArr.shape[1]) / nFrames)))
     ...:   rowArr = np.linspace(0, inArr.shape[0] - filterSize[0], nFrames).astype(int)
     ...:   colArr = np.linspace(0, inArr.shape[1] - filterSize[1], nFrames).astype(int)
     ...: 
     ...:   for iRow in range(nFrames):
     ...:       for iCol in range(nFrames):
     ...:           newArray[iRow, iCol] = np.max(inArr[rowArr[iRow]: rowArr[iRow] + filterSize[0], colArr[iCol]: colArr[iCol] + filterSize[1]])
     ...: 
     ...:   return newArray
     ...: 

In [115]: %timeit downSampleMax(inArr, nFrames)
10 loops, best of 3: 20.1 ms per loop

In [116]: %timeit vectorized_downSampleMax(inArr, nFrames)
1000 loops, best of 3: 909 µs per loop

【讨论】:

  • 我期待着弄清楚这到底是做什么的:) 啊,我现在明白了。 nFrames 不是求平均的大小,而是最终图像的大小。很好!
  • @AndrasDeak 啊,你在关注 numpy 标签!?好吧,这只是一个重塑技巧,类似于stackoverflow.com/questions/26280418/…stackoverflow.com/questions/26871083/…
  • 非常感谢您的链接!是的,我正在学习 python/numpy,我碰巧注意到@Divakar 回答的帖子。学习随之而来;)
  • @AndrasDeak 非常酷!从 MATLAB 过渡到 Numpy 相当容易,所以去吧! :)
  • 我认为这仅在输入数组的每个维度都可以被 nFrames 整除时才有效,但这是一个很大的速度改进,因此我可以在重塑之前进行一些数组填充或裁剪。谢谢@Divakar!
猜你喜欢
  • 2013-12-17
  • 2019-04-17
  • 2021-11-19
  • 2012-06-06
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多