#pragma once
#include "stdafx.h"
namespace ANN {
class Neuron;
class Connection {
public:
Neuron * From;
double Weight;
Connection(Neuron * From):From(From) {
Weight = (2.0*(double)rand()/(double)RAND_MAX)-1.0;
}
Connection(Neuron * From, double w):From(From) {
Weight = w;
}
void Randomize()
{
Weight = (2.0*(double)rand()/(double)RAND_MAX)-1.0;
}
void AdjustWeight(double Delta) {
Weight += Delta;
// Weight = std::max(std::min(Weight, 1.0), -1.0);
}
};
class Neuron {
public:
Neuron()
{
Output = 0;
Bias = false;
}
void CalcOutput(std::vector<Connection *> & Connections) {
if (Bias) {
} else {
double Sum = 0;
for (int i = 0; i < Connections.size(); i++) {
Neuron & From = *Connections[i]->From;
Sum += From.Output*Connections[i]->Weight;
}
Output = f(Sum);
}
}
void SetBias()
{
Output = 1;
Bias = true;
}
double f(double x) {
return std::max(std::min(x, 1.0), 0.0);
// return 0.5*((sqrt(fabs((x-0.5)/0.5))*(x>0.5?1.0:-1.0))+1.0);
// return x>0.55?1.0:(x<0.45?0.0:0.5);
// return x>0.0?1.0:-1.0;
// return x>0.0?1.0:0.0;
// return fabs(x)<0.2?0.0:(x>0.0?1.0:-1.0);
// return 1.0 / (1.0 + (double) exp(-x));
// return 1.0 / (1.0 + (double) pow(2.1, -x));
}
double Output;
bool Bias;
};
class Network {
public:
std::vector<Neuron *> Input, Output;
std::vector<Neuron *> Hidden;
std::vector<std::vector<Connection *> > InputToHidden, InputToOutput, HiddenToOutput;
double LearnConstant;
std::string DebugString()
{
std::ostringstream OStr;
if (Hidden.size()>0)
{
OStr<<"(";
for (unsigned int i=0; i<Hidden.size()-1; i++)
OStr<<(floor(Hidden[i]->Output*100.0)/100.0)<<", ";
OStr<<Hidden[Hidden.size()-1]->Output<<") ";
}
return OStr.str();
}
std::string WeightsString(unsigned int k)
{
std::ostringstream OStr;
if (Hidden.size()==0)
{
std::vector<std::vector<Connection *> > & Current = InputToOutput;
OStr<<"(";
for (unsigned int i=0; i<Current.size(); i++)
{
for (unsigned int j=0; j<Current[i].size(); j++)
OStr<<(floor(Current[i][j]->Weight*100.0)/100.0)<<", ";
OStr<<"; ";
}
OStr<<") ";
return OStr.str();
}
for (unsigned int k=0; k<2; k++)
{
std::vector<std::vector<Connection *> > & Current = k==0?InputToHidden:HiddenToOutput;
OStr<<"(";
for (unsigned int i=0; i<Current.size(); i++)
{
for (unsigned int j=0; j<Current[i].size(); j++)
OStr<<(floor(Current[i][j]->Weight*100.0)/100.0)<<", ";
OStr<<"; ";
}
OStr<<") ";
}
return OStr.str();
}
// InputAmount - The number of inputs the network expects.
// HiddenAmount - The number of hidden Neurons in the hidden layer. Pass 0 for a Perceptron.
// OutputAmount - The number of outputs the network will produce.
// LearnConstant - A value between 0.0 and 1.0 to specify how fast/accurate the network learns.
Network(unsigned int InputAmount, unsigned int HiddenAmount, unsigned int OutputAmount, double LearnConstant):LearnConstant(LearnConstant) {
Input.resize(InputAmount+1);
Output.resize(OutputAmount);
for (int i = 0; i < Input.size(); i++) {
Input[i] = new Neuron();
}
if (HiddenAmount>0)
{
Hidden.resize(HiddenAmount+1);
for (int i = 0; i < Hidden.size(); i++) {
Hidden[i] = new Neuron();
}
Hidden[Hidden.size()-1]->SetBias();
}
Input[Input.size()-1]->SetBias();
for (int i = 0; i < Output.size(); i++) {
Output[i] = new Neuron();
}
if (HiddenAmount>0)
{
InputToHidden.resize(Hidden.size());
for (int i = 0; i < Hidden.size(); i++) {
InputToHidden[i].resize(Input.size());
for (int j = 0; j < Input.size(); j++) {
InputToHidden[i][j] = new Connection (Input[j]);
}
}
HiddenToOutput.resize(Output.size());
for (int i = 0; i < Output.size(); i++) {
HiddenToOutput[i].resize(Hidden.size());
for (int j = 0; j < Hidden.size(); j++) {
HiddenToOutput[i][j] = new Connection (Hidden[j]);
}
}
}
else
{
InputToOutput.resize(Output.size());
for (int i = 0; i < Output.size(); i++) {
InputToOutput[i].resize(Input.size());
for (int j = 0; j < Input.size(); j++) {
InputToOutput[i][j] = new Connection (Input[j]);
}
}
}
}
void RandomizeWeights()
{
if (Hidden.size()>0)
{
for (int i = 0; i < Hidden.size(); i++) {
for (int j = 0; j < Input.size(); j++) {
InputToHidden[i][j]->Randomize();
}
}
for (int i = 0; i < Output.size(); i++) {
for (int j = 0; j < Hidden.size(); j++) {
HiddenToOutput[i][j]->Randomize();
}
}
}
else
for (int i = 0; i < Output.size(); i++) {
for (int j = 0; j < Input.size(); j++) {
InputToOutput[i][j]->Randomize();
}
}
}
void FeedForward(std::vector<double> & InputValues, std::vector<double> & OutputValues)
{
for (unsigned int i = 0; i < InputValues.size(); i++) {
Input[i]->Output = InputValues[i];
}
if (Hidden.size()>0)
{
for (int i = 0; i < Hidden.size()-1; i++) {
Hidden[i]->CalcOutput(InputToHidden[i]);
}
for (int i = 0; i < Output.size(); i++) {
Output[i]->CalcOutput(HiddenToOutput[i]);
}
}
else
{
for (int i = 0; i < Output.size(); i++) {
Output[i]->CalcOutput(InputToOutput[i]);
}
}
for (int i = 0; i < Output.size(); i++) {
OutputValues[i] = Output[i]->Output;
}
}
void Train(std::vector<double> & Delta)
{
Propagate (Delta, LearnConstant);
}
double InverseF(double y) {
return -log((1.0/y) - 1.0);
}
void Propagate(std::vector<double> & Delta, double Constant)
{
if (Hidden.size()==0)
{
for (unsigned int i = 0; i < Output.size(); i++)
{
for (unsigned int j = 0; j < InputToOutput[i].size(); j++)
{
double DeltaOutput = Delta[i];
double DeltaWeight = DeltaOutput;
InputToOutput[i][j]->AdjustWeight (Input[j]->Output*DeltaWeight*Constant);
}
}
return;
}
for (unsigned int i = 0; i < Output.size(); i++)
{
for (unsigned int j = 0; j < HiddenToOutput[i].size(); j++)
{
double DeltaOutput = Delta[i];
double DeltaWeight = DeltaOutput;
HiddenToOutput[i][j]->AdjustWeight (Hidden[j]->Output*DeltaWeight*Constant);
}
}
for (unsigned int i = 0; i < Hidden.size(); i++)
{
double Sum = 0;
for (unsigned int j = 0; j < Output.size(); j++)
Sum+=HiddenToOutput[j][i]->Weight*Delta[j];
double Output1 = Hidden[i]->Output;
// double DeltaHidden = Output1 * (1.0 - Output1);
double DeltaHidden = Output1;
DeltaHidden *= Sum;
for (unsigned int j = 0; j < Input.size(); j++)
{
float DeltaWeight = Input[j]->Output*DeltaHidden;
InputToHidden[i][j]->AdjustWeight(Constant*DeltaWeight);
}
}
}
};
}