📄 bp.cpp
字号:
#pragma warning(disable: 4786)
#include "BP.h"
#include "..\\Core\\Exception.h"
#include "..\\Utils\\xs.h"
#include "..\\Input\\File\\ArffStream.h"
#include <cmath>
#include <fstream>
#include <iostream>
//: for test
#include <ctime>
using namespace std;
BP::BP(vector<Data>* train_set,BP_PARAM params)
{
_ni = params.input;
_nh = params.hidden;
_no = params.output;
_enta = params.learning_rate;
_range = params.random_range;
_max_epoch = params.max_epoch;
_train_set = train_set;
this->initialize();
}
BP::~BP()
{
delete[] _wih; delete[] _who;
delete[] _dwih; delete[] _dwho;
delete[] _bh; delete[] _bo;
delete[] _dbh; delete[] _dbo;
delete[] _sh; delete[] _so;
delete[] _oh; delete[] _oo;
}
void BP::train()
{
if(_train_set == NULL)
throw new Exception("BP::train, current is working mode, training is forbidden!");
int i = 0;
vector<Data>::iterator it;
while(i++<_max_epoch)
{
for(it=_train_set->begin();it!=_train_set->end();it++)
{
forward(*it);
backward(*it);
}
update_weights();
}
}
void BP::work(Data& data)
{
this->forward(data);
for(int k=0;k<_no;k++)
data[_ni+k] = _oo[k];
}
void BP::check()
{
if(_ni < 0)
throw new Exception("BP::check,input layer count < 0");
cout<<"BP: using input layer count: "<<_ni<<endl;
if(_nh < 0)
throw new Exception("BP::check,hidden layer count < 0");
cout<<"BP: using hidden layer count: "<<_nh<<endl;
if(_no < 0)
throw new Exception("BP::check,output layer count < 0");
cout<<"BP: using output layer count: "<<_no<<endl;
if(_enta < 0)
throw new Exception("BP::check,learning rate < 0");
if(_enta >= 1)
cout<<"WARNING: learning rate>=1.0"<<endl;
cout<<"BP: using learning rate: "<<_enta<<endl;
if(abs(_range)>0.5)
cout<<"WARNING: random range>0.5"<<endl;
cout<<"BP: using random range: "<<_range<<endl;
if(_max_epoch < 100)
cout<<"WARNING: maximum epoch count < 100"<<endl;
if(_max_epoch > 10000)
cout<<"WARNING: maximum epoch count > 10000"<<endl;
cout<<"BP: using maximum epoch: "<<_max_epoch<<endl;
}
double BP::random()
{
return _range*(rand()-RAND_MAX/2)/RAND_MAX*2;
}
void BP::initialize()
{
this->check();
//: weights
_wih = new double[_ni*_nh];
_who = new double[_nh*_no];
_dwih = new double[_ni*_nh];
_dwho = new double[_nh*_no];
//: biases
_bh = new double[_nh];
_bo = new double[_no];
_dbh = new double[_nh];
_dbo = new double[_no];
//: sigma error
_sh = new double[_nh];
_so = new double[_no];
//: output
_oh = new double[_nh];
_oo = new double[_no];
int i,j,k;
//: initialize weights and biases with random range
for(i=0;i<_ni;i++)
{
for(j=0;j<_nh;j++)
{
_wih[i*_nh+j] = random();
_dwih[i*_nh+j] = 0;
}
}
for(j=0;j<_nh;j++)
{
for(k=0;k<_no;k++)
{
_who[j*_no+k] = random();
_dwho[j*_no+k] = 0;
}
}
for(j=0;j<_nh;j++)
{
_bh[j] = random();
_dbh[j] = 0;
}
for(k=0;k<_no;k++)
{
_bo[k] = random();
_dbo[k] = 0;
}
}
void BP::forward(Data data)
{
int i,j,k;
//: hidden layer
for(j=0;j<_nh;j++)
{
double netj = _bh[j]; //: bias is a must
for(i=0;i<_ni;i++) //: compute input layer activity
netj += data[i]*_wih[i*_nh+j];
_oh[j] = squash(netj);
}
//: output layer
for(k=0;k<_no;k++)
{
double netk = _bo[k]; //: bias is a must
for(j=0;j<_nh;j++) //: compute hidden layer activity
netk += _oh[j] *_who[j*_no+k];
_oo[k] = squash(netk);
}
}
void BP::backward(Data data)
{
int i,j,k;
//: output layer backward propagation
for(k=0;k<_no;k++)
_so[k] = dx_squash(_oo[k])*(data[_ni+k]-_oo[k]);
//: hidden layer backward propagation
for(j=0;j<_nh;j++)
{
double ss = 0;
//: calculates the sigma of output layer affection
for(k=0;k<_no;k++)
ss += _who[j*_no+k]*_so[k];
_sh[j] = dx_squash(_oh[j]) * ss;
}
//: compute delta weights and delta bias weights
for(j=0;j<_nh;j++)
for(k=0;k<_no;k++)
_dwho[j*_no+k] += _enta*_so[k]*_oh[j];
for(i=0;i<_ni;i++)
for(j=0;j<_nh;j++)
_dwih[i*_nh+j] += _enta*_sh[j]*data[i];
for(j=0;j<_nh;j++)
_dbh[j] += _enta*_sh[j];
for(k=0;k<_no;k++)
_dbo[k] += _enta*_so[k];
}
void BP::update_weights()
{
int i,j,k;
//: weights between input and hidden layer
for(i=0;i<_ni;i++)
for(j=0;j<_nh;j++)
_wih[i*_nh+j] += _dwih[i*_nh+j];
//: weights between hidden and output layer
for(j=0;j<_nh;j++)
for(k=0;k<_no;k++)
_who[j*_no+k] += _dwho[j*_no+k];
for(j=0;j<_nh;j++)
_bh[j] += _dbh[j];
for(k=0;k<_no;k++)
_bo[k] += _dbo[k];
//:reset delta weights
for(j=0;j<_nh;j++)
for(k=0;k<_no;k++)
_dwho[j*_no+k] = 0;
for(i=0;i<_ni;i++)
for(j=0;j<_nh;j++)
_dwih[i*_nh+j] = 0;
for(j=0;j<_nh;j++)
_dbh[j] = 0;
for(k=0;k<_no;k++)
_dbo[k] = 0;
}
//////////////////////////////////////////////////////////////////////////
//: activity functions
//////////////////////////////////////////////////////////////////////////
double BP::squash(double net)
{
return 1/(1+exp(-net));
}
//: o is the output of the neuron
double BP::dx_squash(double o)
{
return o*(1-o);
}
double BP::linear(double net)
{
return net;
}
double BP::dx_linear(double o)
{
return 1;
}
//////////////////////////////////////////////////////////////////////////
//: saving and loading network file section here
//////////////////////////////////////////////////////////////////////////
//: saves the network to a specified file, for data format see the content
void BP::save(string file)
{
ofstream stream(file.c_str());
if(!stream.is_open())
throw new Exception("LUGD::save file: "+file + " cannot open to write");
//: file save format as following, input,output,weight sections
stream<<"INPUT="<<_ni<<endl;
stream<<"HIDDEN="<<_nh<<endl;
stream<<"OUTPUT="<<_no<<endl;
stream<<"WIH=";
int i;
int lih = _ni*_nh;
for(i=0;i<lih;i++)
{
if(i != lih-1) stream<<_wih[i]<<",";
else stream<<_wih[i]<<endl;
}
int lho = _nh*_no;
stream<<"WHO=";
for(i=0;i<lho;i++)
{
if(i != lho-1) stream<<_who[i]<<",";
else stream<<_who[i]<<endl;
}
stream<<"BH=";
for(i=0;i<_nh;i++)
{
if(i != _nh-1) stream<<_bh[i]<<",";
else stream<<_bh[i]<<endl;
}
stream<<"BO=";
for(i=0;i<_no;i++)
{
if(i != _no-1) stream<<_bo[i]<<",";
else stream<<_bo[i]<<endl;
}
}
//: load the network from a specified file to build a BP algorithm
BP* BP::load(string file)
{
ifstream stream(file.c_str());
if(!stream.is_open())
throw new Exception("Cannot open file: "+file);
//:reads input,output and weight section strings
string input,hidden,output,wih,who,bh,bo;
if(!getline(stream,input))
throw new Exception("File missing input-node number line,check for no blank line!");
if(!getline(stream,hidden))
throw new Exception("File missing hidden-node number line,check for no blank line!");
if(!getline(stream,output))
throw new Exception("File missing output-number data line,check for no blank line!");
if(!getline(stream,wih))
throw new Exception("File missing weights between input and hidden layer,check for no blank line!");
if(!getline(stream,who))
throw new Exception("File missing weights between hidden and output layer,check for no blank line!");
if(!getline(stream,bh))
throw new Exception("File missing bias weight of hidden layer,check for no blank line!");
if(!getline(stream,bo))
throw new Exception("File missing bias weight of output layer,check for no blank line!");
stream.close();
//: parses the three sections
vector<string> vi = xs::split(input," =;");
if(vi.size() != 2)
throw new Exception("input section format error!");
int ni = atoi(vi[1].c_str());
vector<string> vh = xs::split(hidden," =;");
if(vh.size() != 2)
throw new Exception("hidden section format error!");
int nh = atoi(vh[1].c_str());
vector<string> vo = xs::split(output," =;");
if(vo.size() != 2)
throw new Exception("output section format error!");
int no = atoi(vo[1].c_str());
vector<string> vwih = xs::split(wih," =,;");
if(vwih.size() != ni*nh+1 )
throw new Exception("wih section format error!");
vector<string> vwho= xs::split(who," =,;");
if(vwho.size() != nh*no+1 )
throw new Exception("who section format error!");
vector<string> vbh = xs::split(bh," =,;");
if(vbh.size() != nh+1 )
throw new Exception("BH section format error!");
vector<string> vbo = xs::split(bo," =,;");
if(vbo.size() != no+1 )
throw new Exception("BO section format error!");
BP_PARAM params;
params.input = ni;
params.hidden = nh;
params.output = no;
BP* bp = new BP(NULL,params);
for(int i=1;i<vwih.size();i++)
bp->_wih[i-1] = atof(vwih[i].c_str());
for(i=1;i<vwho.size();i++)
bp->_who[i-1] = atof(vwho[i].c_str());
for(i=1;i<vbh.size();i++)
bp->_bh[i-1] = atof(vbh[i].c_str());
for(i=1;i<vbo.size();i++)
bp->_bo[i-1] = atof(vbo[i].c_str());
return bp;
}
//========================================================================
/************************************************************************/
void main()
{
clock_t start,end;
start = clock();
BP_PARAM params;
ArffStream arff("arff//838.arff");
try
{
arff.open();
vector<Data> data;
while(arff.next())
{
data.push_back(Data(arff.data()));
}
params.input = 8;
params.hidden = 3;
params.output = 8;
params.learning_rate = 0.5;
params.random_range = 0.01;
params.max_epoch = 5000;
// BP* bp = BP::load("arff//bp.ini");
//
BP* bp = new BP(&data,params);
bp->train();
// bp->save("arff//bp.ini");
Data d = data[1];
cout<<d.to_string()<<endl;
bp->work(d);
cout<<d.to_string()<<endl;
delete bp;
}
catch(Exception* e)
{
cout<<e->message()<<endl;
delete e;
}
end = clock();
cout<<"Time eclipsed[s]:"<<(double)(end-start)/CLOCKS_PER_SEC<<endl;
}
/************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -