-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNetwork.cpp
More file actions
165 lines (152 loc) · 4.95 KB
/
Copy pathNetwork.cpp
File metadata and controls
165 lines (152 loc) · 4.95 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
#include "Network.h"
#include <stdexcept>
#include <fstream>
#include <string>
#include <thread>
#include <iostream>
#include "MathNN.h"
Network::Network(int inputLayerSize, int hiddenLayersCount, int hiddenLayerSize, int outputLayerSize) {
Dense* inputLayer = new Dense(inputLayerSize, true);
layers.push_back(inputLayer);
Dense* layer = inputLayer;
for (unsigned int i = 0; i < hiddenLayersCount; i++) {
layer = new Dense(hiddenLayerSize, layer->getActivations());
layers.push_back(layer);
}
layer = new Dense(outputLayerSize, layer->getActivations());
layers.push_back(layer);
outAct = new OutputAct(outputLayerSize, layer->getActivations());
}
void Network::evaluate() {
v2d prediction = this->predict(testData);
int correct = 0;
float avgConfidence = 0.f;
for (unsigned int j = 0; j < prediction[0].size(); j++) {
float max = 0.f;
int maxIx = 0,
correctIx = 0;
for (unsigned int i = 0; i < prediction.size(); i++) {
if (prediction[i][j] > max) {
max = prediction[i][j];
maxIx = i;
}
if ((*testLabels)[i][j] == 1.f) {
correctIx = i;
}
}
if (maxIx == correctIx) {
correct++;
avgConfidence += prediction[maxIx][j];
}
}
avgConfidence /= prediction[0].size();
float accuracy = (float) correct / prediction[0].size();
std::ofstream file(evaluationFile, std::ios_base::app);
file << std::to_string(epoch) + ", " + std::to_string(accuracy) + ", " + std::to_string(avgConfidence) + "\n";
std::cout << "epoch " << epoch << ", accuracy=" << accuracy << ", confidence=" << avgConfidence << std::endl;
file.close();
}
void Network::addHiddenLayer(int size) {
Dense* prevHiddenLayer = layers[layers.size() - 2];
Dense* layer = new Dense(size, prevHiddenLayer->getActivations());
auto itPos = layers.begin() + layers.size() - 1;
layers.insert(itPos, layer);
layers[layers.size() - 1]->setDownstrean(layer->getActivations());
}
float Network::train(v2d* batch, v2d* labels, bool saveError, std::string filename) { //batch = n(l) x batch_size
v2d prediction = predict(batch);
if (labels->size() != prediction.size() || (*labels)[0].size() != prediction[0].size()) {
throw std::invalid_argument("label dimensions unequal to prediction dimensions");
}
v2d gradient = v2d(prediction.size(), v1d(prediction[0].size()));
float avgError = 0;
if (this->loss == Loss::crossEntropy) {
for (unsigned int j = 0; j < prediction[0].size(); j++) {
float layerError = 0;
for (unsigned int i = 0; i < prediction.size(); i++) {
layerError += (*labels)[i][j] * log(prediction[i][j]);
gradient[i][j] = (-1) * (*labels)[i][j] / prediction[i][j];
}
layerError *= -1;
avgError += layerError;
}
avgError /= prediction[0].size();
} else if (this->loss == Loss::meanSquared) {
for (unsigned int j = 0; j < prediction[0].size(); j++) {
for (unsigned int i = 0; i < prediction.size(); i++) {
gradient[i][j] += prediction[i][j] - (*labels)[i][j];
avgError += pow(prediction[i][j] - (*labels)[i][j], 2);
}
}
avgError /= prediction.size() * prediction[0].size();
}
outAct->setUpstream(&gradient);
outAct->backward(labels);
std::vector<std::thread*> threads = std::vector<std::thread*>();
for (unsigned int i = layers.size() - 1; i >= 1; i--) {
threads.push_back(layers[i]->backward());
}
for (unsigned int i = 0; i < threads.size(); i++) {
(*threads[i]).join();
delete threads[i];
}
epoch++;
if (saveError) {
std::ofstream errorFile(filename, std::ios_base::app);
errorFile << std::to_string(epoch) + ", " + std::to_string(avgError) + "\n";
errorFile.close();
}
this->evaluate();
return avgError;
}
v1d Network::predict(v1d* input) {
v2d twoDimensional = v2d(1, v1d(*input));
twoDimensional = MathNN::transpose(&twoDimensional);
v2d result = predict(&twoDimensional);
result = MathNN::transpose(&result);
return result[0];
}
v2d Network::predict(v2d* input) {
layers[0]->setDownstrean(input);
for (unsigned int i = 0; i < layers.size(); i++) {
layers[i]->forward();
}
outAct->forward();
v2d* prediction = outAct->getActivations();
return *prediction;
}
void Network::setTestConfig(v2d* testData, v2d* labels, std::string filename) {
this->testData = testData;
this->testLabels = labels;
this->evaluationFile = filename;
}
void Network::setActivationFct(Fct fct) {
this->actFct = fct;
}
void Network::initialise() {
Dense* nextLayer = layers[layers.size() - 1];
nextLayer->setUpstream(outAct->getGradient());
for (unsigned int i = layers.size() - 2; i >= 1; i--) {
nextLayer->initialise(actFct);
layers[i]->setUpstream(nextLayer->getGradient());
nextLayer = layers[i];
}
nextLayer->initialise(actFct);
this->setLearningRate(this->learningRate);
outAct->setLoss(this->loss);
}
void Network::setLearningRate(float eta) {
this->learningRate = eta;
for (unsigned int i = 0; i < layers.size(); i++) {
layers[i]->setLearningRate(eta);
}
}
void Network::setLoss(Loss loss) {
this->loss = loss;
}
Network::~Network() {
for (unsigned int i = 0; i < layers.size(); i++) {
delete layers[i];
}
delete outAct;
}