Python Scipy ndimage.COLVE跳过通道的总和

Python Scipy ndimage.COLVE跳过通道的总和,python,numpy,scipy,conv-neural-network,convolution,Python,Numpy,Scipy,Conv Neural Network,Convolution,我正在尝试使用scipy的ndimage.convolve函数对三维图像(RGB、宽度、高度)执行卷积 请看这里: 很明显,对于任何输入,每个内核/过滤器的输出都应该只有NxN,深度严格为1 这是scipy的一个问题,当您使用ndimage时。使用大小(3,5,5)的输入和大小(3,3,3)的过滤器/内核卷积,此操作的结果会产生(3,5,5)的输出大小,显然不会对不同的通道求和 有没有一种方法可以在不手动的情况下强制求和?我尽量尽可能少地使用Python,因为许多外部库都是用C++编写的,并且

我正在尝试使用
scipy
ndimage.convolve
函数对三维图像(RGB、宽度、高度)执行卷积

请看这里:

很明显,对于任何输入,每个内核/过滤器的输出都应该只有NxN,深度严格为1

这是
scipy
的一个问题,当您使用
ndimage时。使用大小
(3,5,5)
的输入和大小
(3,3,3)
的过滤器/内核卷积
,此操作的结果会产生
(3,5,5)
的输出大小,显然不会对不同的通道求和


有没有一种方法可以在不手动的情况下强制求和?我尽量尽可能少地使用Python,因为许多外部库都是用C++编写的,并且运行速度更快。或者有其他选择吗?

没有scipy不会跳过通道的总和。获得
(3,5,5)
输出的原因是
ndimage.convolve
沿所有轴填充输入数组,然后在“相同”模式下执行卷积(即,输出与输入具有相同的形状,相对于“完全”模式相关性的输出居中)。有关模式的更多详细信息,请参见

对于形状
(3,5,5)
的输入和形状
(3,3,3)
的过滤器
w0
,输入将被填充,从而生成一个
(7,9,9)
数组。请参见下文(为了简单起见,我使用0的常量填充):

在继续之前,请注意,在来自cs231n的图像中,执行的是相关,而不是卷积,因此我们需要翻转
w0
,或者使用相关函数(我将使用前者)

然后,通过沿第一维度(轴-0)滑动来执行卷积,即(翻转的)
w0
卷积为
a_p[0:3]
,然后卷积为
a_p[1:4]
,然后卷积为
a_p[2:5]
,然后卷积为
a_p[3:6]
,最后卷积为
a_p[4:7]
,每个卷积为
(1,7,7)
由于在通道上求和而产生的数组。然后将它们堆叠在一起,形成
(5,7,7)
阵列。为了显示这一点,我使用了
scipy.signal.convolve
,它允许使用
full
模式:

out = scipy.signal.convolve(a, np.flip(w0), mode='full')

array([[[ 2,  0,  0,  2,  0, -2, -2],
        [-1,  1, -5, -1, -4, -4, -2],
        [-1, -3,  2, -3,  1, -4,  0],
        [ 2,  1, -1, -3, -7,  0, -2],
        [-1, -2, -4, -1, -4, -2,  2],
        [-1, -2, -2, -2,  1, -2,  0],
        [ 0, -1,  1, -1, -1,  2,  0]],

       [[ 3,  2,  4,  0,  4,  2,  1],
        [ 2, -1,  1, -1, -1,  0, -2],
        [ 1, -3,  3,  5,  2,  1,  3],
        [ 4,  2,  1,  4,  0, -3, -2],
        [ 1,  1,  1, -1, -1,  3, -1],
        [ 1, -4,  3, -1, -3, -4,  0],
        [ 0,  0,  0, -1,  1,  2,  2]],

       [[ 1,  2,  4,  4,  2, -2, -1],
        [ 1,  2,  1, -3, -4, -4,  1],
        [-2,  2, -3,  3,  1,  2,  4],
        [ 1,  2,  5, -6,  6, -2,  3],
        [ 2, -5,  4,  1,  5,  4,  0],
        [-2,  0,  0,  1, -3, -4,  3],
        [-1,  1, -1, -2,  4,  3,  3]],

       [[ 0,  0,  2,  2,  4,  2,  2],
        [ 0,  0,  3,  3,  3, -2,  1],
        [-1,  0,  0,  4,  0,  4,  3],
        [ 0,  0,  2,  3,  1,  3,  3],
        [ 0,  0,  0,  1,  7,  1,  3],
        [-2,  2,  0,  2, -3,  1,  4],
        [ 0, -1, -1,  0,  2,  4,  1]],

       [[ 0,  0,  0,  0,  0,  0,  0],
        [ 0,  0,  0, -2,  0,  0,  2],
        [ 0,  0, -3, -1,  1,  3,  0],
        [ 0, -1, -1,  1, -1,  2,  0],
        [ 0,  0, -2,  0,  2, -2,  2],
        [ 0, -2,  2, -2, -2,  3,  1],
        [ 0,  0, -2,  0,  1,  1,  0]]])
要进入
ndimage.convolve的“相同”模式,我们需要将
调出

out = out[1:-1, 1:-1, 1:-1]

array([[[-1,  1, -1, -1,  0],
        [-3,  3,  5,  2,  1],
        [ 2,  1,  4,  0, -3],
        [ 1,  1, -1, -1,  3],
        [-4,  3, -1, -3, -4]],

       [[ 2,  1, -3, -4, -4],
        [ 2, -3,  3,  1,  2],
        [ 2,  5, -6,  6, -2],
        [-5,  4,  1,  5,  4],
        [ 0,  0,  1, -3, -4]],

       [[ 0,  3,  3,  3, -2],
        [ 0,  0,  4,  0,  4],
        [ 0,  2,  3,  1,  3],
        [ 0,  0,  1,  7,  1],
        [ 2,  0,  2, -3,  1]]])
这正是运行scipy.ndimage.convolve(a,np.flip(w0),mode='constant',cval=0)时得到的结果。
。最后,为了获得所需的输出,我们需要忽略依赖于沿第一维度填充的元素(即仅保留中间部分),还需要使用步幅
s=2
(即
out[1][::s,::s]
),最后添加偏差
b=1

out[1][::s, ::s] + b

array([[ 3, -2, -3],
       [ 3, -5, -1],
       [ 1,  2, -3]])
将所有内容放在一行:

scipy.ndimage.convolve(a, np.flip(w0), mode='constant', cval=0)[1][::2, ::2] + b

# or using scipy.signal.convolve
# scipy.signal.convolve(a, np.flip(w0), 'full')[2][1:-1,1:-1][::2, ::2] + b
# or
# scipy.signal.convolve(a, np.flip(w0), 'same')[1][::2, ::2] + b

谢谢你的高质量回答!就像另一个相关的问题一样,你会知道为什么在机器学习中使用卷积而不是相关性吗?去年,我意外地创建了一个相关神经网络,它学习得很好,所以我很好奇为什么过滤器的翻转在真正的卷积中如此重要,内核相对于输入翻转,但是在CNN中这种翻转是不必要的,因为内核值是学习的,所以可以跳过这个额外的操作(因此卷积变为互相关)在机器学习中被称为卷积的原因可能是历史原因,可能最初一些库使用的是真正的卷积,但后来删除了保留操作名称的翻转部分…无论如何,这两种操作都可以在CNN中使用。一年后重新讨论这个问题-我通过测试发现,如果使用在前向传递上的相关性最终在后向传递中使用卷积来学习参数,如果在前向传递中使用卷积,则反之亦然。
scipy.ndimage.convolve(a, np.flip(w0), mode='constant', cval=0)[1][::2, ::2] + b

# or using scipy.signal.convolve
# scipy.signal.convolve(a, np.flip(w0), 'full')[2][1:-1,1:-1][::2, ::2] + b
# or
# scipy.signal.convolve(a, np.flip(w0), 'same')[1][::2, ::2] + b