Skip to content

Commit 4676c43

Browse files
committed
implement cnn in numpy
1 parent ed8a4ec commit 4676c43

File tree

3 files changed

+592
-98
lines changed

3 files changed

+592
-98
lines changed

assignment2/ConvolutionalNetworks.ipynb

Lines changed: 502 additions & 91 deletions
Large diffs are not rendered by default.

assignment2/cs231n/classifiers/cnn.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,21 @@ def __init__(self, input_dim=(3, 32, 32), num_filters=32, filter_size=7,
4848
# hidden affine layer, and keys 'W3' and 'b3' for the weights and biases #
4949
# of the output affine layer. #
5050
############################################################################
51-
pass
51+
C, H, W = input_dim
52+
53+
self.params['W1'] = weight_scale * np.random.randn(num_filters, C, filter_size, filter_size)
54+
self.params['b1'] = np.zeros(num_filters)
55+
56+
# max polling
57+
H2 = H // 2
58+
W2 = W // 2
59+
60+
self.params['W2'] = weight_scale * np.random.randn(num_filters * H2 * W2, hidden_dim)
61+
self.params['b2'] = np.zeros(hidden_dim)
62+
63+
self.params['W3'] = weight_scale * np.random.randn(hidden_dim, num_classes)
64+
self.params['b3'] = np.zeros(num_classes)
65+
5266
############################################################################
5367
# END OF YOUR CODE #
5468
############################################################################
@@ -80,7 +94,19 @@ def loss(self, X, y=None):
8094
# computing the class scores for X and storing them in the scores #
8195
# variable. #
8296
############################################################################
83-
pass
97+
98+
# conv - relu ->
99+
out_1, cache_1 = conv_forward_fast(X, W1, b1, conv_param)
100+
101+
# 2x2 max pool ->
102+
out_2, cache_2 = max_pool_forward_fast(out_1, pool_param)
103+
104+
# affine - relu ->
105+
out_3, cache_3 = affine_relu_forward(out_2, W2, b2)
106+
107+
# affine - softmax
108+
scores, cache_4 = affine_forward(out_3, W3, b3)
109+
84110
############################################################################
85111
# END OF YOUR CODE #
86112
############################################################################
@@ -95,7 +121,20 @@ def loss(self, X, y=None):
95121
# data loss using softmax, and make sure that grads[k] holds the gradients #
96122
# for self.params[k]. Don't forget to add L2 regularization! #
97123
############################################################################
98-
pass
124+
loss, dx = softmax_loss(scores, y)
125+
loss += self.reg * 0.5 * (np.sum(W1 * W1) + np.sum(W2 * W2) + np.sum(W3 * W3))
126+
127+
dX3, dW3, db3 = affine_backward(dx, cache_4)
128+
dX2, dW2, db2 = affine_relu_backward(dX3, cache_3)
129+
dX1 = max_pool_backward_fast(dX2, cache_2)
130+
dX0, dW1, db1 = conv_backward_fast(dX1, cache_1)
131+
132+
grads['W3'] = dW3 + self.reg * self.params['W3']
133+
grads['b3'] = db3
134+
grads['W2'] = dW2 + self.reg * self.params['W2']
135+
grads['b2'] = db2
136+
grads['W1'] = dW1 + self.reg * self.params['W1']
137+
grads['b1'] = db1
99138
############################################################################
100139
# END OF YOUR CODE #
101140
############################################################################

assignment2/cs231n/layers.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,10 @@ def conv_backward_naive(dout, cache):
483483
Inputs:
484484
- dout: Upstream derivatives.
485485
- cache: A tuple of (x, w, b, conv_param) as in conv_forward_naive
486+
487+
Some helpful explonation could be find there:
488+
- https://medium.com/@2017csm1006/forward-and-backpropagation-in-convolutional-neural-network-4dfa96d7b37e
489+
- https://becominghuman.ai/back-propagation-in-convolutional-neural-networks-intuition-and-code-714ef1c38199
486490
487491
Returns a tuple of:
488492
- dx: Gradient with respect to x
@@ -551,7 +555,20 @@ def max_pool_forward_naive(x, pool_param):
551555
###########################################################################
552556
# TODO: Implement the max pooling forward pass #
553557
###########################################################################
554-
pass
558+
(N, C, H, W) = x.shape
559+
pool_height = pool_param['pool_height']
560+
pool_width = pool_param['pool_width']
561+
stride = pool_param['stride']
562+
out_H = H // stride
563+
out_W = W // stride
564+
out = np.zeros((N, C, out_H, out_W))
565+
566+
for h in range(out_H):
567+
for w in range(out_W):
568+
xx = h * stride
569+
yy = w * stride
570+
out[:,:,h,w] = np.max(x[:,:,xx:xx + pool_height,yy:yy + pool_width], axis=(2,3))
571+
555572
###########################################################################
556573
# END OF YOUR CODE #
557574
###########################################################################
@@ -574,7 +591,28 @@ def max_pool_backward_naive(dout, cache):
574591
###########################################################################
575592
# TODO: Implement the max pooling backward pass #
576593
###########################################################################
577-
pass
594+
(x, pool_param) = cache
595+
596+
pool_height = pool_param['pool_height']
597+
pool_width = pool_param['pool_width']
598+
stride = pool_param['stride']
599+
600+
dx = np.zeros_like(x)
601+
602+
(N, C, H, W) = dout.shape
603+
for h in range(H):
604+
for w in range(W):
605+
xx = h * stride
606+
yy = w * stride
607+
# find which x were contribute to the out
608+
x_frame = x[:,:,xx:xx + pool_height,yy:yy + pool_width]
609+
# x_frame has shape = [number_of_samples, features] but should be [number_of_samples, features, h, w]
610+
# or at least [number_of_samples, features, 1, 1]
611+
# in other words operation "*[:,:,None,None]" changes dimesion
612+
# from [number_of_samples, features] to [number_of_samples, features, 1, 1]
613+
x_mask = x_frame == x_frame.max(axis=(2,3))[:,:,None,None]
614+
dx[:,:,xx:xx + pool_height,yy:yy + pool_width] += dout[:,:,h,w][:,:,None,None] * x_mask
615+
578616
###########################################################################
579617
# END OF YOUR CODE #
580618
###########################################################################
@@ -612,7 +650,11 @@ def spatial_batchnorm_forward(x, gamma, beta, bn_param):
612650
# version of batch normalization defined above. Your implementation should#
613651
# be very short; ours is less than five lines. #
614652
###########################################################################
615-
pass
653+
N, C, H, W = x.shape
654+
# put channel at the last dimention and stretch all dimensions except the last one
655+
flat_output, cache = batchnorm_forward(x.transpose(0,2,3,1).reshape((N*H*W,C)), gamma, beta, bn_param)
656+
# revert dimensions
657+
out = flat_output.reshape(N,H,W,C).transpose(0,3,1,2)
616658
###########################################################################
617659
# END OF YOUR CODE #
618660
###########################################################################
@@ -642,7 +684,9 @@ def spatial_batchnorm_backward(dout, cache):
642684
# version of batch normalization defined above. Your implementation should#
643685
# be very short; ours is less than five lines. #
644686
###########################################################################
645-
pass
687+
N, C, H, W = dout.shape
688+
flat_dx, dgamma, dbeta = batchnorm_backward(dout.transpose(0,2,3,1).reshape((N*H*W,C)), cache)
689+
dx = flat_dx.reshape(N,H,W,C).transpose(0,3,1,2)
646690
###########################################################################
647691
# END OF YOUR CODE #
648692
###########################################################################

0 commit comments

Comments
 (0)