forked from snrazavi/Machine-Learning-in-Python-Workshop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlayers.py
245 lines (187 loc) · 6.46 KB
/
layers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
import numpy as np
def affine_forward(x, W, b):
"""
A linear mapping from inputs to scores.
Inputs:
- x: input matrix (N, d_1, ..., d_k)
- W: weigh matrix (D, C)
- b: bias vector (C, )
Outputs:
- out: output of linear layer (N, C)
"""
x2d = np.reshape(x, (x.shape[0], -1)) # convert 4D input matrix to 2D
out = np.dot(x2d, W) + b # linear transformation
cache = (x, W, b) # keep for backward step (stay with us)
return out, cache
def affine_backward(dout, cache):
"""
Computes the backward pass for an affine layer.
Inputs:
- dout: Upstream derivative, of shape (N, C)
- cache: Tuple of:
- x: Input data, of shape (N, d_1, ... d_k)
- w: Weights, of shape (D, C)
- b: biases, of shape (C,)
Outputs:
- dx: Gradient with respect to x, of shape (N, d1, ..., d_k)
- dw: Gradient with respect to w, of shape (D, C)
- db: Gradient with respect to b, of shape (C,)
"""
x, w, b = cache
x2d = np.reshape(x, (x.shape[0], -1))
# compute gradients
db = np.sum(dout, axis=0)
dw = np.dot(x2d.T, dout)
dx = np.dot(dout, w.T)
# reshape dx to match the size of x
dx = dx.reshape(x.shape)
return dx, dw, db
def relu_forward(x):
"""Forward pass for a layer of rectified linear units.
Inputs:
- x: a numpy array of any shape
Outputs:
- out: output of relu, same shape as x
- cache: x
"""
cache = x
out = np.maximum(0, x)
return out, cache
def relu_backward(dout, cache):
"""Backward pass for a layer of rectified linear units.
Inputs:
- dout: upstream derevatives, of any shape
- cache: x, same shape as dout
Outputs:
- dx: gradient of loss w.r.t x
"""
x = cache
dx = dout * (x > 0)
return dx
def svm_loss_naive(scores, y):
"""
Naive implementation of SVM loss function.
Inputs:
- scores: scores for all training data (N, C)
- y: correct labels for the training data
Outputs:
- loss: data loss plus L2 regularization loss
- grads: graidents of loss w.r.t. scores
"""
N, C = scores.shape
# Compute svm data loss
loss = 0.0
for i in range(N):
s = scores[i] # scores for the ith data
correct_class = y[i] # correct class score
for j in range(C):
if j == y[i]:
continue
else:
# loss += max(0, s[j] - s[correct_class] + 1.0)
margin = s[j] - s[correct_class] + 1.0
if margin > 0:
loss += margin
loss /= N
# Compute gradient off loss function w.r.t. scores
# We will write this part later
grads = {}
return loss, grads
def svm_loss_half_vectorized(scores, y):
"""
Half-vectorized implementation of SVM loss function.
Inputs:
- scores: scores for all training data (N, C)
- y: correct labels for the training data
Outputs:
- loss: data loss plus L2 regularization loss
- grads: graidents of loss wrt scores
"""
N, C = scores.shape
# Compute svm data loss
loss = 0.0
for i in range(N):
s = scores[i] # scores for the ith data
correct_class = y[i] # correct class score
margins = np.maximum(0.0, s - s[correct_class] + 1.0)
margins[correct_class] = 0.0
loss += np.sum(margins)
loss /= N
# Compute gradient off loss function w.r.t. scores
# We will write this part later
grads = {}
return loss, grads
def svm_loss(scores, y):
"""
Fully-vectorized implementation of SVM loss function.
Inputs:
- scores: scores for all training data (N, C)
- y: correct labels for the training data of shape (N,)
Outputs:
- loss: data loss plus L2 regularization loss
- grads: graidents of loss w.r.t scores
"""
N = scores.shape[0]
# Compute svm data loss
correct_class_scores = scores[range(N), y]
margins = np.maximum(0.0, scores - correct_class_scores[:, None] + 1.0)
margins[range(N), y] = 0.0
loss = np.sum(margins) / N
# Compute gradient off loss function w.r.t. scores
num_pos = np.sum(margins > 0, axis=1)
dscores = np.zeros(scores.shape)
dscores[margins > 0] = 1
dscores[range(N), y] -= num_pos
dscores /= N
return loss, dscores
def softmax_loss_naive(scores, y):
"""
Softmax loss function, naive implementation (with loops)
Inputs have dimension D, there are C classes, and we operate on minibatches
of N examples.
Inputs:
- scores: A numpy array of shape (N, C).
- y: A numpy array of shape (N,) containing training labels;
Outputs:
- loss: as single float
- grads: gradient with respect to weights W; an array of same shape as W
"""
N, C = scores.shape
# compute data loss
loss = 0.0
for i in range(N):
correct_class = y[i]
score = scores[i]
score -= np.max(scores)
exp_score = np.exp(score)
probs = exp_score / np.sum(exp_score)
loss += -np.log(probs[correct_class])
loss /= N
# Compute gradient off loss function w.r.t. scores
# We will write this part later
grads = {}
return loss, grads
def softmax_loss(scores, y):
"""
Softmax loss function, fully vectorized implementation.
Inputs have dimension D, there are C classes, and we operate on minibatches
of N examples.
Inputs:
- scores: A numpy array of shape (N, C).
- y: A numpy array of shape (N,) containing training labels;
Outputs:
- loss as single float
- gradient with respect to scores
"""
N = scores.shape[0] # number of input data
# compute data loss
shifted_logits = scores - np.max(scores, axis=1, keepdims=True)
Z = np.sum(np.exp(shifted_logits), axis=1, keepdims=True)
log_probs = shifted_logits - np.log(Z)
probs = np.exp(log_probs)
loss = -np.sum(log_probs[range(N), y]) / N
# Compute gradient of loss function w.r.t. scores
dscores = probs.copy()
dscores[range(N), y] -= 1
dscores /= N
return loss, dscores