-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlayers.py
More file actions
99 lines (73 loc) · 3.4 KB
/
Copy pathlayers.py
File metadata and controls
99 lines (73 loc) · 3.4 KB
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
import numpy as np
from activations import ReLU
from optimizers import SGD
class Tensor:
def __init__(self, shape):
self.data = np.ndarray(shape, np.float32) # here keep the weights
self.grad = np.ndarray(shape, np.float32) # here keep the grads of the weights
class Abstract_Layer(object):
input: np.ndarray
def forward(self, x: np.ndarray) -> np.ndarray:
raise NotImplementedError
def backward(self, d_y: np.ndarray) -> np.ndarray:
raise NotImplementedError
def parameters(self):
return []
class Linear(Abstract_Layer):
def __init__(self, in_nodes, out_nodes):
self.type = 'linear'
self.weights = Tensor((in_nodes, out_nodes))
self.bias = Tensor((1, out_nodes))
def forward(self, x: np.ndarray) -> np.ndarray:
self.input = x
return np.dot(x, self.weights.data) + self.bias.data
def backward(self, d_y: np.ndarray) -> np.ndarray:
self.weights.grad += np.dot(self.input.T, d_y)
self.bias.grad += np.sum(d_y, axis=0, keepdims=True)
return np.dot(d_y, self.weights.data.T)
def parameters(self):
return [self.weights, self.bias]
class Softmax(Abstract_Layer):
probabilities: np.ndarray
true_label: np.ndarray
def __init__(self, in_nodes, out_nodes):
self.weights = Tensor((in_nodes, out_nodes))
self.bias = Tensor((1, out_nodes))
self.type = 'softmax'
def forward(self, x: np.ndarray) -> np.ndarray:
self.input = x
linear_output = np.dot(x, self.weights.data) + self.bias.data
logits = np.exp(linear_output - np.max(linear_output, axis=1, keepdims=True))
self.probabilities = logits / np.sum(logits, axis=1, keepdims=True)
return self.probabilities
def backward(self, true_label: np.ndarray) -> np.ndarray:
error = self.probabilities
# print("error: ",error)
error[range(len(true_label)), true_label] -= 1.0 # exponents - C
# print("new error: ",error)
error /= len(true_label)
self.weights.grad += np.dot(self.input.T, error)
self.bias.grad += np.sum(error, axis=0, keepdims=True)
return np.dot(error, self.weights.data.T)
def parameters(self):
return [self.weights, self.bias]
class ResBlock(Abstract_Layer): # with only 1 relu
def __init__(self, in_nodes, out_nodes):
self.type = 'resblock'
self.weights1 = Tensor((in_nodes, out_nodes))
self.weights2 = Tensor((in_nodes, out_nodes))
self.bias1 = Tensor((1, out_nodes))
self.bias2 = Tensor((1, out_nodes))
self.relu = ReLU()
def forward(self, x: np.ndarray) -> np.ndarray:
self.input = x
return np.dot(x, self.weights2.data) + self.relu.forward(np.dot(x, self.weights1.data) + self.bias1.data) + self.bias2.data
def backward(self, d_y: np.ndarray) -> np.ndarray:
temp_x = self.input
self.weights1.grad += np.dot((self.input * np.where(temp_x > 0, temp_x, 0)).T, d_y)
self.weights2.grad += np.dot(self.input.T, d_y)
self.bias1.grad += np.sum(np.dot((np.where(temp_x > 0, temp_x, 0)).T, d_y), axis=0, keepdims=True)
self.bias2.grad += np.sum(d_y, axis=0, keepdims=True)
return np.dot(d_y, self.weights1.data.T) * np.where(temp_x > 0, temp_x, 0) + np.dot(d_y, self.weights2.data.T)
def parameters(self):
return [self.weights1, self.weights2, self.bias1, self.bias2]