Python中使用Numpy的卷积层

2024-04-19 09:18:29 发布

您现在位置:Python中文网/ 问答频道 /正文

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

  • N:批大小
  • H:图像高度
  • W:图像宽度
  • C:通道数

卷积滤波器也是形状[F, F, Cin, Cout]的四维数组,其中

  • F:方形过滤器的高度和宽度
  • Cin:输入通道数(Cin = C
  • Cout:输出通道数

假设沿所有轴的步长为1,并且没有填充,输出应该是一个4维的shape [N, H - F + 1, W - F + 1, Cout]数组。在

我的代码如下:

import numpy as np

def conv2d(image, filter):
  # Height and width of output image
  Hout = image.shape[1] - filter.shape[0] + 1
  Wout = image.shape[2] - filter.shape[1] + 1

  output = np.zeros([image.shape[0], Hout, Wout, filter.shape[3]])

  for n in range(output.shape[0]):
    for i in range(output.shape[1]):
      for j in range(output.shape[2]):
        for cout in range(output.shape[3]):
          output[n,i,j,cout] = np.multiply(image[n, i:i+filter.shape[0], j:j+filter.shape[1], :], filter[:,:,:,cout]).sum()

  return output

这很好地工作,但是使用了四个for循环,速度非常慢。有没有更好的方法来实现一个卷积层,它接受4维输入和滤波器,并使用Numpy返回一个4维输出?在


Tags: inimagenumpyforoutputnprange数组
1条回答
网友
1楼 · 发布于 2024-04-19 09:18:29

这是这种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.tensordot(a, b, axes=3)性能比np.einsum("abcijk,ijkd", a, b)好得多,强烈推荐使用。 因此,函数变成:

^{pr2}$

相关问题 更多 >