Python中使用Numpy的卷积层

Python中使用Numpy的卷积层,python,arrays,numpy,conv-neural-network,Python,Arrays,Numpy,Conv Neural Network,我正在尝试使用Numpy在Python中实现一个卷积层。 输入是形状[N,H,W,C]的4维数组,其中: N:批量大小 H:图像高度 W:图像的宽度 C:频道数 卷积滤波器也是一个形状为[F,F,Cin,Cout]的四维数组,其中 F:方形过滤器的高度和宽度 Cin:输入通道的数量Cin=C Cout:输出通道数 假设沿所有轴的步幅为1,并且没有填充,则输出应该是形状[N,H-F+1,W-F+1,Cout]的4维数组 我的代码如下: 将numpy作为np导入 def conv2dimage,过滤

我正在尝试使用Numpy在Python中实现一个卷积层。 输入是形状[N,H,W,C]的4维数组,其中:

N:批量大小 H:图像高度 W:图像的宽度 C:频道数 卷积滤波器也是一个形状为[F,F,Cin,Cout]的四维数组,其中

F:方形过滤器的高度和宽度 Cin:输入通道的数量Cin=C Cout:输出通道数 假设沿所有轴的步幅为1,并且没有填充,则输出应该是形状[N,H-F+1,W-F+1,Cout]的4维数组

我的代码如下:

将numpy作为np导入 def conv2dimage,过滤器: 输出图像的高度和宽度 Hout=image.shape[1]-过滤器.shape[0]+1 Wout=image.shape[2]-过滤器.shape[1]+1 输出=np.zeros[image.shape[0],Hout,Wout,filter.shape[3]] 对于rangeoutput.shape[0]中的n: 对于rangeoutput.shape[1]中的i: 对于rangeoutput.shape[2]中的j: 对于rangeoutput.shape[3]中的cout: 输出[n,i,j,cout]=np.multiplyimage[n,i:i+filter.shape[0],j:j+filter.shape[1],:],filter[:,:,:,cout].sum 返回输出
这工作得很好,但是使用四个for循环,速度非常慢。有没有更好的方法实现卷积层,使用Numpy进行四维输入和过滤,并返回四维输出?

这是一种类似于keras的卷积的简单实现。对于初学者来说,这可能很难理解,因为它使用了大量的广播和跨步技巧

from numpy.lib.stride_tricks import as_strided
def conv2d(a, b):
    a = as_strided(a,(len(a),a.shape[1]-len(b)+1,a.shape[2]-b.shape[1]+1,len(b),b.shape[1],a.shape[3]),a.strides[:3]+a.strides[1:])
    return np.einsum('abcijk,ijkd', a, b[::-1,::-1])
顺便说一句:如果你用非常大的内核进行卷积,请使用基于傅立叶的算法

编辑:[::-1,::-1]应该删除,以防卷积不涉及像tensorflow中那样首先翻转内核

编辑:np.tensordota,b,axes=3比np.einsumabcijk,ijkd,a,b性能好得多,强烈推荐使用。 因此,函数变为:

from numpy.lib.stride_tricks import as_strided

def conv2d(a, b):
  Hout = a.shape[1] - b.shape[0] + 1
  Wout = a.shape[2] - b.shape[1] + 1

  a = as_strided(a, (a.shape[0], Hout, Wout, b.shape[0], b.shape[1], a.shape[3]), a.strides[:3] + a.strides[1:])

  return np.tensordot(a, b, axes=3)

我很难复制这个。你能给我一个样品过滤器吗?由此判断,filter.shape[3],它是四维的吗?filter是四维的。样本过滤器可以是filter=np.random.randint0,2[5,5,3,16]。这将是一个5 X 5的过滤器,在三通道输入图像上运行,并生成一个16通道的输出“图像”。好的,我有时间的时候会看一看。谢谢你的回答。然而,这似乎并没有产生正确的结果。例如,我将它与tensorflow.conv2da,b,strips=[1,1,1,1],padding=VALID进行比较,结果是不同的。输出张量的形状相同,但值不同。知道为什么会这样吗?我发现了问题。这似乎与卷积的定义有关。对于[1,2,3]与[1,2,3]的卷积,在我的理解中,它应该是1*3+2*2+3*1,否则称为关联。但tensorflow似乎将卷积定义为1*1+2*2+3*3。无论如何,要获得tensorflow的结果,只需删除最后一行的[::-1,:::-1]即可。该方法似乎很有趣,因此评估了所有3个变体的性能。结果如下。TF仅使用CPU@Prabindh是的,在类似的算法实现下,通常numpy不应该比同一cpu上的tensorflow慢,并且这个实现基本上等同于tf.nn.conv2d文档中的psudocode:在任何时间生成一个虚拟矩阵,除了这里是一个6-张量,并在einsum中进行正确的乘法。您可以通过删除[::-1,::-1]来解决结果不同的问题。感谢您的贡献@ZisIsNotZis和@Prabindh。建议使用np.tensordota,b,axes=3代替np.einsumabcijk,ijkd,a,b。我注意到前者的工作速度比后者快得多,尤其是在越来越大的数据集上。