222 lines
5.0 KiB
C++
222 lines
5.0 KiB
C++
// Demo: Training of a Neural Network / Back-Propagation algorithm
|
|
// Jan Oostindie, Avans Hogeschool, dd 6-12-2016
|
|
// email: jac.oostindie@avans.nl
|
|
|
|
#include "NeuralNetwork.h"
|
|
|
|
NeuralNetwork::NeuralNetwork()
|
|
{
|
|
V0 = Mat();
|
|
W0 = Mat();
|
|
}
|
|
|
|
NeuralNetwork::~NeuralNetwork()
|
|
{
|
|
}
|
|
|
|
Mat NeuralNetwork::Train(Mat& ITset, Mat& OTset)
|
|
{
|
|
// V0, W0 : weightfactor matrices
|
|
// dV0, dW0 : weightfactor correction matrices
|
|
Mat dW0, dV0;
|
|
|
|
// default number of hiddenNeurons. The definite number is user input
|
|
// inputNeurons and outputNeurons are implicitly determined via
|
|
// the trainingset, i.e.: inputNeurons = ITset.cols ; outputNeurons = OTset.cols;
|
|
int hiddenNeurons = 8;
|
|
|
|
//loadTrainingSet1(ITset, OTset);
|
|
initializeBPN(ITset.cols, hiddenNeurons, OTset.cols, V0, dV0, W0, dW0);
|
|
//testBPN(ITset, OTset, V0, dV0, W0, dW0);
|
|
|
|
|
|
// IT: current training input of the inputlayer
|
|
// OT: desired training output of the BPN
|
|
// OH: output of the hiddenlayer
|
|
// OO: output of the outputlayer
|
|
Mat IT, OT, OH, OO;
|
|
|
|
// outputError0: error on output for the current input and weighfactors V0, W0
|
|
// outputError1: error on output for the current input and new calculated
|
|
// weighfactors, i.e. V1, W1
|
|
double outputError0, outputError1, sumSqrDiffError = MAX_OUTPUT_ERROR + 1;
|
|
Mat V1, W1;
|
|
|
|
cout << endl << "Starting neural training..." << endl;
|
|
|
|
int runs = 0;
|
|
while ((sumSqrDiffError > MAX_OUTPUT_ERROR) && (runs < MAXRUNS)) {
|
|
|
|
sumSqrDiffError = 0;
|
|
|
|
for (int inputSetRowNr = 0; inputSetRowNr < ITset.rows; inputSetRowNr++) {
|
|
|
|
IT = transpose(getRow(ITset, inputSetRowNr));
|
|
|
|
OT = transpose(getRow(OTset, inputSetRowNr));
|
|
|
|
calculateOutputHiddenLayer(IT, V0, OH);
|
|
|
|
calculateOutputBPN(OH, W0, OO);
|
|
|
|
adaptVW(OT, OO, OH, IT, W0, dW0, V0, dV0, W1, V1);
|
|
|
|
calculateOutputBPNError(OO, OT, outputError0);
|
|
|
|
calculateOutputBPNError(BPN(IT, V1, W1), OT, outputError1);
|
|
|
|
sumSqrDiffError += (outputError1 - outputError0) * (outputError1 - outputError0);
|
|
|
|
V0 = V1;
|
|
W0 = W1;
|
|
}
|
|
runs++;
|
|
|
|
if (runs % 1000 == 0)
|
|
cout << "Completed " << runs << " runs, still working on it.. (" << sumSqrDiffError << ")" << endl;
|
|
}
|
|
|
|
cout << "Training complete in " << runs << " runs" << endl;
|
|
|
|
Mat inputVectorTrainingSet, outputVectorTrainingSet, outputVectorBPN;
|
|
|
|
// druk voor elke input vector uit de trainingset de output vector uit trainingset af
|
|
// tezamen met de output vector die het getrainde BPN (zie V0, W0) genereerd bij de
|
|
// betreffende input vector.
|
|
for (int row = 0; row < ITset.rows; row++) {
|
|
|
|
// haal volgende inputvector op uit de training set
|
|
inputVectorTrainingSet = transpose(getRow(ITset, row));
|
|
|
|
// haal bijbehorende outputvector op uit de training set
|
|
outputVectorTrainingSet = transpose(getRow(OTset, row));
|
|
|
|
// bepaal de outputvector die het getrainde BPN oplevert
|
|
// bij de inputvector uit de trainingset
|
|
outputVectorBPN = BPN(inputVectorTrainingSet, V0, W0);
|
|
}
|
|
|
|
write();
|
|
|
|
return outputVectorBPN;
|
|
}
|
|
|
|
void NeuralNetwork::Predict(Mat& ITset, string& name)
|
|
{
|
|
Mat output;
|
|
output = transpose(BPN(ITset, V0, W0));
|
|
|
|
mat_class(output, name);
|
|
}
|
|
|
|
void NeuralNetwork::Read()
|
|
{
|
|
load();
|
|
}
|
|
|
|
void NeuralNetwork::write()
|
|
{
|
|
for (pair<int, string> p : classes)
|
|
cout << p.first << " - " << p.second << endl;
|
|
|
|
FileStorage fs("factors.yml", FileStorage::WRITE);
|
|
fs << "W0" << W0 << "V0" << V0;
|
|
fs.release();
|
|
|
|
FileStorage fs2("classes.yml", FileStorage::WRITE);
|
|
|
|
fs2 << "classes" << "{:";
|
|
|
|
for (pair<int, string> p : classes)
|
|
{
|
|
string el = "e" + to_string(p.first);
|
|
fs2 << el << p.second;
|
|
}
|
|
|
|
fs2 << "}";
|
|
|
|
fs2.release();
|
|
}
|
|
|
|
void NeuralNetwork::load()
|
|
{
|
|
FileStorage fs("factors.yml", FileStorage::READ);
|
|
|
|
fs["W0"] >> W0;
|
|
fs["V0"] >> V0;
|
|
|
|
fs.release();
|
|
|
|
FileStorage fs2("classes.yml", FileStorage::READ);
|
|
|
|
classes.clear();
|
|
|
|
FileNode cls = fs2["classes"];
|
|
FileNodeIterator it = cls.begin(), it_end = cls.end();
|
|
int idx = 0;
|
|
|
|
// iterate through a sequence using FileNodeIterator
|
|
for (; it != it_end; ++it, idx++)
|
|
{
|
|
cv::FileNode item = *it;
|
|
std::string key = item.name();
|
|
string value = (string)item;
|
|
|
|
classes.insert(pair<int, string>(idx, value));
|
|
}
|
|
|
|
cout << endl << "Available classes: " << endl;
|
|
|
|
for (pair<int, string> p : classes)
|
|
cout << p.first << " - " << p.second << endl;
|
|
|
|
cout << endl;
|
|
|
|
fs2.release();
|
|
}
|
|
|
|
void NeuralNetwork::getClass(const string& name, Mat& ref)
|
|
{
|
|
save_class(name, ref);
|
|
}
|
|
|
|
void NeuralNetwork::save_class(const string& name, Mat& ref)
|
|
{
|
|
for (pair<int, string> p : classes)
|
|
{
|
|
if (p.second == name)
|
|
{
|
|
class_mat(p.first, ref);
|
|
return;
|
|
}
|
|
}
|
|
|
|
classes.insert(pair<int, string>(classidx, name));
|
|
class_mat(classidx, ref);
|
|
classidx++;
|
|
}
|
|
|
|
void NeuralNetwork::class_mat(int index, Mat& ref)
|
|
{
|
|
ref = cv::Mat::zeros(cv::Size(numclasses, 1), CV_32F);
|
|
ref.at<float>(index) = 1;
|
|
}
|
|
|
|
void NeuralNetwork::mat_class(Mat& ref, string& name)
|
|
{
|
|
double maxvalue = 0;
|
|
int index = 0;
|
|
|
|
for (int i = 0; i < ref.cols; i++)
|
|
{
|
|
double temp = getEntry(ref, 0, i);
|
|
|
|
if (temp > maxvalue)
|
|
{
|
|
maxvalue = temp;
|
|
index = i;
|
|
}
|
|
}
|
|
|
|
name = classes[index] + " " + to_string(maxvalue*100) + "%";
|
|
} |