-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple-nn.js
More file actions
118 lines (100 loc) · 3.66 KB
/
Copy pathsimple-nn.js
File metadata and controls
118 lines (100 loc) · 3.66 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
/**
* CHEESE Blockchain - Reusable feedforward Neural Network
* Pure JavaScript implementation with serialization support (toJSON/fromJSON)
*/
class SimpleNeuralNetwork {
constructor(inputSize, hiddenSize, outputSize) {
this.inputSize = inputSize;
this.hiddenSize = hiddenSize;
this.outputSize = outputSize;
// Xavier initialization
this.weightsIH = this._initWeights(inputSize, hiddenSize);
this.weightsHO = this._initWeights(hiddenSize, outputSize);
this.biasH = new Array(hiddenSize).fill(0);
this.biasO = new Array(outputSize).fill(0);
this.learningRate = 0.01;
}
_initWeights(rows, cols) {
const weights = [];
const scale = Math.sqrt(2 / (rows + cols));
for (let i = 0; i < rows; i++) {
weights[i] = [];
for (let j = 0; j < cols; j++) {
weights[i][j] = (Math.random() - 0.5) * 2 * scale;
}
}
return weights;
}
_sigmoid(x) {
return 1 / (1 + Math.exp(-Math.max(-500, Math.min(500, x))));
}
_sigmoidDerivative(x) {
return x * (1 - x);
}
forward(input) {
// Input to Hidden
this.hiddenInputs = new Array(this.hiddenSize).fill(0);
for (let i = 0; i < this.hiddenSize; i++) {
for (let j = 0; j < this.inputSize; j++) {
this.hiddenInputs[i] += input[j] * this.weightsIH[j][i];
}
this.hiddenInputs[i] += this.biasH[i];
}
this.hiddenOutputs = this.hiddenInputs.map(x => this._sigmoid(x));
// Hidden to Output
this.finalInputs = new Array(this.outputSize).fill(0);
for (let i = 0; i < this.outputSize; i++) {
for (let j = 0; j < this.hiddenSize; j++) {
this.finalInputs[i] += this.hiddenOutputs[j] * this.weightsHO[j][i];
}
this.finalInputs[i] += this.biasO[i];
}
this.outputs = this.finalInputs.map(x => this._sigmoid(x));
return this.outputs;
}
train(input, target) {
this.forward(input);
// Output layer error
const outputErrors = [];
for (let i = 0; i < this.outputSize; i++) {
outputErrors[i] = (target[i] - this.outputs[i]) * this._sigmoidDerivative(this.outputs[i]);
}
// Hidden layer error
const hiddenErrors = [];
for (let i = 0; i < this.hiddenSize; i++) {
let error = 0;
for (let j = 0; j < this.outputSize; j++) {
error += outputErrors[j] * this.weightsHO[i][j];
}
hiddenErrors[i] = error * this._sigmoidDerivative(this.hiddenOutputs[i]);
}
// Update weights
for (let i = 0; i < this.hiddenSize; i++) {
for (let j = 0; j < this.outputSize; j++) {
this.weightsHO[i][j] += this.learningRate * outputErrors[j] * this.hiddenOutputs[i];
}
}
for (let i = 0; i < this.inputSize; i++) {
for (let j = 0; j < this.hiddenSize; j++) {
this.weightsIH[i][j] += this.learningRate * hiddenErrors[j] * input[i];
}
}
return this.outputs;
}
toJSON() {
return {
weightsIH: this.weightsIH,
weightsHO: this.weightsHO,
biasH: this.biasH,
biasO: this.biasO
};
}
fromJSON(json) {
if (!json) return;
if (json.weightsIH) this.weightsIH = json.weightsIH;
if (json.weightsHO) this.weightsHO = json.weightsHO;
if (json.biasH) this.biasH = json.biasH;
if (json.biasO) this.biasO = json.biasO;
}
}
module.exports = SimpleNeuralNetwork;