Jensen-holm commited on
Commit
79f3d28
·
1 Parent(s): e92ba0d

produced a solution to the problem of funcions not being accessed

Browse files
neural_network/backprop.py CHANGED
@@ -1,33 +1,20 @@
1
  import numpy as np
2
- from tqdm import tqdm
3
 
4
- from neural_network.opts import activation
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
- activation: callable,
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=activation)
30
- y_hat = compute_node(arr=n1, w=w2, b=b2, func=activation)
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
- epochs, func, func_prime, lr, w1, w2, b1, b2 = get_args(args, wb)
41
- r = {}
42
  loss_history = []
43
- for e in tqdm(range(epochs)):
44
  # forward prop
45
  y_hat, node1, error = fp(
46
  X_train=X_train,
47
  y_train=y_train,
48
- actiavtion=func,
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) * func_prime(node1),
 
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 -= (lr * dw1)
71
- w2 -= (lr * dw2)
72
- b1 -= (lr * db1)
73
- b2 -= (lr * db2)
74
 
75
- # keeping track of each epochs' numbers
76
- r[e] = {
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
- "W1": np.random.randn(X.shape[1], hidden_size),
20
  "b1": np.zeros((1, hidden_size)),
21
- "W2": np.random.randn(hidden_size, 1),
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
- # once we have these results we should test it against
40
- # the y_test data
41
- results, loss_history = bp(X_train, y_train, wb, args)
42
- final = results[args["epochs"] - 1]
43
- func = activation[args["activation_func"]]["main"]
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)