-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnn.js
More file actions
169 lines (135 loc) · 4.44 KB
/
Copy pathnn.js
File metadata and controls
169 lines (135 loc) · 4.44 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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
const chalk = require("chalk");
const Matrix = require("./lib/matrix");
/**
*
* Sigmoid
*/
const S = (x) => 1 / (1 + Math.exp(-x));
/**
*
* Sigmoid Derivative
*
* Took awhile to get this.
*/
const sigDer = (x) => S(x) * (1 - S(x));
/**
*
* Error Margin for backward propagation
*
*/
const loss = (result, target) => 0.5 * (target - result) ** 2;
/**
*
* Loss derivative
*
*/
const lossDer = (result, target) => target - result;
/**
*
* @param {array} input 1d array
* @param {number} target number
* @param {number} lr float
*
*/
function feed_backward(input, target, lr, lambda) {
const learningRateF = (x) => x * lr;
// Matrix.from() -> creates a 2d matrix
// Matrix.dot() -> multiplies matricies by row*column
// Matrix.apply() -> adds a function to all elements in the matrix
// Matrix.add() -> adds two matricies together using a function modifier
// L_ Matrix.multiply() and Matrix.addition()
// Matrix.T -> Transposes the matrix - inverting the shape row*column -> column*row
// Matrix.sigmoid acts like apply but with a pre-set function
//Forward Feed
input = Matrix.from(input);
const hidden = input.dot(w1).apply((b) => b + b1);
const hidden_sig = hidden.sigmoid;
const output = hidden_sig.dot(w2.T);
const output_sig = output.sigmoid;
const error = loss(output_sig.scalar, target);
// Backpropagation
// dLoss/dSig2
const errorDer = lossDer(output_sig.scalar, target);
// dSig2/dSum2
const outputDer = sigDer(output.scalar);
// dLoss/dSig2 * dSig2/dSum2
const pd = Matrix.from([[errorDer * outputDer]]);
// dSum2/dW2
const sumWDer = hidden_sig;
// dLoss/dW2 = dLoss/dSig2 * dSig2/dSum2 * dSum2/dW2
const lossWeight2 = pd.dot(sumWDer);
// dLoss/dB1 = dLoss/dSig2 * dSig2/dSum2 * dSum2/dB1
const lossBias1 = errorDer * outputDer * (b1 >= 0 ? 1 : -1);
// dSum2/dSig1
const sumSDer = w2;
// dSig1/dSum1
const hiddenDer = hidden.apply(sigDer);
// dLoss/dW1 = dLoss/dSig2 * dSig2/dSum2 * dSum2/dSig1 * dSig1/dSum1
const lossWeight1 = input.T.dot(pd.dot(sumSDer).multiply(hiddenDer));
// This is used in the wrong way. But it gives us amazing results.
const l2GradientW1 = w1.apply((x) => lambda * x);
const l2GradientW2 = w2.apply((x) => lambda * x);
// Gives us really good results
const lossWeight1WithReg = lossWeight1.addition(l2GradientW1);
const lossWeight2WithReg = lossWeight2.addition(l2GradientW2);
// Uppdate our Weigths
let newW1 = w1.addition(lossWeight1WithReg.apply(learningRateF));
let newW2 = w2.addition(lossWeight2WithReg.apply(learningRateF));
let newB1 = b1 + lossBias1 * lr;
w1 = Matrix.from(newW1.full);
w2 = Matrix.from(newW2.full);
b1 = newB1;
return error;
}
function logError(e1, e2, e3, e4) {
// console.log("\033c", "\n",)
console.log(" Errors");
console.log("-----------------------------------------------------");
console.log("| Margin of error for 1 o 1:", chalk.red(e1));
console.log("| Margin of error for 0 o 1:", chalk.red(e2));
console.log("| Margin of error for 1 o 0:", chalk.red(e3));
console.log("| Margin of error for 0 o 0:", chalk.red(e4));
console.log("----------------------------------------------------- \n");
}
function feed_forward(inpu, targ) {
const inputs = Matrix.from([inpu]);
const hidden = inputs.dot(w1);
const output = hidden.apply(S).dot(w2.T);
const result = output.apply(S);
console.log("---------------");
console.log("Input", inpu);
console.log("result", Math.round(result.full[0]), result.full[0]);
console.log("target", targ);
console.log("---------------");
}
function TrainNN(iterations = 5000, lr, lambda) {
let e1, e2, e3, e4;
for (let m = 0; m < iterations; m++) {
e1 = feed_backward([[1, 1]], 0, lr, lambda);
e2 = feed_backward([[0, 1]], 1, lr, lambda);
e3 = feed_backward([[1, 0]], 1, lr, lambda);
e4 = feed_backward([[0, 0]], 0, lr, lambda);
if (m % 100 === 0) {
logError(e1, e2, e3, e4);
}
}
}
let w1 = Matrix.randoms([2, 5]);
let w2 = Matrix.randoms([1, 5]);
let b1 = Math.random();
const iterations = 10000;
const lr = 0.3;
const lambda = 0.0001;
TrainNN(iterations, lr, lambda);
console.log(chalk.blue("\nMy Weights\n"));
console.log("- Weigths 1", w1.view);
console.log("");
console.log("- Weigths 2", w2.view);
console.log("");
console.log("- Bias\nOutput: \n ", b1);
console.log("\n");
console.log(" My Inputs and results");
feed_forward([1, 1], 0);
feed_forward([0, 1], 1);
feed_forward([1, 0], 1);
feed_forward([0, 0], 0);