// 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" using namespace chrono; 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; double lowestError = 10; Mat V0l, W0l; Mat V1, W1; cout << endl << "Starting neural training, this might take a while..." << endl; int runs = 0; milliseconds lasttime = timestamp(); milliseconds starttime = timestamp(); bool shown = false; 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); if (sumSqrDiffError < lowestError) { lowestError = sumSqrDiffError; V0l = V0; W0l = W0; } V0 = V1; W0 = W1; } runs++; if (timestamp() > lasttime + milliseconds(15000) && !shown) { cout << "We are still working on it, hold on..." << endl; shown = true; } if (runs % 500 == 0) { shown = false; auto runtime = (timestamp() - lasttime) / 1000; cout << "Completed " << runs << " runs, still working on it.. (" << sumSqrDiffError << ")(" << runtime.count() << "s)" << endl; lasttime = timestamp(); } } V0 = V0l; W0 = W0l; auto totalduration = (timestamp() - starttime) / 1000; cout << "Training finished in " << runs << " runs, it took " << totalduration.count() << "s" << endl; cout << "The lowest error rate was " << lowestError << ", we are savind the matching factors" << 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() { FileStorage fs("factors.yml", FileStorage::WRITE); fs << "W0" << W0 << "V0" << V0; fs.release(); FileStorage fs2("classes.yml", FileStorage::WRITE); fs2 << "classes" << "{:"; for (pair 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(idx, value)); } cout << endl << "Available classes: " << endl; for (pair 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 p : classes) { if (p.second == name) { class_mat(p.first, ref); return; } } classes.insert(pair(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(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) + "%"; } milliseconds NeuralNetwork::timestamp() { milliseconds ms = duration_cast( system_clock::now().time_since_epoch()); return ms; }