#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
#define BIAS -1
#define ERROR_THRESHOLD 0.0002
#define LEARNING_RATE 0.1
#define COUNT_OF_TRAINSET 8
//计算布尔算术式:a + (b · c)
//定义神经网络的训练集
const double trainsets[COUNT_OF_TRAINSET][4]=
{
1,0,1,1,//在这里,a=1,b=0,c=1,结果代入式子 a + (b · c),即为 1
1,0,0,1,
0,0,0,0,
0,1,0,0,
0,0,1,0,
1,1,0,1,
0,1,1,1,
1,1,1,1,
};
//随机产生[0,1]的实数
inline double RandFloat()
{
return (rand())/(RAND_MAX+1.0);
}
//随机产生[-1,1]的实数
inline double RandomClamped()
{
return RandFloat() - RandFloat();
}
//S型函数:把(负无穷,正无穷)映射到实数域(0,1)上
double Sigmoid(double input )
{
return ( 1 / ( 1 + exp(-input / 1.0)));
}
//神经元结构
typedef struct SNeuron
{
//这个神经元的输入个数
int num_input;
//这个神经元各个输入的权
vector<double> m_vecWeight;
//这个神经元的激活阈值
double m_dActivation;
//这个神经元的误差
double m_dError;
//构造函数
SNeuron(int NumInputs)
{
num_input=NumInputs+1;//添加了偏离值所以要加1
m_dActivation=0;
m_dError=0;
for (int i=0; i<num_input; ++i)m_vecWeight.push_back(0);//RandomClamped());
}
}SNeuron;
//神经网络层(所有层的抽象)
typedef struct SNeuronLayer
{
//当前网络层的神经元数目
int m_iNumNeurons;
//各个神经元的数组
vector<SNeuron> m_vecNeurons;
//构造函数
SNeuronLayer(int NumNeurons, int NumInputsPerNeuron)
{
m_iNumNeurons=NumNeurons;
for (int i=0; i<NumNeurons; ++i)m_vecNeurons.push_back(SNeuron(NumInputsPerNeuron));
}
}SNeuronLayer;
int m_iNumInputs;//有多少个输入
int m_iNumOutputs;//有多少个输出
int m_iNumHiddenLayers;//有多少个隐藏层
int m_iNeuronsPerHiddenLyr;//隐藏层有多少个神经元
double m_dErrorSum;//错误率,用来判断是否
int m_iNumEpochs;//只是用来统计经过了多少代
//存储所有的网络层(顺序:输入层,隐藏层,输入层)
vector<SNeuronLayer> m_vecLayers;
//创建网络
void CreateNet()
{
m_iNumInputs=3;
m_iNumOutputs=1;
m_iNumHiddenLayers=1;
m_iNeuronsPerHiddenLyr=1;
m_dErrorSum=9999;
//创建输入层
m_vecLayers.push_back(SNeuronLayer(m_iNeuronsPerHiddenLyr, m_iNumInputs));
//创建隐藏层
for (int i=0; i<m_iNumHiddenLayers-1; ++i)
m_vecLayers.push_back(SNeuronLayer(m_iNeuronsPerHiddenLyr,m_iNeuronsPerHiddenLyr));
//创建输出层
m_vecLayers.push_back(SNeuronLayer(m_iNumOutputs, m_iNeuronsPerHiddenLyr));
}
//初始化网络
void InitializeNetwork()
{
//对所有层
for (int i=0; i<m_iNumHiddenLayers + 1; ++i)
{
//对所有神经元
for (int n=0; n<m_vecLayers[i].m_iNumNeurons; ++n)
{
//对所有输入权
for (int k=0; k<m_vecLayers[i].m_vecNeurons[n].num_input; ++k)
{
m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k] =0;// RandomClamped();
}
}
}
m_dErrorSum = 9999;
m_iNumEpochs = 0;
}
//向前传递
vector<double> GoForward(vector<double> inputs)
{
int cWeight = 0;
vector<double> outputs;
//所有层都对权值加和起作用
for (int i=0; i<m_iNumHiddenLayers + 1; ++i)
{
if ( i > 0 )
{
inputs = outputs;
}
outputs.clear();
cWeight = 0;
//对所有的神经元
SNeuronLayer CurrLayer=m_vecLayers[i];//当前网络层
for (int n=0; n<CurrLayer.m_iNumNeurons; ++n)
{
SNeuron CurNeuron=CurrLayer.m_vecNeurons[n];//当前的网络层的神经元
double netinput = 0;
int count_input = CurNeuron.num_input;
//对于每个输入的权重
for (int k=0; k<count_input - 1; ++k)//不算上偏离值
{
//权值X输入的加和
netinput += m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k] * inputs[cWeight++];
}
//加上偏离值
netinput += m_vecLayers[i].m_vecNeurons[n].m_vecWeight[count_input-1] * BIAS;//最后那个就是偏离值啦
//更改激励值
m_vecLayers[i].m_vecNeurons[n].m_dActivation = Sigmoid(netinput);
//保存每个神经元的输入
outputs.push_back(m_vecLayers[i].m_vecNeurons[n].m_dActivation);
cWeight = 0;
}
}
return outputs;
}
//训练网络
bool NetworkTraining(vector< vector<double> > &SetIn,vector< vector<double> > &SetOut)
{
//对所有的输入数据和期望的数据输入,网络会训练调整权值
m_dErrorSum = 0;
//对每一个训练集都进行输出层和隐藏层的训练
for (int vec=0; vec<SetIn.size(); ++vec)
{
//产生实际的输入(主要和期望输出做对比)
vector<double> outputs = GoForward(SetIn[vec]);
/*****************开始调整输出层******************/
for (int op=0; op<m_iNumOutputs; ++op)//此例是1
{
//计算当前某个输出向量的输出的误差
double err = (SetOut[vec][op] - outputs[op]) * outputs[op] * (1 - outputs[op]);
//保存该隐藏层的误差
m_vecLayers[1].m_vecNeurons[op].m_dError = err;
//更新误差总值(当该总值低于一预设阈值时,即是完成训练)
m_dErrorSum += (SetOut[vec][op] - outputs[op]) * (SetOut[vec][op] - outputs[op]);
vector<SNeuron>::iterator curNrnHid = m_vecLayers[0].m_vecNeurons.begin();
vector<double>::iterator curWeight ;
//更新权重,不包括偏移
//此例是2次循环
for(curWeight = m_vecLayers[1].m_vecNeurons[op].m_vecWeight.begin();
curWeight != m_vecLayers[1].m_vecNeurons[op].m_vecWeight.end()-1;)
{
//基于BP规则计算新的权重
*curWeight += err * LEARNING_RATE * curNrnHid->m_dActivation;
// cout<<curNrnHid->m_dActivation<<"\t";
++curNrnHid;
++curWeight;
}
//加上偏移值的权重
*curWeight += err * LEARNING_RATE * BIAS;
}
/*****************结束调整输出层******************/
/*****************开始调整隐藏层******************/
vector<SNeuron>::iterator curNrnHid;
int n = 0;
for(curNrnHid= m_vecLayers[0].m_vecNeurons.begin();curNrnHid != m_vecLayers[0].m_vecNeurons.end();++curNrnHid)
{
vector<SNeuron>::iterator curNrnOut;
double err = 0;
for(curNrnOut = m_vecLayers[1].m_vecNeurons.begin();curNrnOut != m_vecLayers[1].m_vecNeurons.end();++curNrnOut)
{
err += curNrnOut->m_dError * curNrnOut->m_vecWeight[n];
}
//计算误差
err =err* curNrnHid->m_dActivation * (1 - curNrnHid->m_dActivation);
//基于误差计算每个权重
for (int w=0; w<m_iNumInputs; ++w)
{
curNrnHid->m_vecWeight[w] += err * LEARNING_RATE * SetIn[vec][w];
}
//加上偏移量
curNrnHid->m_vecWeight[m_iNumInputs] += err * LEARNING_RATE * BIAS;
++n;
}
/*****************结束调整隐藏层******************/
}//结束当前一个训练集的训练
return true;
}
double test(double a,double b,double c)
{
vector<double> min;
min.push_back(a);
min.push_back(b);
min.push_back(c);
vector<double> mout=GoForward(min);
return mout.at(0);
}
bool Train()
{
vector<vector<double> > SetIn ;
vector<vector<double> > SetOut;
int i,j;
for(i=0;i<COUNT_OF_TRAINSET;i++)
{
vector<double> tin;
vector<double> tout;
tin.push_back(trainsets[i][0]);
tin.push_back(trainsets[i][1]);
tin.push_back(trainsets[i][2]);
tout.push_back(trainsets[i][3]);
SetIn.push_back(tin);
SetOut.push_back(tout);
}
//initialize all the weights to small random values
InitializeNetwork();
//一直训练到合标准为止
while( m_dErrorSum > ERROR_THRESHOLD )
{
NetworkTraining(SetIn, SetOut);
++m_iNumEpochs;
}
return true;
}
void main()
{
clock_t a,b;
a=clock();
CreateNet();
InitializeNetwork();
Train();
int i;
char buf[1024];
for(i=0;i<COUNT_OF_TRAINSET;i++)
{
sprintf(buf,"%d + (%d · %d) 结果约为: %f\n",
(int)trainsets[i][0],(int)trainsets[i][1],(int)trainsets[i][2],
test(trainsets[i][0],trainsets[i][1],trainsets[i][2]));
cout<<buf;
} b=clock();
cout<<endl<<b-a;
system("pause");
}