Spaces:
Sleeping
Sleeping
Commit
·
79f3d28
1
Parent(s):
e92ba0d
produced a solution to the problem of funcions not being accessed
Browse files- neural_network/backprop.py +21 -46
- neural_network/main.py +14 -22
- neural_network/model.py +0 -20
- neural_network/neural_network.py +39 -0
- neural_network/plot.py +0 -37
neural_network/backprop.py
CHANGED
@@ -1,33 +1,20 @@
|
|
1 |
import numpy as np
|
2 |
-
from
|
3 |
|
4 |
-
from neural_network.
|
5 |
-
|
6 |
-
|
7 |
-
def get_args(args: dict, wb: dict):
|
8 |
-
return (
|
9 |
-
args["epochs"],
|
10 |
-
args["activation_func"],
|
11 |
-
args["func_prime"],
|
12 |
-
args["learning_rate"],
|
13 |
-
wb["W1"],
|
14 |
-
wb["W2"],
|
15 |
-
wb["b1"],
|
16 |
-
wb["b2"],
|
17 |
-
)
|
18 |
|
19 |
|
20 |
def fp(
|
21 |
X_train: np.array,
|
22 |
y_train: np.array,
|
23 |
-
|
24 |
w1: np.array,
|
25 |
w2: np.array,
|
26 |
b1: np.array,
|
27 |
b2: np.array,
|
28 |
):
|
29 |
-
n1 = compute_node(arr=X_train, w=w1, b=b1, func=
|
30 |
-
y_hat = compute_node(arr=n1, w=w2, b=b2, func=
|
31 |
return y_hat, n1, (y_hat-y_train)
|
32 |
|
33 |
|
@@ -37,16 +24,15 @@ def bp(
|
|
37 |
wb: dict,
|
38 |
args: dict
|
39 |
):
|
40 |
-
|
41 |
-
r = {}
|
42 |
loss_history = []
|
43 |
-
for
|
44 |
# forward prop
|
45 |
y_hat, node1, error = fp(
|
46 |
X_train=X_train,
|
47 |
y_train=y_train,
|
48 |
-
|
49 |
-
w1=w1, w2=w2, b1=b1, b2=b2,
|
50 |
)
|
51 |
mean_squared_error = mse(y_train, y_hat)
|
52 |
loss_history.append(mean_squared_error)
|
@@ -54,38 +40,27 @@ def bp(
|
|
54 |
# backprop
|
55 |
dw1 = np.dot(
|
56 |
X_train.T,
|
57 |
-
np.dot(error * func_prime(y_hat), w2.T) *
|
|
|
58 |
)
|
59 |
dw2 = np.dot(
|
60 |
node1.T,
|
61 |
-
error * func_prime(y_hat),
|
62 |
)
|
63 |
-
db2 = np.sum(error * func_prime(y_hat), axis=0)
|
64 |
-
db1 = np.sum(np.dot(error * func_prime(y_hat), w2.T)
|
65 |
-
* func_prime(node1), axis=0)
|
66 |
|
67 |
# update weights & biases using gradient descent.
|
68 |
# this is -= and not += because if the gradient descent
|
69 |
# is positive, we want to go down.
|
70 |
-
w1 -= (
|
71 |
-
w2 -= (
|
72 |
-
b1 -= (
|
73 |
-
b2 -= (
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
"W1": w1,
|
78 |
-
"W2": w2,
|
79 |
-
"b1": b1,
|
80 |
-
"b2": b2,
|
81 |
-
"dw1": dw1,
|
82 |
-
"dw2": dw2,
|
83 |
-
"db1": db1,
|
84 |
-
"db2": db2,
|
85 |
-
"error": error,
|
86 |
-
"mse": mean_squared_error,
|
87 |
-
}
|
88 |
-
return r, loss_history
|
89 |
|
90 |
|
91 |
def compute_node(arr, w, b, func):
|
|
|
1 |
import numpy as np
|
2 |
+
from typing import Callable
|
3 |
|
4 |
+
from neural_network.neural_network import NeuralNetwork
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
|
7 |
def fp(
|
8 |
X_train: np.array,
|
9 |
y_train: np.array,
|
10 |
+
func: Callable,
|
11 |
w1: np.array,
|
12 |
w2: np.array,
|
13 |
b1: np.array,
|
14 |
b2: np.array,
|
15 |
):
|
16 |
+
n1 = compute_node(arr=X_train, w=w1, b=b1, func=func)
|
17 |
+
y_hat = compute_node(arr=n1, w=w2, b=b2, func=func)
|
18 |
return y_hat, n1, (y_hat-y_train)
|
19 |
|
20 |
|
|
|
24 |
wb: dict,
|
25 |
args: dict
|
26 |
):
|
27 |
+
model = NeuralNetwork.from_dict(args | wb)
|
|
|
28 |
loss_history = []
|
29 |
+
for _ in range(model.epochs):
|
30 |
# forward prop
|
31 |
y_hat, node1, error = fp(
|
32 |
X_train=X_train,
|
33 |
y_train=y_train,
|
34 |
+
func=model.activation_func,
|
35 |
+
w1=model.w1, w2=model.w2, b1=model.b1, b2=model.b2,
|
36 |
)
|
37 |
mean_squared_error = mse(y_train, y_hat)
|
38 |
loss_history.append(mean_squared_error)
|
|
|
40 |
# backprop
|
41 |
dw1 = np.dot(
|
42 |
X_train.T,
|
43 |
+
np.dot(error * model.func_prime(y_hat), model.w2.T) *
|
44 |
+
model.func_prime(node1),
|
45 |
)
|
46 |
dw2 = np.dot(
|
47 |
node1.T,
|
48 |
+
error * model.func_prime(y_hat),
|
49 |
)
|
50 |
+
db2 = np.sum(error * model.func_prime(y_hat), axis=0)
|
51 |
+
db1 = np.sum(np.dot(error * model.func_prime(y_hat), model.w2.T)
|
52 |
+
* model.func_prime(node1), axis=0)
|
53 |
|
54 |
# update weights & biases using gradient descent.
|
55 |
# this is -= and not += because if the gradient descent
|
56 |
# is positive, we want to go down.
|
57 |
+
model.w1 -= (model.learning_rate * dw1)
|
58 |
+
model.w2 -= (model.learning_rate * dw2)
|
59 |
+
model.b1 -= (model.learning_rate * db1)
|
60 |
+
model.b2 -= (model.learning_rate * db2)
|
61 |
|
62 |
+
model.set_loss_hist(loss_hist=loss_history)
|
63 |
+
return model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
|
66 |
def compute_node(arr, w, b, func):
|
neural_network/main.py
CHANGED
@@ -3,8 +3,6 @@ import numpy as np
|
|
3 |
|
4 |
from neural_network.opts import activation
|
5 |
from neural_network.backprop import bp
|
6 |
-
from neural_network.model import Network
|
7 |
-
from neural_network.plot import loss_history_plt, save_plt
|
8 |
|
9 |
|
10 |
def init(
|
@@ -16,41 +14,35 @@ def init(
|
|
16 |
weights and biases to start off the neural_network
|
17 |
"""
|
18 |
return {
|
19 |
-
"
|
20 |
"b1": np.zeros((1, hidden_size)),
|
21 |
-
"
|
22 |
"b2": np.zeros((1, 1)),
|
23 |
}
|
24 |
|
25 |
|
26 |
-
def main(
|
27 |
X: np.array,
|
28 |
y: np.array,
|
29 |
args,
|
30 |
) -> None:
|
31 |
wb = init(X, args["hidden_size"])
|
|
|
|
|
|
|
|
|
32 |
X_train, X_test, y_train, y_test = train_test_split(
|
33 |
X,
|
34 |
y,
|
35 |
test_size=0.3,
|
36 |
random_state=8675309
|
37 |
)
|
|
|
38 |
|
39 |
-
#
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
# initialize our final network
|
46 |
-
fm = Network(final_wb=final, activation_func=func)
|
47 |
-
|
48 |
-
# predict the x test data and compare it to y test data
|
49 |
-
pred = fm.predict(X_test)
|
50 |
-
mse = np.mean((pred - y_test) ** 2)
|
51 |
-
print(f"mean squared error: {mse}")
|
52 |
|
53 |
-
# plot predicted versus actual
|
54 |
-
# also plot the training loss over epochs
|
55 |
-
animated_loss_plt = loss_history_plt(loss_history)
|
56 |
-
save_plt(animated_loss_plt, "plt.svg", animated=True, fps=30)
|
|
|
3 |
|
4 |
from neural_network.opts import activation
|
5 |
from neural_network.backprop import bp
|
|
|
|
|
6 |
|
7 |
|
8 |
def init(
|
|
|
14 |
weights and biases to start off the neural_network
|
15 |
"""
|
16 |
return {
|
17 |
+
"w1": np.random.randn(X.shape[1], hidden_size),
|
18 |
"b1": np.zeros((1, hidden_size)),
|
19 |
+
"w2": np.random.randn(hidden_size, 1),
|
20 |
"b2": np.zeros((1, 1)),
|
21 |
}
|
22 |
|
23 |
|
24 |
+
def main(
|
25 |
X: np.array,
|
26 |
y: np.array,
|
27 |
args,
|
28 |
) -> None:
|
29 |
wb = init(X, args["hidden_size"])
|
30 |
+
act = activation[args["activation_func"]]
|
31 |
+
args["activation_func"] = act["main"]
|
32 |
+
args["func_prime"] = act["prime"]
|
33 |
+
|
34 |
X_train, X_test, y_train, y_test = train_test_split(
|
35 |
X,
|
36 |
y,
|
37 |
test_size=0.3,
|
38 |
random_state=8675309
|
39 |
)
|
40 |
+
model = bp(X_train, y_train, wb, args)
|
41 |
|
42 |
+
# evaluate the model and return final results
|
43 |
+
model.eval(
|
44 |
+
X_test=X_test,
|
45 |
+
y_test=y_test,
|
46 |
+
)
|
47 |
+
return model.__dict__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
|
|
|
|
|
|
|
neural_network/model.py
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
import numpy as np
|
2 |
-
from typing import Callable
|
3 |
-
|
4 |
-
|
5 |
-
class Network:
|
6 |
-
def __init__(self, final_wb: dict[str, np.array], activation_func: Callable):
|
7 |
-
self.func = activation_func
|
8 |
-
self.final_wb = final_wb
|
9 |
-
self.w1 = final_wb["W1"]
|
10 |
-
self.w2 = final_wb["W2"]
|
11 |
-
self.b1 = final_wb["b1"]
|
12 |
-
self.b2 = final_wb["b2"]
|
13 |
-
|
14 |
-
def predict(self, x: np.array) -> np.array:
|
15 |
-
n1 = self.compute_node(x, self.w1, self.b1, self.func)
|
16 |
-
return self.compute_node(n1, self.w2, self.b2, self.func)
|
17 |
-
|
18 |
-
@staticmethod
|
19 |
-
def compute_node(arr, w, b, func):
|
20 |
-
return func(np.dot(arr, w) + b)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
neural_network/neural_network.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from dataclasses import dataclass, field
|
2 |
+
from typing import Callable
|
3 |
+
import numpy as np
|
4 |
+
|
5 |
+
|
6 |
+
@dataclass
|
7 |
+
class NeuralNetwork:
|
8 |
+
epochs: int
|
9 |
+
learning_rate: float
|
10 |
+
activation_func: Callable
|
11 |
+
func_prime: Callable
|
12 |
+
hidden_size: int
|
13 |
+
w1: np.array
|
14 |
+
w2: np.array
|
15 |
+
b1: np.array
|
16 |
+
b2: np.array
|
17 |
+
|
18 |
+
mse: float = 0
|
19 |
+
loss_history: list = field(
|
20 |
+
default_factory=lambda: [],
|
21 |
+
)
|
22 |
+
|
23 |
+
def predict(self, x: np.array) -> np.array:
|
24 |
+
n1 = self.compute_node(x, self.w1, self.b1, self.activation_func)
|
25 |
+
return self.compute_node(n1, self.w2, self.b2, self.activation_func)
|
26 |
+
|
27 |
+
def set_loss_hist(self, loss_hist: list) -> None:
|
28 |
+
self.loss_history = loss_hist
|
29 |
+
|
30 |
+
def eval(self, X_test, y_test) -> None:
|
31 |
+
self.mse = np.mean((self.predict(X_test) - y_test) ** 2)
|
32 |
+
|
33 |
+
@staticmethod
|
34 |
+
def compute_node(arr, w, b, func) -> np.array:
|
35 |
+
return func(np.dot(arr, w) + b)
|
36 |
+
|
37 |
+
@classmethod
|
38 |
+
def from_dict(cls, dct):
|
39 |
+
return cls(**dct)
|
neural_network/plot.py
DELETED
@@ -1,37 +0,0 @@
|
|
1 |
-
import seaborn as sns
|
2 |
-
import matplotlib.pyplot as plt
|
3 |
-
from matplotlib.animation import FuncAnimation, FFMpegWriter
|
4 |
-
|
5 |
-
sns.set()
|
6 |
-
|
7 |
-
"""
|
8 |
-
Save plots to the plots folder for when
|
9 |
-
we would like to show results on our little
|
10 |
-
flask application
|
11 |
-
"""
|
12 |
-
|
13 |
-
PLT_PATH: str = "static/assets/"
|
14 |
-
|
15 |
-
|
16 |
-
def loss_history_plt(loss_history: list) -> FuncAnimation:
|
17 |
-
fig, ax = plt.subplots()
|
18 |
-
|
19 |
-
def animate(i):
|
20 |
-
ax.clear()
|
21 |
-
sns.lineplot(
|
22 |
-
x=range(i),
|
23 |
-
y=loss_history[:i],
|
24 |
-
ax=ax,
|
25 |
-
)
|
26 |
-
ax.set_xlabel("Epoch")
|
27 |
-
ax.set_ylabel("Training Loss")
|
28 |
-
|
29 |
-
return FuncAnimation(fig, animate, frames=len(loss_history), interval=100)
|
30 |
-
|
31 |
-
|
32 |
-
def save_plt(plot, filename: str, animated: bool, fps=10):
|
33 |
-
if not animated:
|
34 |
-
plot.savefig(filename)
|
35 |
-
return
|
36 |
-
writer = FFMpegWriter(fps=fps)
|
37 |
-
plot.save(PLT_PATH + filename, writer=writer)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|