Matlab中的卷积似乎是Numpy中卷积的两倍。
Python代码(我的机器需要19秒):
import numpy as np
from scipy import ndimage
import time
img = np.ones((512,512,512))
kernel = np.ones((5,5,5))/125
start_time = time.time()
ndimage.convolve(img,kernel,mode='constant')
print "Numpy execution took ", (time.time() - start_time), "seconds"
Matlab代码(在我的机器上花费8.7秒):
img = ones(512,512,512);
kernel = ones(5,5,5) / 125;
tic
convn(img, kernel, 'same');
toc
两者给出相同的结果。
有没有办法改善Numpy以匹配或击败Matlab的表现?
有趣的是,这个因素或运行时间的差异在许多输入大小都是一致的。
答案 0 :(得分:8)
你在做什么准确的手术?如果您不需要一般的N-d卷积,ndimage
提供了许多优化。
例如,您当前的操作:
img = np.ones((512,512,512))
kernel = np.ones((5,5,5))/125
result = ndimage.convolve(img, kernel)
相当于:
img = np.ones((512,512,512))
result = ndimage.uniform_filter(img, 5)
然而,执行速度存在很大差异:
In [22]: %timeit ndimage.convolve(img, kernel)
1 loops, best of 3: 25.9 s per loop
In [23]: %timeit ndimage.uniform_filter(img, 5)
1 loops, best of 3: 8.69 s per loop
差异是由uniform_filter
沿每个轴预先形成1-d卷积而不是通用3D卷积引起的。
在内核是对称的情况下,您可以进行这些简化并显着加快速度。
我不确定convn
,但如果您的输入数据符合某些条件,matlab的函数通常会在幕后进行这些优化。 Scipy更常用的是每个函数一个算法,并希望用户知道在哪种情况下选择哪一个。
你提到了“高斯拉普拉斯”滤波器。我总是对这里的术语感到困惑。
我认为你想要的ndimage
函数是scipy.ndimage.gaussian_laplace
或scipy.ndimage.gaussian_filter
order=2
(按高斯的二阶导数过滤)。
无论如何,两者都会将操作简化为每个轴上的1-d卷积,这应该会带来显着的(2-3倍)加速。
答案 1 :(得分:3)
不是anwer;只是评论:
在比较性能之前,您需要确保两个函数返回相同的结果:
如果Matlab的convn返回与Octave的convn相同的结果,那么
convn
与ndimage.convolve
不同:
octave> convn(ones(3,3), ones(2,2))
ans =
1 2 2 1
2 4 4 2
2 4 4 2
1 2 2 1
In [99]: ndimage.convolve(np.ones((3,3)), np.ones((2,2)))
Out[99]:
array([[ 4., 4., 4.],
[ 4., 4., 4.],
[ 4., 4., 4.]])
ndimage.convolve
还有其他模式'reflect','constant','nearest','mirror', 'wrap'
,但这些模式都不符合convn
的默认(“完整”)行为。
对于2D阵列,scipy.signal.convolve2d
比scipy.signal.convolve
快。
对于3D数组,scipy.signal.convolve
似乎与convn(A,B)
具有相同的行为:
octave> x = convn(ones(3,3,3), ones(2,2,2))
x =
ans(:,:,1) =
1 2 2 1
2 4 4 2
2 4 4 2
1 2 2 1
ans(:,:,2) =
2 4 4 2
4 8 8 4
4 8 8 4
2 4 4 2
ans(:,:,3) =
2 4 4 2
4 8 8 4
4 8 8 4
2 4 4 2
ans(:,:,4) =
1 2 2 1
2 4 4 2
2 4 4 2
1 2 2 1
In [109]: signal.convolve(np.ones((3,3,3), dtype='uint8'), np.ones((2,2,2), dtype='uint8'))
Out[109]:
array([[[1, 2, 2, 1],
[2, 4, 4, 2],
[2, 4, 4, 2],
[1, 2, 2, 1]],
[[2, 4, 4, 2],
[4, 8, 8, 4],
[4, 8, 8, 4],
[2, 4, 4, 2]],
[[2, 4, 4, 2],
[4, 8, 8, 4],
[4, 8, 8, 4],
[2, 4, 4, 2]],
[[1, 2, 2, 1],
[2, 4, 4, 2],
[2, 4, 4, 2],
[1, 2, 2, 1]]], dtype=uint8)
请注意,np.ones((n,m,p))
默认情况下会创建一个 float 数组。 Matlab ones(n,m,p)
似乎创建了一个int数组。为了进行比较,你应该尝试将numpy数组的dtype与Matlab矩阵的类型相匹配。