-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
204 lines (160 loc) · 5.06 KB
/
main.go
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package main
import (
"bufio"
"encoding/csv"
"fmt"
"io"
"log"
"math"
"math/rand"
"os"
"strconv"
)
// sigmoid Sigmoid activation function: f(x) = 1 / (1 + e^(-x))
func sigmoid(x float64) float64 {
return 1 / (1 + math.Exp(-x))
}
// derivSigmoid Derivative of sigmoid: f'(x) = f(x) * (1 - f(x))
func derivSigmoid(x float64) float64 {
fx := sigmoid(x)
return fx * (1 - fx)
}
// mse Mean Squared Error
func mse(inputs []Input, predictions []float64) float64 {
len := len(inputs)
var total float64
for i := 0; i < len; i++ {
total += math.Pow(inputs[i].Expected-predictions[i], 2)
}
return total / float64(len)
}
// ApplyInputToNeuron returns activation and result
func ApplyInputToNeuron(i Input, n Neuron) (float64, float64) {
result := n.Weight1*i.One + n.Weight2*i.Two + n.Bias
activation := sigmoid(result)
return activation, result
}
// Predict generates the prediction
func Predict(n1, n2, n3 Neuron, i Input) float64 {
n1Activation, _ := ApplyInputToNeuron(i, n1)
n2Activation, _ := ApplyInputToNeuron(i, n2)
n3Activation, _ := ApplyInputToNeuron(Input{n1Activation, n2Activation, 0.0}, n3)
return n3Activation
}
// Input represents a input
type Input struct {
One float64
Two float64
Expected float64
}
// Neuron represents a single neuron
type Neuron struct {
Weight1 float64
Weight2 float64
Bias float64
}
// GenNeuron returns a new randomized neuron
func GenNeuron() Neuron {
return Neuron{rand.NormFloat64(), rand.NormFloat64(), rand.NormFloat64()}
}
// GenTrainingData generates the training Data
func GenTrainingData() []Input {
var inputs []Input
csvFile, _ := os.Open("inputs.csv")
reader := csv.NewReader(bufio.NewReader(csvFile))
tWeight := 0.0
tHeight := 0.0
for {
line, error := reader.Read()
if error == io.EOF {
break
} else if error != nil {
log.Fatal(error)
}
expected := 1.0
if line[0] == "Male" {
expected = 0.0
}
weight, _ := strconv.ParseFloat(line[2], 64)
height, _ := strconv.ParseFloat(line[1], 64)
tWeight += weight
tHeight += height
inputs = append(inputs, Input{
One: weight,
Two: height,
Expected: expected,
})
}
avgHeight := tHeight / float64(len(inputs))
avgWeight := tWeight / float64(len(inputs))
for i := range inputs {
inputs[i].One -= avgWeight
inputs[i].Two -= avgHeight
}
return inputs
}
func main() {
n1 := GenNeuron()
n2 := GenNeuron()
n3 := GenNeuron()
inputs := GenTrainingData()
learnRate := 0.0001
epochs := 4000
lastLoss := 0.0
lastLossSetValue := 0.0
lastLossSet := false
for i := 1; i <= epochs; i++ {
for _, input := range inputs {
n1Activation, n1Result := ApplyInputToNeuron(input, n1)
n2Activation, n2Result := ApplyInputToNeuron(input, n2)
n3Activation, n3Result := ApplyInputToNeuron(Input{n1Activation, n2Activation, 0.0}, n3)
prediction := n3Activation
pLpPrediction := -2 * (input.Expected - prediction)
// Neuron 3 (output)
pPredictionpW5 := n1Activation * derivSigmoid(n3Result)
pPredictionpW6 := n2Activation * derivSigmoid(n3Result)
pPredictionpB3 := derivSigmoid(n3Result)
pPredictionpN1Activation := n3.Weight1 * derivSigmoid(n3Result)
pPredictionpN2Activation := n3.Weight2 * derivSigmoid(n3Result)
// Neuron 1
pN1ActivationpN1W1 := input.One * derivSigmoid(n1Result)
pN1ActivationpN1W2 := input.Two * derivSigmoid(n1Result)
pN1ActivationpN1B1 := derivSigmoid(n1Result)
// Neuron 2
pN2ActivationpW3 := input.One * derivSigmoid(n2Result)
pN2ActivationpW4 := input.Two * derivSigmoid(n2Result)
pN2ActivationpB2 := derivSigmoid(n2Result)
n1.Weight1 -= learnRate * pLpPrediction * pPredictionpN1Activation * pN1ActivationpN1W1
n1.Weight2 -= learnRate * pLpPrediction * pPredictionpN1Activation * pN1ActivationpN1W2
n1.Bias -= learnRate * pLpPrediction * pPredictionpN1Activation * pN1ActivationpN1B1
n2.Weight1 -= learnRate * pLpPrediction * pPredictionpN2Activation * pN2ActivationpW3
n2.Weight2 -= learnRate * pLpPrediction * pPredictionpN2Activation * pN2ActivationpW4
n2.Bias -= learnRate * pLpPrediction * pPredictionpN2Activation * pN2ActivationpB2
n3.Weight1 -= learnRate * pLpPrediction * pPredictionpW5
n3.Weight2 -= learnRate * pLpPrediction * pPredictionpW6
n3.Bias -= learnRate * pLpPrediction * pPredictionpB3
}
var dPredictions []float64
for _, input := range inputs {
dPredictions = append(dPredictions, Predict(n1, n2, n3, input))
}
loss := mse(inputs, dPredictions)
if !lastLossSet {
fmt.Printf("Epoch %d loss %.4f\n", i, loss)
lastLossSetValue = loss
lastLossSet = true
}
if lastLossSetValue/loss >= 2.0 {
fmt.Printf("Epoch %d loss %.4f\n", i, loss)
lastLossSetValue = loss
}
lastLoss = loss
}
fmt.Printf("Final Epoch %d has %.2f%% accuracy!\n", epochs, (1.0-lastLoss)*100)
a1 := Predict(n1, n2, n3, Input{136.6870, 69.6850, +1.0})
a2 := Predict(n1, n2, n3, Input{244.7130, 72.0472, +0.0})
a3 := Predict(n1, n2, n3, Input{141.0960, 66.5354, +0.0})
fmt.Printf("Fabiana WomanIndex: %.4f%%\n", a1*100)
fmt.Printf("Guilherme WomanIndex: %.4f%%\n", a2*100)
fmt.Printf("Rosely WomanIndex: %.4f%%\n", a3*100)
}