-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathNeuron.java
146 lines (120 loc) · 3.57 KB
/
Neuron.java
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
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Random;
public class Neuron implements Serializable {
private ArrayList<Double> weights;
private double bias;
Activation activation;
public ArrayList<Double> getWeights() {
return new ArrayList<Double>(weights);
}
public void setWeights(ArrayList<Double> w) {
weights = new ArrayList<Double>(w);
}
public double getBias() {
return bias;
}
public void setBias(double newB) {
bias = newB;
}
public Neuron(Activation activation, int numInputs) {
this.activation = activation;
this.bias = (Math.random() * 2) - 1;
weights = new ArrayList<Double>();
for (int i = 0; i < numInputs; i++) {
weights.add((Math.random() * 2) - 1);
}
}
public Neuron() {
}
/**
* Returns the output of the neuron given the appropriate inputs. First it multiplies each
* input to the corresponding weight, then it sums that value and runs it through an activation
* function so that the output is low and non-linear.
*
* @author Arjun
* @param inputs is an ArrayList
* @return output of the neuron
*/
public double propagate(ArrayList<Double> inputs) {
if (inputs.size() != weights.size())
throw new Error("Input size given is not assigned");
double sum = 0;
for (int i = 0; i < inputs.size(); i++) {
sum += inputs.get(i) * weights.get(i);
}
sum += bias;
if (activation == Activation.Sigmoid)
sum = (1 / (1 + Math.pow(Math.E, (-1 * sum))));
else if (activation == Activation.ReLu)
sum = Math.max(0.01 * sum, sum);
else if (activation == Activation.Tanh)
sum = 2 / (1 + Math.pow(Math.E, (-2 * sum)));
return sum;
}
public static void print(ArrayList<Integer> arrayList) {
for (Integer a : arrayList) {
System.out.print(a.intValue()+", ");
}
System.out.print("\n");
}
/**
* Creates offspring of two parent neurons analogous to meiosis. First it selects one of the two
* parents randomly. Then it copies a random section of the parent's weights and adds it to the
* offspring's weights.
*
* @author Arjun
* @param n1 First Parent Neuron
* @param n2 Second Parent Neuron
* @return offspring of the two neurons
*/
public static Neuron reproduce(Neuron n1, Neuron n2, double mutationRate) {
if (n1.getWeights().size() != n2.getWeights().size())
throw new RuntimeException("Neuron input sizes are not same while trying to reproduce");
Neuron n = new Neuron();
ArrayList<Double> newWeights = n1.getWeights();
int lastRandom = 0;
while (true) {
int rand = randomNum(lastRandom, n1.getWeights().size()-1);
for (int i=lastRandom; i<rand; i++) {
double num = Math.random();
if (num < mutationRate) {
newWeights.set(i, Math.random());
}
else if (num < 0.5) {
newWeights.set(i, n2.getWeights().get(i)); // need to clone
}
else {
newWeights.set(i, n1.getWeights().get(i));
}
}
if (rand >= n1.getWeights().size()-1) {
break;
}
}
double num = Math.random();
if (num < mutationRate)
n.setBias(Math.random());
else if (num < 0.5)
n.setBias(n1.getBias());
else
n.setBias(n2.getBias());
n.setWeights(newWeights);
return n;
}
private static int randomNum(int min, int max) {
Random r = new Random();
return r.nextInt((max - min) + 1) + min;
}
@SuppressWarnings("null")
public double compareTo(Neuron n) {
double sum = 0.0;
if (n.getWeights().size() != weights.size())
return (Double) null;
for (int i=0; i<n.getWeights().size(); i++) {
sum += n.getWeights().get(i) - weights.get(i);
}
sum += bias - n.getBias();
return sum;
}
}