卷积层的numpy实现

只用Numpy完成卷积层的前向传播和反向传播,以增强对卷积层的了解。

这里实现的是naive的方式,实际上会使用 im2col 和 gemm 来加速计算。

forward pass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def (x, w, b, conv_param):
N, C, H, W = x.shape
F, C, HH, WW = w.shape
pad, stride = conv_param["pad"], conv_param["stride"]
X = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), "constant")

H_out = 1 + int((H + 2 * pad - HH) / stride)
W_out = 1 + int((W + 2 * pad - WW) / stride)
out = np.zeros((N, F, H_out, W_out))

for n in range(N):
for f in range(F):
for i in range(H_out):
for j in range(W_out):
data = X[n, :, i * stride: i * stride + HH, j * stride: j * stride + WW].reshape(1, -1)
filt = w[f, :, :, :].reshape(-1, 1)
out[n, f, i, j] = data.dot(filt) + b[f]

cache = (x, w, b, conv_param)
return out, cache

backward pass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def conv_backward_naive(dout, cache):
x, w, b, conv_param = cache
N, F, H_out, W_out = dout.shape
N, C, H, W = x.shape
F, C, HH, WW = w.shape
pad, stride = conv_param["pad"], conv_param["stride"]
X = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), "constant")
dw = np.zeros_like(w)
dX = np.zeros_like(X)

for n in range(N):
for f in range(F):
for i in range(H_out):
for j in range(W_out):
dX[n, :, i * stride: i * stride + HH, j * stride: j * stride + WW] += w[f] * dout[n, f, i, j]
dw[f] += X[n, :, i * stride: i * stride + HH, j * stride: j * stride + WW] * dout[n, f, i, j]

db = np.sum(dout, axis=(0, 2, 3))
dx = dX[:, :, pad: -pad, pad: -pad]
return dx, dw, db

Reference:

CNN卷积网络的Python实现(三):卷积网络实现