My perceptron's train function seems to materialize my BadInput exception object out of nowhere. Yet, everything works fine.
And when I put an forever loop in main to validate the output with many different inputs, I get a bad_alloc exception and a call to terminate().
BadInput.hpp
Code:
#ifndef BADINPUT_HPP
#define BADINPUT_HPP
class BadInput
{
public:
BadInput(int val):difference(val)
{
}
int difference;
};
#endif
Typedefs.hpp
Code:
#ifndef TYPEDEF_HPP
#define TYPEDEF_HPP
#include <vector>
#include <random>
typedef std::vector <float>FloatV;
typedef std::random_device RNG;
typedef std::uniform_int_distribution <> UID;
#endif
Functor.hpp
Code:
#ifndef FUNCTOR_HPP
#define FUNCTOR_HPP
#include "Typedefs.hpp"
#include "BadInput.hpp"
class Functor
{
public:
Functor()
{
}
Functor(const Functor & rhs) = default;
virtual ~Functor(){}
virtual float operator() (const FloatV & input)const = 0;
int GetArgNum() const
{
return argnum;
}
private:
int argnum;
};
class Plane:public Functor
{
public:
Plane() = delete;
Plane(const FloatV & values):cf(values), argnum(2)
{
}
Plane(const Plane & rhs) = default;
virtual ~Plane()
{
}
virtual float operator() (const FloatV & input)const
{
float sum = 0;
if (input.size() != argnum)
throw BadInput(input.size() - argnum);
for (int i = 0; i < input.size(); i++)
sum += input[i] * cf[i];
sum += cf.back();
}
private:
const int argnum;
const FloatV cf;
};
#endif
Trainer.hpp
Code:
#ifndef TRAINER_HPP
#define TRAINER_HPP
#include "Typedefs.hpp"
#include "Functor.hpp"
class Trainer
{
public:
Trainer() = delete;
Trainer(const Functor& function);
void GenerateData();
FloatV& GetData() const;
int GetAnswer() const;
private:
const Functor& f;
mutable FloatV TrainingData;
mutable int answer;
};
#endif
Trainer.cpp
Code:
#include "BadInput.hpp"
#include "Trainer.hpp"
Trainer::Trainer(const Functor& function):f(function),
TrainingData(f.GetArgNum())
{
}
void Trainer::GenerateData()
{
RNG rand;
for (auto & val:TrainingData)
val = rand();
float z;
try
{
z = f(TrainingData);
}
catch(BadInput&)
{
throw;
}
TrainingData.push_back(rand());
if (TrainingData.back() < z)
answer = -1;
else
answer = 1;
}
FloatV & Trainer::GetData() const
{
return TrainingData;
}
int Trainer::GetAnswer() const
{
return answer;
}
Perceptron.hpp
Code:
#ifndef PERCEPTRON_HPP
#define PERCEPTRON_HPP
#include "Typedefs.hpp"
#include "Trainer.hpp"
class Perceptron
{
public:
Perceptron() = delete;
Perceptron(Trainer& trainer);
~Perceptron();
int feedforward(FloatV& input);
void retrain(Trainer& trainer);
private:
void train(Trainer & trainer);
int activate(float sum);
FloatV weights;
static const float bias;
static const float correction;
};
#endif
Perceptron.cpp
Code:
#include "BadInput.hpp"
#include "Perceptron.hpp"
#include <iostream>
const float Perceptron::bias = 1.0;
const float Perceptron::correction = 0.01;
Perceptron::Perceptron(Trainer & trainer):weights(trainer.GetData().size() + 1)
{
UID rand(-1, 1);
RNG rng;
for (auto & weight:weights)
weight = static_cast < float >(rand(rng));
try
{
train(trainer);
}
catch(BadInput & error)
{
std::
cerr <<
"An error occurred during the initialization of the perceptron." <<
std::endl;
}
}
Perceptron::~Perceptron()
{
}
void Perceptron::retrain(Trainer & trainer)
{
UID rand(-1, 1);
RNG rng;
for (auto & weight:weights)
weight = static_cast < float >(rand(rng));
try
{
train(trainer);
}
catch(BadInput & error)
{
std::
cerr <<
"An error occurred during the retraining of the perceptron." <<
std::endl;
}
}
int Perceptron::feedforward(FloatV & input)
{
float sum = 0;
input.push_back(bias);
if (input.size() != weights.size())
{
BadInput error(input.size() - weights.size());
std::cerr << "Biased input is " << error.difference <<
" value different from the number of weights in the perceptron." <<
std::endl;
throw error;
}
for (int i = 0; i < input.size(); i++)
sum += (input[i] * weights[i]);
return activate(sum);
}
void Perceptron::train(Trainer & trainer)
{
for (int i = 0; i < 2000; i++)
{
int guess;
int correct;
try
{
trainer.GenerateData();
}
catch(BadInput & error)
{
std::cerr << "An error has occurred in training the perceptron." <<
std::endl;
throw;
}
guess = feedforward(trainer.GetData());
correct = trainer.GetAnswer();
int error = correct - guess;
for (int i = 0; i < (trainer.GetData().size() + 1); i++)
weights[i] += (trainer.GetData()[i] * error * correction);
}
}
int Perceptron::activate(float sum)
{
if (sum > 0)
return 1;
else
return -1;
}
Main.cpp
Code:
#include <iostream>
#include "BadInput.hpp"
#include "Typedefs.hpp"
#include "Functor.hpp"
#include "Trainer.hpp"
#include "Perceptron.hpp"
using std::cout;
using std::cerr;
using std::cin;
using std::endl;
int main()
{
FloatV coefficients(3);
cout <<
"This program will learn to classify whether a given point lies above or below a plane given by z=mx+ny+b. Please enter values for m, n, and b: "
<< endl;
for (auto & val:coefficients)
{
cin >> val;
if (cin.fail())
{
cerr << "Please enter a number! Program will now terminate." <<
endl;
return -1;
}
}
Plane f(coefficients);
Trainer ProfessorWilson(f);
Perceptron brain(ProfessorWilson);
cout << "Enter a point (x, y, z) to classify: " << endl;
FloatV point(3);
for (auto & val:point)
{
cin >> val;
if (cin.fail())
{
cerr << "Please enter a number! Program will now terminate." <<
endl;
return -1;
}
}
int classification;
try
{
classification = brain.feedforward(point);
}
catch(const BadInput & error)
{
return -1;
}
if (classification == 1)
cout << "Point is above the plane." << endl;
if (classification == -1)
cout << "Point is below the plane." << endl;
return 0;
}
I cannot figure out why train() is throwing an exception...feedforward didn't, as it's error message never printed.
Thanks,
Lexi