import numpy as np
import scipy.signal as sg
M, N, P = 4, 10, 20
A = np.random.randn(M, N)
B = np.random.randn(M, P)
C = sg.convolve(A, B, 'full')[(2*M-1)/2]
import numpy as np
import scipy.signal as sg
M, N, P = 4, 10, 20
A = np.random.randn(M, N) # (4, 10)
B = np.random.randn(M, P) # (4, 20)
C = np.vstack([sg.convolve(a, b, 'full') for a, b in zip(A, B)])
>>> C.shape
(4, 29)
import torch
import torch.nn.functional as F
@torch.no_grad()
def torch_conv(A, B):
M, N, P = A.shape[0], A.shape[1], B.shape[1]
C = F.conv1d(A, B[:, None, :], bias=None, stride=1, groups=M, padding=N+(P-1)//2)
return C.numpy()
# Convert A and B to torch tensors + flip B
X = torch.from_numpy(A) # (4, 10)
W = torch.from_numpy(np.fliplr(B).copy()) # (4, 20)
# Do grouped conv and get np array
Y = torch_conv(X, W)
>>> Y.shape
(4, 29)
>>> np.allclose(C, Y)
True
5条答案
按热度按时间x7yiwoj41#
您可以使用
np.apply_along_axis
沿着所需的轴应用np.convolve
。下面是一个将矩形波串滤镜应用于二维数组的示例:这是一种简单的方法,可以推广许多没有
axis
参数的函数。kg7wmglp2#
使用ndimage.convolve1d,您可以指定轴...
3yhwsihp3#
np.apply_along_axis
实际上对你没有什么帮助,因为你试图迭代 two 数组,实际上,你必须使用一个循环,如here所述。现在,如果数组很小,循环就可以了,但如果N和P很大,那么您可能需要使用FFT来进行卷积。
但是,您需要首先对数组进行适当的零填充,以便“完整”卷积具有预期的形状:
voj3qocg4#
对于2D数组,函数scipy.signal.convolve2d更快,scipy.signal.fftconvolve甚至更快(取决于数组的维数):
这里同样代码用N = 100000
答案都是一样的,只是由于使用了不同的计算方法而略有不同(例如,fft与直接乘法,但我不知道convolve2d使用的是什么):
ltqd579y5#
迟来的答案,但值得张贴参考。引用OP的评论:
A中的每一行都被B中对应的行过滤。我可以这样实现它,只是觉得可能有更快的方法。
A的大小大约是10千兆字节,我使用重叠相加。
天真/直接的方法
A中的每一行与B中的每一相应行卷积,实质上卷积M个1D阵列/向量。
无循环+ CUDA支持的版本
可以使用PyTorch的F.conv1d来复制此操作。我们必须将
A
想象为一个长度为10* 的 *4通道一维信号。我们希望将A
中的每个通道与长度为20的特定内核进行卷积。这是一种称为深度卷积的特殊情况,通常用于深度学习。请注意,torch的卷积是以互相关的形式实现的,因此我们需要提前翻转B以进行实际卷积。
使用焊炬深度回旋的优点:
A
和B
是非常大的矩阵,那么CUDA/GPU确实可以加快速度。(从OP的评论来看,情况似乎是这样的:A的大小为10 GB。)缺点: