Skip to content

Commit 56abca5

Browse files
kkweonhunkim
authored andcommitted
add: pure numpy (hunkim#180)
add: Numpy README
1 parent fdcb256 commit 56abca5

3 files changed

Lines changed: 299 additions & 0 deletions

File tree

numpy/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Pure Numpy version of DeepLearningZeroToAll
2+
3+
* [x] Logistics Regression
4+
* [x] Softmax Classification
5+
* [ ] Convolution Network
6+
* [ ] Recurrent Neural Network
7+
8+
9+
## Other resources
10+
* [minpy](https://github.com/dmlc/minpy)
11+
12+
Minpy is a pure Numpy Interface on the top of MXNet. So it can run on GPUs. It's simple to use by swapping `import numpy as np` with `import minpy.numpy as np`
13+
14+
* [Autograd](https://github.com/HIPS/autograd)
15+
16+
Autograd allows automatic gradient computations with Numpy. However, in this repo, there will be no autograd for study purpose.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
"""
2+
Logistic Regression
3+
4+
y = sigmoid(X @ W + b)
5+
6+
"""
7+
import numpy as np
8+
9+
x_data = [[1, 2],
10+
[2, 3],
11+
[3, 1],
12+
[4, 3],
13+
[5, 3],
14+
[6, 2]]
15+
y_data = [[0],
16+
[0],
17+
[0],
18+
[1],
19+
[1],
20+
[1]]
21+
22+
X_train = np.array(x_data, dtype=np.float32)
23+
y_train = np.array(y_data).reshape(-1, 1)
24+
25+
N = X_train.shape[0]
26+
D = X_train.shape[1]
27+
28+
C = 1
29+
LEARNING_RATE = 0.1
30+
MAX_ITER = 1000
31+
32+
W = np.random.standard_normal((D, C))
33+
b = np.zeros((C,))
34+
35+
36+
def sigmoid(x):
37+
"""Sigmoid function """
38+
sigmoid = 1 / (1 + np.exp(-x))
39+
40+
return sigmoid
41+
42+
43+
def sigmoid_cross_entropy(logit, labels):
44+
"""Compute a binary cross entropy loss
45+
46+
z = logit = X @ W + b
47+
p = sigmoid(z)
48+
loss_i = y * - log(p) + (1 - y) * - log(1 - p)
49+
50+
Args:
51+
logit (2-D Array): Logit array of shape (N, 1)
52+
labels (2-D Array): Binary Label array of shape (N, 1)
53+
54+
Returns:
55+
float: mean(loss_i)
56+
"""
57+
assert logit.shape == (N, C)
58+
assert labels.shape == (N, C)
59+
60+
probs = sigmoid(logit)
61+
loss_i = labels * -np.log(probs + 1e-8)
62+
loss_i += (1 - labels) * -np.log(1 - probs + 1e-8)
63+
64+
loss = np.mean(loss_i)
65+
66+
return loss
67+
68+
69+
def grad_sigmoid_cross_entropy(logit, labels):
70+
"""Returns
71+
72+
d_loss_i d_sigmoid
73+
-------- * ---------
74+
d_sigmoid d_z
75+
76+
z = logit = X * W + b
77+
78+
Args:
79+
logit (2-D Array): Logit array of shape (N, 1)
80+
labels (2-D Array): Binary Label array of shape (N, 1)
81+
82+
Returns:
83+
2-D Array: Backpropagated gradients of loss (N, 1)
84+
"""
85+
return sigmoid(logit) - labels
86+
87+
88+
def affine_forward(X, W, b):
89+
"""Returns a logit
90+
91+
logit = X @ W + b
92+
93+
Args:
94+
X (2-D Array): Input array of shape (N, D)
95+
W (2-D Array): Weight array of shape (D, 1)
96+
b (1-D Array): Bias array of shape (1,)
97+
98+
Returns:
99+
logit (2-D Array): Logit array of shape (N, 1)
100+
"""
101+
return np.dot(X, W) + b
102+
103+
104+
for i in range(MAX_ITER):
105+
106+
logit = affine_forward(X_train, W, b)
107+
loss = sigmoid_cross_entropy(logit, y_train)
108+
d_loss = grad_sigmoid_cross_entropy(logit, y_train)
109+
110+
d_W = np.dot(X_train.T, d_loss) / N
111+
d_b = np.sum(d_loss) / N
112+
113+
W -= LEARNING_RATE * d_W
114+
b -= LEARNING_RATE * d_b
115+
116+
if i % (MAX_ITER // 10) == 0:
117+
prob = affine_forward(X_train, W, b)
118+
prob = sigmoid(prob)
119+
pred = prob > 0.5
120+
acc = (pred == y_train).mean()
121+
122+
print("[Step: {:5}] Loss: {:<5.3} Accuracy: {:>5.2%}".format(i, loss, acc))
123+
124+
"""
125+
[Step: 0] Loss: 2.35 Accuracy: 50.00%
126+
[Step: 100] Loss: 0.523 Accuracy: 83.33%
127+
[Step: 200] Loss: 0.435 Accuracy: 83.33%
128+
[Step: 300] Loss: 0.368 Accuracy: 83.33%
129+
[Step: 400] Loss: 0.316 Accuracy: 83.33%
130+
[Step: 500] Loss: 0.275 Accuracy: 83.33%
131+
[Step: 600] Loss: 0.243 Accuracy: 100.00%
132+
[Step: 700] Loss: 0.217 Accuracy: 100.00%
133+
[Step: 800] Loss: 0.196 Accuracy: 100.00%
134+
[Step: 900] Loss: 0.178 Accuracy: 100.00%
135+
"""
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import numpy as np
2+
3+
data = np.loadtxt("../data-04-zoo.csv",
4+
delimiter=",",
5+
dtype=np.float32)
6+
7+
X_train = data[:, :-1]
8+
y_train = data[:, -1].astype(np.int8)
9+
assert X_train.shape == (101, 16)
10+
assert y_train.shape == (101,)
11+
12+
N, D = X_train.shape
13+
C = np.max(y_train) + 1
14+
15+
y_train_onehot = np.zeros(shape=(N, C))
16+
y_train_onehot[np.arange(N), y_train] = 1
17+
18+
assert C == 7, "There are 7 classes to predict"
19+
20+
W = np.random.standard_normal((D, C))
21+
b = np.zeros((C,))
22+
23+
24+
def affine_forward(X, W, b):
25+
"""Returns a logit
26+
27+
logit = X @ W + b
28+
29+
Args:
30+
X (2-D Array): Input array of shape (N, D)
31+
W (2-D Array): Weight array of shape (D, C)
32+
b (1-D Array): Bias array of shape (C,)
33+
34+
Returns:
35+
logit (2-D Array): Logit array of shape (N, C)
36+
"""
37+
return np.dot(X, W) + b
38+
39+
40+
def softmax(z):
41+
"""Softmax Function
42+
43+
Subtract max for numerical stability
44+
45+
Args:
46+
z (2-D Array): Array of shape (N, C)
47+
48+
Returns:
49+
2-D Array: Softmax output of (N, C)
50+
"""
51+
z -= np.max(z)
52+
numerator = np.exp(z)
53+
denominator = np.sum(numerator, axis=1).reshape(-1, 1) + 1e-7
54+
55+
return numerator / denominator
56+
57+
58+
def softmax_cross_entropy_loss(logit, labels):
59+
"""Returns a softmax cross entropy loss
60+
61+
loss_i = - log(P(y_i | x_i))
62+
63+
Args:
64+
logit (2-D Array): Logit array of shape (N, C)
65+
labels (2-D Array): Label Onehot array of shape (N, C)
66+
67+
Returns:
68+
float: mean(loss_i)
69+
"""
70+
p = softmax(logit)
71+
loss_i = - labels * np.log(p + 1e-8)
72+
return np.mean(loss_i)
73+
74+
75+
def grad_softmax_cross_entropy_loss(logit, labels):
76+
"""Returns
77+
78+
d_loss_i d_softmax
79+
-------- * ---------
80+
d_softmax d_z
81+
82+
z = logit = X * W + b
83+
84+
Args:
85+
logit (2-D Array): Logit array of shape (N, C)
86+
labels (2-D Array): Onehot label array of shape (N, C)
87+
88+
Returns:
89+
2-D Array: Backpropagated gradients of loss (N, C)
90+
91+
Notes:
92+
[1] Neural Net Backprop in one slide! by Sung Kim
93+
https://docs.google.com/presentation/d/1_ZmtfEjLmhbuM_PqbDYMXXLAqeWN0HwuhcSKnUQZ6MM/edit#slide=id.g1ec1d04b5a_1_83
94+
95+
"""
96+
return softmax(logit) - labels
97+
98+
99+
def get_accuracy(logit, labels):
100+
"""Returna an accracy
101+
102+
Args:
103+
logit (2-D Array): Logit array of shape (N, C)
104+
labels (2-D Array): Onehot label array of shape (N, C)
105+
106+
Returns:
107+
float: Accuracy
108+
"""
109+
110+
probs = softmax(logit)
111+
pred = np.argmax(probs, axis=1)
112+
true = np.argmax(labels, axis=1)
113+
114+
return np.mean(pred == true)
115+
116+
117+
LEARNING_RATE = 0.1
118+
MAX_ITER = 2000
119+
PRINT_N = 10
120+
121+
for i in range(MAX_ITER):
122+
123+
logit = affine_forward(X_train, W, b)
124+
loss = softmax_cross_entropy_loss(logit, y_train_onehot)
125+
d_loss = grad_softmax_cross_entropy_loss(logit, y_train_onehot)
126+
127+
d_W = np.dot(X_train.T, d_loss) / N
128+
d_b = np.sum(d_loss) / N
129+
130+
W -= LEARNING_RATE * d_W
131+
b -= LEARNING_RATE * d_b
132+
133+
if i % (MAX_ITER // PRINT_N) == 0:
134+
acc = get_accuracy(logit, y_train_onehot)
135+
print("[Step: {:5}] Loss: {:<10.5} Acc: {:.2%}".format(i, loss, acc))
136+
137+
"""
138+
[Step: 0] Loss: 0.76726 Acc: 31.68%
139+
[Step: 200] Loss: 0.057501 Acc: 87.13%
140+
[Step: 400] Loss: 0.034893 Acc: 92.08%
141+
[Step: 600] Loss: 0.025472 Acc: 97.03%
142+
[Step: 800] Loss: 0.020099 Acc: 97.03%
143+
[Step: 1000] Loss: 0.016562 Acc: 99.01%
144+
[Step: 1200] Loss: 0.014058 Acc: 100.00%
145+
[Step: 1400] Loss: 0.012204 Acc: 100.00%
146+
[Step: 1600] Loss: 0.010784 Acc: 100.00%
147+
[Step: 1800] Loss: 0.0096631 Acc: 100.00%
148+
"""

0 commit comments

Comments
 (0)