File size: 2,001 Bytes
4c97910
79f3d28
4c97910
79f3d28
031ac83
24f2542
 
 
 
79f3d28
24f2542
 
 
 
 
79f3d28
 
24f2542
 
 
 
 
 
 
ba1e2db
 
ecb0c79
 
bec1ee5
79f3d28
031ac83
24f2542
 
 
79f3d28
 
24f2542
204251b
bec1ee5
031ac83
 
 
c777165
79f3d28
 
031ac83
4e6140d
 
79f3d28
4e6140d
79f3d28
88a3c01
 
 
0f9e8ef
 
 
 
79f3d28
 
 
 
0f9e8ef
79f3d28
 
c777165
031ac83
4e6140d
 
204251b
 
 
 
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
import numpy as np
from typing import Callable

from neural_network.neural_network import NeuralNetwork


def fp(
    X_train: np.array,
    y_train: np.array,
    func: Callable,
    w1: np.array,
    w2: np.array,
    b1: np.array,
    b2: np.array,
):
    n1 = compute_node(arr=X_train, w=w1, b=b1, func=func)
    y_hat = compute_node(arr=n1, w=w2, b=b2, func=func)
    return y_hat, n1, (y_hat-y_train)


def bp(
    X_train: np.array,
    y_train: np.array,
    wb: dict,
    args: dict,
) -> NeuralNetwork:
    args.update(wb)
    model = NeuralNetwork.from_dict(args)
    loss_history = []
    for _ in range(model.epochs):
        # forward prop
        y_hat, node1, error = fp(
            X_train=X_train,
            y_train=y_train,
            func=model.activation_func,
            w1=model.w1, w2=model.w2, b1=model.b1, b2=model.b2,
        )
        mean_squared_error = mse(y_train, y_hat)
        loss_history.append(mean_squared_error)

        # backprop
        dw1 = np.dot(
            X_train.T,
            np.dot(error * model.func_prime(y_hat), model.w2.T) *
            model.func_prime(node1),
        )
        dw2 = np.dot(
            node1.T,
            error * model.func_prime(y_hat),
        )
        db2 = np.sum(error * model.func_prime(y_hat), axis=0)
        db1 = np.sum(
            np.dot(error * model.func_prime(y_hat), model.w2.T) * model.func_prime(node1), axis=0,
        )

        # update weights & biases using gradient descent.
        # this is -= and not += because if the gradient descent
        # is positive, we want to go down.
        model.w1 -= (model.learning_rate * dw1)
        model.w2 -= (model.learning_rate * dw2)
        model.b1 -= (model.learning_rate * db1)
        model.b2 -= (model.learning_rate * db2)

    model.set_loss_hist(loss_hist=loss_history)
    return model


def compute_node(arr, w, b, func):
    return func(np.dot(arr, w) + b)


def mse(y: np.array, y_hat: np.array):
    return np.mean((y - y_hat) ** 2)