/*
NeuralNet.cpp
轻型神经网络算法库,实现监督学习算法之一——反向传播算法
*/
#include <vector>
#include <map>
#include <cmath>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <exception>
using namespace std;
#ifndef NeuralNet_CPP
#define NeuralNet_CPP
namespace NeuralNetLibrary
{
const static int LINEAR = 0x000000;
const static int SIGMOID = 0x000001;
const static int HYPERTAN = 0x000002;
class NeuralException:virtual exception
{
private:
string msg;
public:
NeuralException(string msg) throw()
{
this->msg = msg;
}
~NeuralException() throw(){}
virtual const char* what() const throw()
{
return msg.c_str();
}
};
class RandomDouble
{
public:
void init()
{
srand(time(NULL));
}
double drand()
{
//返回一个介于 0*(10^-6) 和 1 之间的实数
return (rand()%(1000000-1)+1)/1000000.0;
}
};
class DataSet
{
private:
map<int,double> datas;
public:
double &operator[](int cur)
{
return datas[cur];
}
};
class Neuron
{
private:
vector<double> weights;
int type;
DataSet inputs;
double sum;
double out;
double derivative;
double sensibility;
public:
Neuron(int type,int numofweights,RandomDouble randomer)
{
this->type = type;
for(int i = 0;i < numofweights;i++)
weights.push_back(randomer.drand());
}
vector<double> &getWeights()
{
return weights;
}
double getSensibility()
{
return sensibility;
}
void setSensibility(double sensibility)
{
this->sensibility = sensibility;
}
double getSum()
{
return sum;
}
double getOut()
{
return out;
}
DataSet getInputs()
{
return inputs;
}
double getDerivative()
{
return derivative;
}
double calc(DataSet datas)
{
inputs = datas;
sum = 0.0;
for(int i = 0;i < weights.size();i++)
sum += weights[i]*datas[i];
switch(type)
{
case LINEAR:
out = sum;
derivative = 1;
break;
case SIGMOID:
out = 1/(1+exp(sum));
derivative = out*(1-out);
break;
case HYPERTAN:
out = (1-exp(sum))/(1+exp(sum));
derivative = 1-out*out;
break;
}
return out;
}
};
class Layer
{
private:
vector<Neuron> neurons;
int type;
public:
Layer(int type,int numofweights,RandomDouble randomer,int numofneurons)
{
this->type = type;
for(int i = 0;i < numofweights;i++)
{
Neuron neuron(type,numofweights,randomer);
neurons.push_back(neuron);
}
}
int getType()
{
return type;
}
DataSet calc(DataSet datas)
{
DataSet ret;
for(int i = 0;i < neurons.size();i++)
ret[i] = neurons[i].calc(datas);
return ret;
}
vector<Neuron> &getNeurons()
{
return neurons;
}
};
class NeuralNet
{
private:
vector<Layer> layers;
bool inited;
int numofinputs;
RandomDouble randomer;
public:
NeuralNet(int numofinputs)
{
this->numofinputs = numofinputs;
inited = false;
randomer.init();
}
int getNumOfInputs()
{
return numofinputs;
}
void addLayer(int type,int numofneurons)
{
if(inited) throw NeuralException("NeuralNet:Failed to add a new layer:The neuralnet has been initialized");
else
{
int numofweights;
if(layers.empty()) numofweights = numofinputs;
else numofweights = layers.back().getNeurons().size();
Layer newlayer(type,numofweights,randomer,numofneurons);
layers.push_back(newlayer);
}
}
vector<Layer> &getLayers()
{
return layers;
}
void init()
{
if(layers.empty()) throw NeuralException("NeuralNet:Failed to initialize the neuralnet:No layers");
else inited = true;
}
bool isinited()
{
return inited;
}
DataSet calc(DataSet datas)
{
if(!inited) throw NeuralException("NeuralNet:Failed to calculate:The neuralnet has not been initialized");
else
{
for(int i = 0;i < layers.size();i++)
datas = layers[i].calc(datas);
return datas;
}
}
};
class TrainSet
{
private:
DataSet inputs;
DataSet outputs;
public:
void setIODataSet(DataSet inputs,DataSet outputs)
{
this->inputs = inputs;
this->outputs = outputs;
}
DataSet &getInputDataSet()
{
return inputs;
}
DataSet &getOutputDataSet()
{
return outputs;
}
};
class Trainer
{
private:
vector<TrainSet> trainsets;
public:
virtual void train(NeuralNet &net) = 0;
void addTrainSet(TrainSet trainset)
{
trainsets.push_back(trainset);
}
vector<TrainSet> &getTrainSet()
{
return trainsets;
}
};
class BackPropagation:public virtual Trainer
{
private:
double learningrate;
double goalmse;
int maxtimes;
public:
BackPropagation(double learningrate,double goalmse,int maxtimes)
{
this->learningrate = learningrate;
this->goalmse = goalmse;
this->maxtimes = maxtimes;
}
virtual void train(NeuralNet &net)
{
for(int times = 1;times <= maxtimes;times++){
bool acess = true;
for(int cur = 0;cur < getTrainSet().size();cur++)
{
DataSet nowinput = getTrainSet()[cur].getInputDataSet();
DataSet nowoutput = getTrainSet()[cur].getOutputDataSet();
//获取网络输出
DataSet netout = net.calc(nowinput);
double mse = 0.0;
for(int i = 0;i < net.getLayers().back().getNeurons().size();i++)
mse += sqrt(netout[i]-nowoutput[i]);
mse /= net.getLayers().back().getNeurons().size();
//检查MSE是否满足目标
if(mse <= goalmse) continue;
else acess = false;
//计算灵敏度
for(int i = net.getLayers().size()-1;i >= 0;i--)
{
Layer &nowlayer = net.getLayers()[i];
for(int j = 0;j < nowlayer.getNeurons().size();j++)
{
if(i == net.getLayers().size()-1)
nowlayer.getNeurons()[j].setSensibility((nowoutput[j]-netout[j])*nowlayer.getNeurons()[j].getDerivative());
else
{
double sensibility = 0.0;
Layer nextlayer = net.getLayers()[i+1];
for(int k = 0;k < nextlayer.getNeurons().size();k++)
{
Neuron nextneuron = nextlayer.getNeurons()[k];
sensibility += nextneuron.getSensibility()*nextneuron.getWeights()[j];
}
sensibility *= nowlayer.getNeurons()[j].getDerivative();
nowlayer.getNeurons()[j].setSensibility(sensibility);
}
}
}
//更新权值
for(int i = net.getLayers().size()-1;i >= 0;i--)
{
Layer &nowlayer = net.getLayers()[i];
for(int j = 0;j < nowlayer.getNeurons().size();j++)
{
Neuron &nowneuron = nowlayer.getNeurons()[j];
for(int k = 0; k <nowneuron.getWeights().size();k++)
nowneuron.getWeights()[k] += learningrate*nowneuron.getSensibility()*nowneuron.getInputs()[k];
}
}
}
}
}
};
typedef struct
{
int numofinputs;
int numoflayers;
int layeroff;
}NEURALNET_HEAD;
typedef struct
{
int type;
int numofneurons;
int neuronoff;
}LAYER_HEAD;
typedef struct
{
int numofweights;
int weightoff;
}NEURON_HEAD;
class NeuralNetFile
{
private:
string file;
public:
NeuralNetFile(string file)
{
this->file = file;
}
NeuralNet read()
{
FILE* f = fopen(file.c_str(),"r");
fseek(f,0,SEEK_SET);
NEURALNET_HEAD nnhdr;
fread(&nnhdr,sizeof(NEURALNET_HEAD),1,f);
NeuralNet net(nnhdr.numofinputs);
for(int i = 0;i < nnhdr.numoflayers;i++)
{
fseek(f,nnhdr.layeroff+i*sizeof(LAYER_HEAD),SEEK_SET);
LAYER_HEAD lhdr;
fread(&lhdr,sizeof(LAYER_HEAD),1,f);
net.addLayer(lhdr.type,lhdr.numofneurons);
Layer &nowlayer = net.getLayers()[i];
for(int j = 0;j < lhdr.numofneurons;j++)
{
fseek(f,lhdr.neuronoff+j*sizeof(NEURON_HEAD),SEEK_SET);
NEURON_HEAD nhdr;
fread(&nhdr,sizeof(NEURON_HEAD),1,f);
Neuron &nowneuron = nowlayer.getNeurons()[j];
for(int k = 0;k < nhdr.numofweights;k++)
{
fseek(f,nhdr.weightoff+k*sizeof(double),SEEK_SET);
double weight;
fread(&weight,sizeof(weight),1,f);
nowneuron.getWeights()[k] = weight;
}
}
}
net.init();
fclose(f);
return net;
}
void write(NeuralNet net)
{
if(!net.isinited())
{
throw NeuralException("NeuralNet:Failed to calculate:The neuralnet has not been initialized");
return;
}
FILE* f = fopen(file.c_str(),"w");
int off = 0;
NEURALNET_HEAD nnhdr;
nnhdr.numofinputs = net.getNumOfInputs();
nnhdr.numoflayers = net.getLayers().size();
off += sizeof(NEURALNET_HEAD);
nnhdr.layeroff = off;
fwrite(&nnhdr,sizeof(NEURALNET_HEAD),1,f);
off += sizeof(LAYER_HEAD)*nnhdr.numoflayers;
for(int i = 0;i < nnhdr.numoflayers;i++)
{
LAYER_HEAD lhdr;
lhdr.type = net.getLayers()[i].getType();
lhdr.numofneurons = net.getLayers()[i].getNeurons().size();
lhdr.neuronoff = off;
fwrite(&lhdr,sizeof(LAYER_HEAD),1,f);
off += sizeof(NEURON_HEAD)*lhdr.numofneurons;
}
for(int i = 0;i < nnhdr.numoflayers;i++)
{
Layer nowlayer = net.getLayers()[i];
int numofneurons = nowlayer.getNeurons().size();
for(int j = 0;j < numofneurons;j++)
{
Neuron nowneuron = nowlayer.getNeurons()[j];
NEURON_HEAD nhdr;
nhdr.numofweights = nowneuron.getWeights().size();
nhdr.weightoff = off;
fwrite(&nhdr,sizeof(NEURON_HEAD),1,f);
off += sizeof(double)*nhdr.numofweights;
}
}
for(int i = 0;i < nnhdr.numoflayers;i++)
{
Layer nowlayer = net.getLayers()[i];
int numofneurons = nowlayer.getNeurons().size();
for(int j = 0;j < numofneurons;j++)
{
Neuron nowneuron = nowlayer.getNeurons()[j];
int numofweights = nowneuron.getWeights().size();
for(int k = 0;k < numofweights;k++)
fwrite(&nowneuron.getWeights()[k],sizeof(double),1,f);
}
}
fclose(f);
}
};
}
#endif
自己实现一个神经网络算法库
最新推荐文章于 2024-06-06 10:01:25 发布