Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) FANN example 2: solving the XOR problem

 

This example shows how FANN creates a neural network that learns to solve the XOR problem.

 

 

Operating system: Ubuntu 10.04 LTS Lucid Lynx

IDE: Qt Creator 2.0.0

Project type: GUI application

Compiler: G++ 4.4.1

Libraries used:

 

 

 

 

 

Qt project file

 

#-------------------------------------------------
#
# Project created by QtCreator 2010-08-12T16:54:00
#
#-------------------------------------------------
QT += core
QT -= gui
LIBS += -L/usr/local/lib -lfann
TARGET = CppFannExample2
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp

 

 

 

 

 

main.cpp

 

#include <algorithm>
#include <cassert>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

#include <floatfann.h>


//From http://www.richelbilderbeek.nl/CppFileExists.htm
bool FileExists(const std::string& filename)
{
  std::fstream f;
  f.open(filename.c_str(),std::ios::in);
  return f.is_open();
}

//From http://www.richelbilderbeek.nl/CppFileToVector.htm
const std::vector<std::string> FileToVector(const std::string& fileName)
{
  assert(FileExists(fileName)==true);
  std::vector<std::string> myVector;
  std::ifstream in(fileName.c_str());
  std::string myString;
  for (int i=0; !in.eof(); ++i)
  {
    std::getline(in,myString);
    myVector.push_back(myString);
  }
  return myVector;
}

//From http://www.richelbilderbeek.nl/CppCoutContainer.htm
template <class Container>
void CoutContainer(const Container& c)
{
  std::copy(c.begin(),c.end(),
    std::ostream_iterator<typename Container::value_type>(std::cout,"\n"));
}

//From http://www.richelbilderbeek.nl/CppSaveContainer.htm
template <class Container>
void SaveContainer(const Container& c, const std::string& filename)
{
  std::ofstream f(filename.c_str());
  std::copy(c.begin(),c.end(),std::ostream_iterator<typename Container::value_type>(f,"\n"));
}

void CreateXorProblemTrainingFile(const std::string& filename)
{
  std::vector<std::string> s;
  //First line:
  // - 4: number of training sets
  // - 2: number of inputs
  // - 1: number of outputs
  s.push_back("4 2 1");

  //Second line: if the two inputs are 1.0 and 1.0....
  s.push_back("1.0 1.0");
  //Third line: the XOR network should return a -1.0
  s.push_back("-1.0");

  //Fourth line: if the two inputs are -1.0 and -1.0....
  s.push_back("-1.0 -1.0");
  //Fifth line: the XOR network should return a -1.0
  s.push_back("-1.0");

  //And so one...
  s.push_back("-1.0 1.0"); //In
  s.push_back(   "1.0"  ); //Expected out
  s.push_back("1.0 -1.0"); //In
  s.push_back(   "1.0"  ); //Expected out

  SaveContainer(s,filename);
}


int main()
{
  const unsigned int num_input  = 2;
  const unsigned int num_hidden = 3;
  const unsigned int num_output = 1;

  std::vector<unsigned int> layer_sizes;
  layer_sizes.push_back(num_input);
  layer_sizes.push_back(num_hidden);
  layer_sizes.push_back(num_output);
  const std::string file_input  = "XorProblemTrainingSet.txt";
  const std::string file_output = "Output.txt";

  const double desired_error = 0.00001;
  const unsigned int max_epochs = 100000;
  const unsigned int epochs_between_reports = 100;
  const double learning_rate = 0.05;

  fann * const n = fann_create_shortcut_array(learning_rate, layer_sizes.size(),&layer_sizes[0]);

  fann_set_activation_function_hidden(n, FANN_SIGMOID_SYMMETRIC);
  fann_set_activation_function_output(n, FANN_SIGMOID_SYMMETRIC);

  CreateXorProblemTrainingFile(file_input);

  //FANN is not const-correct...
  fann_train_on_file(n,const_cast<char*>(file_input.c_str()), max_epochs, epochs_between_reports, desired_error);

  fann_save(n,file_output.c_str());

  {
    std::cout << "Showing output file: " << '\n';
    const std::vector<std::string> v = FileToVector(file_output);
    CoutContainer(v);
  }

  fann_destroy(n);
}

 

 

 

 

 

Screen output

 

Note that screen output differs between runs, because the random number generator is initialized randomly.

 

Max epochs 100000. Desired error: 0.0000100000
Epochs 1. Current error: 0.2508820593
Epochs 100. Current error: 0.1011718586
Epochs 200. Current error: 0.0171126649
Epochs 300. Current error: 0.0025421339
Epochs 400. Current error: 0.0002089983
Epochs 470. Current error: 0.0000094494
Showing output file:
FANN_FLO_1.1
3 0.050000 1.000000 1 5 5 5.00000000000000000000e-01 5.00000000000000000000e-01
3 4 2
0 0 0
3 3 3 0
6 0
(0 4.18440580368041992188e+00) (1 4.06674432754516601562e+00) (2 3.74954080581665039062e+00) (0 4.17614841461181640625e+00) (1 4.05507659912109375000e+00) (2 3.76885223388671875000e+00) (0 -2.67808938026428222656e+00) (1 -2.79252290725708007812e+00) (2 1.96936237812042236328e+00) (0 -2.83534169197082519531e+00) (1 -2.52798914909362792969e+00) (3 4.44841718673706054688e+00) (4 4.85006999969482421875e+00) (5 4.21606016159057617188e+00) (6 -5.98922777175903320312e+00)

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict