これは、エレガントなものよりも迅速で汚れた最適化のほうがはるかに優れています。議論のために、ウィンドウの9つの要素をfoo
関数として合計します。
import numpy as np
from scipy import ndimage
# take the sum of a 3x3 window of a matrix
def foo_lin_mat(mat):
return mat.sum(axis=(-2, -1)) # sum over the last two axes
# sum up the individual matrices
def foo_lin_nine(m1, m2, m3, m4, m5, m6, m7, m8, m9):
return m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 + m9
# compute foo on an input matrix by shifting the mask around
def nestfor(input, foo):
depth, n, m = input.shape
output = np.zeros((depth, n - 2, m - 2))
mask_hor = np.arange(-1, 2)
mask_ver = mask_hor[:, None]
for i in range(1, n - 1):
for j in range(1, m - 1):
output[:, i - 1, j - 1] = foo(input[:, i + mask_ver, j + mask_hor])
return output
# compute foo on an input matrix by breaking the input matrix into 9 submatrices
def flatargs(input, foo):
depth, n, m = input.shape
return foo(input[:, :n-2, :m-2],
input[:, 1:n-1, :m-2],
input[:, 2:, :m-2],
input[:, :n-2, 1:m-1],
input[:, 1:n-1, 1:m-1],
input[:, 2:, 1:m-1],
input[:, :n-2, 2:],
input[:, 1:n-1, 2:],
input[:, 2:, 2:],)
# compute the sum of a window using ndimage.convolve
def convolve(input, mask):
mask = np.ones((1, 3, 3))
out = ndimage.convolve(input, mask)
# cut off the outer edges
return out[1:-1, 1:-1]
私たちは3つの機能を持っています。マトリックスを取り、個々の3x3ウィンドウを集計します。私は彼らが最後に同じ行列を吐き出すことを確認しました。ベンチマークに関しては、
In [62]: %timeit nestfor(input, foo_lin_mat)
1000 loops, best of 3: 261 µs per loop
In [63]: %timeit flatargs(input, foo_lin_nine)
10000 loops, best of 3: 35.8 µs per loop
In [66]: mask = np.ones((1,3,3))
In [69]: %timeit convolve(input, mask)
The slowest run took 6.12 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 42.2 µs per loop
e.e.e. flatargs
バージョンは、元のネストされたforループバージョンよりも約7倍高速です。
foo
関数が入力ウィンドウの線形関数である場合は、ここでconvolve
関数のように、ndimage.convolve
関数を使用してウィンドウ処理を行うこともできます。最終的なコードを読むのが少し楽になるかもしれませんが、マスクに使用する配列に注意する必要があります。
最後の2つの軸に沿ってスライドウィンドウを表示したいように見えます。だから、skimageを使うことができます: 'skimage.util.shape import view_as_windows、 out = view_as_windows(入力、(1,3,3))'。次に、 'out'の最後の2つの軸に沿って' foo'を使います。 – Divakar
返信いただきありがとうございます!はい、私は完全にその用語が存在することを忘れていた(スライディングウィンドウ)。これは私の問題の半分を解決します。ありがとうございました! –