Running the XOR example present on the website, the application compiles and it returns me the expected results. You can see here the output generated by a typical run of the software:
Iteration: 0 Error: 0.255437
Iteration: 2000 Error: 0.00587259
Iteration: 4000 Error: 0.00165885
Iteration: 6000 Error: 0.000926289
Iteration: 8000 Error: 0.000634771
Iteration: 10000 Error: 0.000480023
Iteration: 12000 Error: 0.000384738
Iteration: 14000 Error: 0.000320382
Iteration: 16000 Error: 0.000274212
Iteration: 18000 Error: 0.00023935
Iteration: 20000 Error: 0.000212056
Iteration: 22000 Error: 0.000190297
Iteration: 24000 Error: 0.000172567
Iteration: 26000 Error: 0.000157842
Iteration: 28000 Error: 0.000145477
Iteration: 30000 Error: 0.000134899
Iteration: 32000 Error: 0.000125788
Iteration: 34000 Error: 0.000117868
Iteration: 36000 Error: 0.000110822
Iteration: 38000 Error: 0.000104457
Iteration: 40000 Error: 9.87694e-05
Iteration: 42000 Error: 9.36685e-05
Iteration: 44000 Error: 8.88934e-05
Iteration: 46000 Error: 8.45752e-05
Iteration: 48000 Error: 8.06261e-05
Iteration: 50000 Error: 7.70264e-05
Inputs: 0 0 - Target output: 0 - Produced output: 0.00407879
Inputs: 0 1 - Target output: 1 - Produced output: 0.992076
Inputs: 1 0 - Target output: 1 - Produced output: 0.992016
Inputs: 1 1 - Target output: 0 - Produced output: 0.0128427
The things become weird if I try to modify the activation function for the hidden and output clusters, from SigmoidFunction to ScaledSigmoidFunction. Those are the results generated:
Iteration: 0 Error: 0.273519
Iteration: 2000 Error: 2.5
Iteration: 4000 Error: 2.5
Iteration: 6000 Error: 2.5
Iteration: 8000 Error: 2.5
Iteration: 10000 Error: 2.5
Iteration: 12000 Error: 2.5
Iteration: 14000 Error: 2.5
Iteration: 16000 Error: 2.5
Iteration: 18000 Error: 2.5
Iteration: 20000 Error: 2.5
Iteration: 22000 Error: 2.5
Iteration: 24000 Error: 2.5
Iteration: 26000 Error: 2.5
Iteration: 28000 Error: 2.5
Iteration: 30000 Error: 2.5
Iteration: 32000 Error: 2.5
Iteration: 34000 Error: 2.5
Iteration: 36000 Error: 2.5
Iteration: 38000 Error: 2.5
Iteration: 40000 Error: 2.5
Iteration: 42000 Error: 2.5
Iteration: 44000 Error: 2.5
Iteration: 46000 Error: 2.5
Iteration: 48000 Error: 2.5
Iteration: 50000 Error: 2.5
Inputs: 0 0 - Target output: 0 - Produced output: -1
Inputs: 0 1 - Target output: 1 - Produced output: -1
Inputs: 1 0 - Target output: 1 - Produced output: -1
Inputs: 1 1 - Target output: 0 - Produced output: -1
Here's the complete code:
- Code: Select all
// Input-output includes
#include <iostream>
#include <fstream>
// NNFW includes
#include "nnfw/nnfw.h"
#include "nnfw/fakecluster.h"
#include "nnfw/biasedcluster.h"
#include "nnfw/dotlinker.h"
#include "nnfw/liboutputfunctions.h"
#include "nnfw/backpropagationalgo.h"
#include "nnfw/random.h"
// Define the network blocks
nnfw::FakeCluster *inputCluster;
nnfw::BiasedCluster *hiddenCluster, *outputCluster;
nnfw::DotLinker *inputToHiddenLinker, *hiddenToOutputLinker;
nnfw::BaseNeuralNet *NN;
nnfw::UpdatableVec nnUpdateOrder, bpOrder;
nnfw::BackPropagationAlgo *bp;
// Main
int main (int argc, char * const argv[]) {
// Initialize the randomizer
nnfw::Random::setSeed(time(0));
// Create the network
NN = new nnfw::BaseNeuralNet();
inputCluster = new nnfw::FakeCluster(2, "CL_inputCluster");
hiddenCluster = new nnfw::BiasedCluster(4, "CL_hiddenCluster");
outputCluster = new nnfw::BiasedCluster(1, "CL_outputCluster");
inputCluster->setFunction(nnfw::IdentityFunction());
hiddenCluster->setFunction(nnfw::ScaledSigmoidFunction(1.0, -1.0, 1.0));
outputCluster->setFunction(nnfw::ScaledSigmoidFunction(1.0, -1.0, 1.0));
//hiddenCluster->setFunction(nnfw::SigmoidFunction(1.0));
//outputCluster->setFunction(nnfw::SigmoidFunction(1.0));
inputToHiddenLinker = new nnfw::DotLinker(inputCluster, hiddenCluster);
hiddenToOutputLinker = new nnfw::DotLinker(hiddenCluster, outputCluster);
NN->addCluster(inputCluster, true, false);
NN->addCluster(hiddenCluster, false, false);
NN->addCluster(outputCluster, false, true);
NN->addLinker(inputToHiddenLinker);
NN->addLinker(hiddenToOutputLinker);
nnUpdateOrder << inputCluster << inputToHiddenLinker << hiddenCluster << hiddenToOutputLinker << outputCluster;
NN->setOrder(nnUpdateOrder);
// Randomize
NN->randomize(-1.0, 1.0);
// Create the back-propagation algorithm
bpOrder << outputCluster << hiddenToOutputLinker << hiddenCluster << inputToHiddenLinker << inputCluster;
bp = new nnfw::BackPropagationAlgo(NN, bpOrder, 0.2); // the third parameter is the learning rate (LR)
// Set-up the momentum (typically 0.8 according to the literature)
bp->setMomentum(0.8);
bp->enableMomentum();
// Define the teaching input (called learning set in NNFW)
nnfw::PatternSet learningSet(4); // 4 elements
// First element: 0,0 -> 1
learningSet[0].setInputsOf(inputCluster, nnfw::RealVec() << 0.0 << 0.0);
learningSet[0].setOutputsOf(outputCluster, nnfw::RealVec() << 0.0);
// Second element: 0,1 -> 1
learningSet[1].setInputsOf(inputCluster, nnfw::RealVec() << 0.0 << 1.0);
learningSet[1].setOutputsOf(outputCluster, nnfw::RealVec() << 1.0);
// Third element: 1,0 -> 1
learningSet[2].setInputsOf(inputCluster, nnfw::RealVec() << 1.0 << 0.0);
learningSet[2].setOutputsOf(outputCluster, nnfw::RealVec() << 1.0);
// Fourth element: 1,1 -> 0
learningSet[3].setInputsOf(inputCluster, nnfw::RealVec() << 1.0 << 1.0);
learningSet[3].setOutputsOf(outputCluster, nnfw::RealVec() << 0.0);
// Create and open the file where to write the error rate
std::ofstream errorFileStream("/Users/fruini/Desktop/error.txt", std::ios::out|std::ios::app|std::ios::ate);
// Apply the BP algorithm for 50,000 iterations
int i;
for (i=0; i<50000; i++) {
bp->learnOnSet(learningSet);
errorFileStream << bp->calculateMSEOnSet(learningSet) << std::endl;
if (i%2000 == 0) std::cout << "Iteration: " << i << "\t\tError: " << bp->calculateMSEOnSet(learningSet) << std::endl;
}
std::cout << "Iteration: " << i << "\t\tError: " << bp->calculateMSEOnSet(learningSet) << std::endl;
// Explicitely compare the outputs produced by the network with those contained into the learning set
for (int i=0; i<4; i++) {
inputCluster->inputs() = learningSet[i].inputsOf(inputCluster);
NN->step();
std::cout << "Inputs: " << inputCluster->getOutput(0) << "\t" << inputCluster->getOutput(1) << " - Target output: " << learningSet[i].outputsOf(outputCluster)[0] << " - Produced output: " << outputCluster->getOutput(0) << std::endl;
}
// Close the file previously opened
errorFileStream.close();
// End of the application
return 0;
}
