Skip to content

Instantly share code, notes, and snippets.

@raytroop
Last active September 14, 2018 14:14
Show Gist options
  • Save raytroop/8ac364bf901f3bf3b2975b5381eb95ba to your computer and use it in GitHub Desktop.
Save raytroop/8ac364bf901f3bf3b2975b5381eb95ba to your computer and use it in GitHub Desktop.
conv2d implementation of cs231n spring1718_assignment2_v2
def conv_forward_naive(x, w, b, conv_param):
"""
A naive implementation of the forward pass for a convolutional layer.
The input consists of N data points, each with C channels, height H and
width W. We convolve each input with F different filters, where each filter
spans all C channels and has height HH and width WW.
Input:
- x: Input data of shape (N, C, H, W)
- w: Filter weights of shape (F, C, HH, WW)
- b: Biases, of shape (F,)
- conv_param: A dictionary with the following keys:
- 'stride': The number of pixels between adjacent receptive fields in the
horizontal and vertical directions.
- 'pad': The number of pixels that will be used to zero-pad the input.
During padding, 'pad' zeros should be placed symmetrically (i.e equally on both sides)
along the height and width axes of the input. Be careful not to modfiy the original
input x directly.
Returns a tuple of:
- out: Output data, of shape (N, F, H', W') where H' and W' are given by
H' = 1 + (H + 2 * pad - HH) / stride
W' = 1 + (W + 2 * pad - WW) / stride
- cache: (x, w, b, conv_param)
"""
out = None
###########################################################################
# TODO: Implement the convolutional forward pass. #
# Hint: you can use the function np.pad for padding. #
###########################################################################
N, C, H, W = x.shape
F, C, HH, WW = w.shape
stride = conv_param['stride']
pad = conv_param['pad']
Ho = 1 + (H + 2 * pad - HH) // stride
Wo = 1 + (W + 2 * pad - WW) // stride
x_padding = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant')
out = np.empty(shape=(N, F, Ho, Wo))
for n in range(N):
for f in range(F):
x_nf = x_padding[n] # (C, H, W))
w_nf = w[f] # (C, HH, WW)
for i in range(Ho):
for j in range(Wo):
x_nf_ij = x_nf[:, i*stride:i*stride+HH, j*stride:j*stride+WW]
o = np.sum(x_nf_ij * w_nf)
out[n, f, i, j] = o
out += b.reshape(1, F, 1, 1)
###########################################################################
# END OF YOUR CODE #
###########################################################################
cache = (x, w, b, conv_param)
return out, cache
def conv_backward_naive(dout, cache):
"""
A naive implementation of the backward pass for a convolutional layer.
Inputs:
- dout: Upstream derivatives.
- cache: A tuple of (x, w, b, conv_param) as in conv_forward_naive
Returns a tuple of:
- dx: Gradient with respect to x
- dw: Gradient with respect to w
- db: Gradient with respect to b
"""
dx, dw, db = None, None, None
###########################################################################
# TODO: Implement the convolutional backward pass. #
###########################################################################
x, w, b, conv_param = cache
N, C, H, W = x.shape
F, C, HH, WW = w.shape
stride = conv_param['stride']
pad = conv_param['pad']
Ho = 1 + (H + 2 * pad - HH) // stride
Wo = 1 + (W + 2 * pad - WW) // stride
x_padding = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant')
db = np.sum(dout, axis=(0, 2, 3))
dx_padding = np.zeros_like(x_padding)
dw = np.zeros_like(w)
"""
- x: Input data of shape (N, C, H, W)
- w: Filter weights of shape (F, C, HH, WW)
- b: Biases, of shape (F,)
- out: Output data, of shape (N, F, H', W') where H' and W' are given by
H' = 1 + (H + 2 * pad - HH) / stride
W' = 1 + (W + 2 * pad - WW) / stride
""" # pylint: disable=W0105
for n in range(N):
for f in range(F):
x_nf = x_padding[n] # (C, H, W))
dx_nf = dx_padding[n]
w_nf = w[f] # (C, HH, WW)
dw_nf = dw[f]
for i in range(Ho):
for j in range(Wo):
x_nf_ij = x_nf[:, i*stride:i*stride+HH, j*stride:j*stride+WW]
dx_nf_ij = dx_nf[:, i*stride:i*stride+HH, j*stride:j*stride+WW]
# o = np.sum(x_nf_ij * w_nf)
# out[n, f, i, j] = o
dw_nf += x_nf_ij * dout[n, f, i, j]
dx_nf_ij += w_nf * dout[n, f, i, j]
dx = dx_padding[:, :, pad:-pad, pad:-pad]
###########################################################################
# END OF YOUR CODE #
###########################################################################
return dx, dw, db
@raytroop
Copy link
Author

Testing conv_forward_naive
difference: 2.2121476417505994e-08

Testing conv_backward_naive function
dx error: 1.159803161159293e-08
dw error: 2.2471264748452487e-10
db error: 3.37264006649648e-11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment