Repository navigation
Expand file tree
/
Copy pathNetworkTrainer.java
More file actions
240 lines (207 loc) · 9.94 KB
/
Copy pathNetworkTrainer.java
File metadata and controls
240 lines (207 loc) · 9.94 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
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
* Authored by Bennett Liu on September 20th, 2019
*
* NetworkTrainer.java implements a trainer of the feed-forward multi-layer perceptron network defined in Network.java.
* Given a training set and training parameters, NetworkTrainer minimizes the error of the perceptron on the training set.
*
* Contains the following methods:
*
* Method | Description
* ------------------------|---------------------
* NetworkTrainer | A constructor for creating a Network, given a network and a training set of doubles.
* NetworkTrainer | A constructor for creating a Network, given a network and a training set of image inputs and double outputs.
* NetworkTrainer | A constructor for creating a Network, given a network and a training set of images.
* calcError | Calculates the total error for the whole training set.
* train | Runs training steps while certain conditions are met.
* adaptiveImprove | Runs adaptive training
* printResults | Prints information on each training case.
* getNetwork | Returns the current network.
*/
import java.util.*;
public class NetworkTrainer
{
Network network; // The network to be trained
int trainingCases; // The number of training cases
double trainingInputs[][]; // The inputs to be trained on
double trainingOutputs[][]; // The outputs to be trained on
double error; // The network's current error
double trainingFactor; // The training factor (lambda)
double adaptConstant; // The adaptive factor, used to modify lambda
/*
* The Network constructor creates a new NetworkTrainer, given a network and double training inputs/outputs.
*/
public NetworkTrainer(Network initialNetwork, double inputs[][], double outputs[][])
{
network = initialNetwork;
trainingCases = inputs.length;
trainingInputs = inputs;
trainingOutputs = outputs;
error = calcError();
return;
}
/*
* The Network constructor creates a new NetworkTrainer, given a network, image file name training inputs, and double training outputs.
*/
public NetworkTrainer(Network initialNetwork, String inputFilenames[], double outputs[][])
{
PelGetter pelGetter = new PelGetter();
network = initialNetwork;
trainingCases = inputFilenames.length;
trainingInputs = new double[trainingCases][network.inputs];
for (int i = 0; i < trainingCases; i++)
{
trainingInputs[i] = pelGetter.getPels(inputFilenames[i]);
}
trainingOutputs = outputs;
error = calcError();
return;
}
/*
* The Network constructor creates a new NetworkTrainer, given a network and image file name training inputs/outputs.
*/
public NetworkTrainer(Network initialNetwork, String inputFilenames[], String outputFilenames[])
{
PelGetter pelGetter = new PelGetter();
network = initialNetwork;
trainingCases = inputFilenames.length;
trainingInputs = new double[trainingCases][network.inputs];
trainingOutputs = new double[trainingCases][network.inputs];
for (int i = 0; i < trainingCases; i++)
{
trainingInputs[i] = pelGetter.getPels(inputFilenames[i]);
trainingOutputs[i] = pelGetter.getPels(outputFilenames[i]);
}
error = calcError();
return;
}
/*
* calcError returns the total error when the network is run for all input-output pairs.
*/
private double calcError()
{
double totalError = 0.0;
double diff;
for (int i = 0; i < trainingCases; i++)
{
double[] results = network.eval(trainingInputs[i]); // Get results
for (int j = 0; j < network.outputs; j++) // Calculate error for given training case
{
diff = (trainingOutputs[i][j] - results[j]);
totalError += (diff * diff);
}
}
totalError /= 2.0; // This halving of error is specified in design doc 1.
return totalError;
} // private double calcError()
/*
* train runs multiple steps while some conditions are still met.
*/
public void train(double initLambda, double adaptConst, int maxSteps, double minError, double minLambda, int updatePeriod, int writePeriod)
{
trainingFactor = initLambda; // Set training factors
adaptConstant = adaptConst;
int step = 0;
boolean improved = true;
while ((step < maxSteps) && (error >= minError) && (trainingFactor >= minLambda) && (adaptConstant != 1 || improved))
{
step++;
improved = adaptiveImprove(minLambda); // Run an adaptive step and save the result
if ((updatePeriod > 0) && ((step % updatePeriod) == 0)) // Saves and prints output every updatePeriod steps
printResults();
if ((writePeriod > 0) && ((step % writePeriod) == 0)) // Saves and prints output every updatePeriod steps
network.exportNet("logs/" + (new Date()).getTime() + ".txt");
} // while ((step < maxSteps) && (error >= minError) && (trainingFactor >= minLambda) && (adaptConstant != 1 || improved))
System.out.println(); // Print the reason(s) for termination
System.out.println(String.format("Terminated after %d steps", step));
if (step >= maxSteps)
System.out.println(String.format("Steps passed limit of %d", maxSteps));
if (error < minError)
System.out.println(String.format("Error fell below %.15f", minError));
if (adaptConstant == 1 && !improved)
System.out.println("Was not able to improve error.");
if (trainingFactor < minLambda)
System.out.println(String.format("Training factor (lambda) fell below %.15f", minLambda));
System.out.println();
} // public void train(double initLambda, double adaptConst, int maxSteps, double minError, double minLambda, int updatePeriod, int writePeriod)
/*
* adaptiveImprove runs a single adaptive training step for each training case. It saves initial weights
* and attempts these steps simultaneously. If the step improves error, the training factor is increased,
* otherwise the weights are rolled back and training factor is decreased. Returns whether error was improved.
*/
private boolean adaptiveImprove(double minLambda)
{
boolean improved;
double newError = 0.0;
double oldWeights[][][] = new double[network.layers - 1][network.maxNodes][network.maxNodes];
for (int layer = 0; layer < network.layers - 1; layer++) // Save old weights in case of roll back
{
for (int i = 0; i < network.nodesInLayer[layer]; i++)
{
for (int j = 0; j < network.nodesInLayer[layer + 1]; j++)
{
oldWeights[layer][i][j] = network.weights[layer][i][j];
}
}
}
for (int trainingCase = 0; trainingCase < trainingCases; trainingCase++) // Improve for each training case
network.step(trainingInputs[trainingCase], trainingOutputs[trainingCase], trainingFactor);
newError = calcError(); // Calculate the new error
if (newError < error) // If steps improved error
{
error = newError; // Update error
trainingFactor *= adaptConstant; // Make a bigger step next time
improved = true;
}
else // If steps worsened error
{
network.setWeights(oldWeights); // Roll back weights
trainingFactor /= adaptConstant; // Make a smaller step next time
improved = false;
}
return improved; // Return whether the error improved
} // private boolean adaptiveImprove(double minLambda)
/*
* printResults prints the network's results for each input-output pair, the training factor, and total error.
*/
public void printResults()
{
System.out.println();
// for (int i = 0; i < trainingCases; i++) // For each training case
// {
// System.out.println(String.format("Case %d:", i + 1)); // Print the number
// System.out.println("Inputs:"); // Print the inputs
// for (int j = 0; j < network.inputs; j++)
// {
// System.out.print(String.format(" %.15f", trainingInputs[i][j]));
// }
// System.out.println();
// System.out.println("Results:"); // Calculate and print the network's outputs
// double results[] = network.eval(trainingInputs[i]);
// for (int j = 0; j < network.outputs; j++)
// {
// System.out.print(String.format(" %.15f", results[j]));
// }
// System.out.println();
// // PelGetter pelGetter = new PelGetter();
// // pelGetter.makeBMP(results, "_.bmp");
// System.out.println("Answers:"); // Calculate and print the correct outputs
// for (int j = 0; j < network.outputs; j++)
// {
// System.out.print(String.format(" %.15f", trainingOutputs[i][j]));
// }
// System.out.println();
// System.out.println();
// } // for (int i = 0; i < trainingCases; i++)
System.out.println(String.format("Lambda: %.15f", trainingFactor)); // Print the training factor
System.out.println(String.format("Total Error: %.15f", error)); // Print the total error
System.out.println();
return;
} // public void printResults()
/*
* getNetwork returns the current network.
*/
public Network getNetwork()
{
return network;
}
} // public class NetworkTrainer