#####################################################################################################
# conv function code source: #
# https://towardsdatascience.com/a-guide-to-convolutional-neural-networks-from-scratch-f1e3bfc3e2de #
#####################################################################################################
def conv(x, filt, stride, pad):
"""
- H: height (number of rows)
- W: width (number of columns)
- stride: stride value to apply to each image when convolving
- pad: number of rows and columns to zero-pad around image
"""
H, W = x.shape
HH, WW = filt.shape
# get output dimensions
H_out = 1 + (H + 2 * pad - HH) // stride
W_out = 1 + (W + 2 * pad - WW) // stride
out = np.zeros((H_out, W_out))
pad_widths = ((pad,), (pad,))
xpad = np.pad(x, pad_widths, 'constant')
Hpad, Wpad = xpad.shape
# perform convolution
for i in range(0, Hpad-(HH-1), stride):
for j in range(0, Wpad-(WW-1), stride):
prod = np.sum(np.multiply(filt, xpad[i:i+HH, j:j+WW]))
out[int(i/stride), int(j/stride)] = prod
return out