我正在尝试使用 Numpy 在 Python 中实现卷积层。输入是一个形状为 的 4 维数组[N, H, W, C]
,其中:
N
: 批量大小H
: 图像高度W
: 图像宽度C
: 通道数卷积滤波器也是一个形状为 的 4 维数组[F, F, Cin, Cout]
,其中
F
:方形过滤器的高度和宽度Cin
: 输入通道数 ( Cin = C
)Cout
: 输出通道数假设沿所有轴的步幅为 1,并且没有填充,则输出应为 shape 的 4 维数组[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 循环并且非常慢。有没有更好的方法来使用 Numpy 实现一个接受 4 维输入和过滤器,并返回一个 4 维输出的卷积层?
这是这种类似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)
,强烈推荐。于是,函数变为:
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)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句