/*
人工神经网络BP算法思想: 神经网络一般分为3层(也可以多层),包括输入层,隐含层和输出层。通过有监督的学习拟合非线性函数。假如输入层有3个神经元,隐含层有5个神经元,输出层有1个神经元。有监督的学习是指既给了输入也给了输出再进行样本训练。可以把该神经网络看做3维向量的输入,一维的输出。每一层的神经元与相邻的一层的神经元全连接,同层的神经元不连接。
比如样本A的输入是{1,2,3},输出是{1},样本B的输入是{2,1,3},输出是{2},当然还有其他的样本,先通过前向传播得到神经元实际的输出值,计算期望值(即样本给的输出值)与输出值得均方误差,如果误差非常小,就不需要调整,否则反向传播调整连接权值(调整涉及到数学中的一些微分的知识)。直到拟合程度比较好时结束训练。此时有一个新的样本输入,不知道输出值,可以通过此神经网络预测输出值。
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<time.h>
#include<fstream>
#include<cstdlib>
using namespace std;
#define RANDOM rand()/32767.0
const int Layer_Max=5; /**神经网络层数**/
const double PI=3.1415927; /**圆周率**/
const int Layer_number[Layer_Max]={2,4,4,2,1} ; /**每层神经元个数**/
const int Neural_Max=4; /**每层最大神经元个数**/
const int InMax=21; /**样本输入个数**/
ofstream Out_W_File("All_W.txt",ios::out);
ofstream Out_Error("Error.txt",ios::out);
/**定义类BP**/
class BP{
public:
BP();
void BP_Print(); /**打印权系数**/
double F(double x); /**激发函数**/
double Y(double x1,double x2); /**要逼近的函数**/
double NetWorkOut(int x1,int x2); /**网络输出,它的输入为第input个样本**/
void AllLayer_D(int x1,int x2); /**求所有神经元的输出误差微分**/
void Change_W(); /**改变权系数**/
void Train(); /**训练函数**/
void After_Train_Out();
double Cost(double out,double Exp); /**代价函数**/
private:
double W[Layer_Max][Neural_Max][Neural_Max];
/**W[i][j][k]表示第i层第j个神经元连接到前一层第k个神经元**/
double Input_Net[2][InMax];/**表示第i个样本的输入x1,x2**/
double Out_Exp[InMax][InMax]; /**期望输出**/
double Layer_Node[Layer_Max][Neural_Max]; /**各神经元的输出**/
double D[Layer_Max][Neural_Max]; /**各神经元的误差微分**/
double Study_Speed; /**学习率**/
double e;
};
BP::BP(){
srand(time(NULL));
for(int i=1;i<Layer_Max;i++){
for(int j=0;j<Layer_number[i];j++){
for(int k=0;k<Layer_number[i-1]+1;k++) W[i][j][k]=RANDOM; /**权系数**/
//Q[i][j]=RANDOM; /**初始化各神经元阈值**/
}
}
/**输入和输出归一化**/
for(int l=0;l<InMax;l++){ /**输入的x1,x2**/
Input_Net[0][l]=l*0.05;
Input_Net[1][l]=1-l*0.05;
}
for(int i=0;i<InMax;i++){
for(int j=0;j<InMax;j++){
Out_Exp[i][j]=Y(Input_Net[0][i],Input_Net[1][j]); /**期望输出**/
Out_Exp[i][j]=Out_Exp[i][j]/3.000000; /**归一化**/
}
}
Study_Speed=0.5; /**初始化学习度**/
e=0.0001; /**误差限制**/
}
double BP::F(double x){ return (1.0/(1+exp(-x))); } /**Sigmoid函数**/
double BP::Y(double x1,double x2){
double temp;
temp=pow(x1-1,4)+2*pow(x2,2);
return temp;
}
/**代价函数**/
double BP::Cost(double Out,double Exp){
return (pow(Out-Exp,2)); /** 计算(Ok-dk)^2 **/
}
double BP::NetWorkOut(int x1,int x2){
int i,j,k;
double N_node[Layer_Max][Neural_Max];/**表示 第i层 第j个神经元 的总输入**/
/**第0层的神经元为输入,不用权系数和阈值**/
N_node[0][0]=Input_Net[0][x1];
Layer_Node[0][0]=Input_Net[0][x1];
N_node[0][1]=Input_Net[1][x2];
Layer_Node[0][1]=Input_Net[1][x2];
for(i=1;i<Layer_Max;i++){
for(j=0;j<Layer_number[i];j++){
N_node[i][j]=0.0;
for(k=0;k<Layer_number[i-1];k++){
N_node[i][j]+=Layer_Node[i-1][k]*W[i][j][k];
}
N_node[i][j]=N_node[i][j]-W[i][j][k]; /**减掉阈值**/
Layer_Node[i][j]=F(N_node[i][j]); /**得到输出**/
}
}
return Layer_Node[Layer_Max-1][0]; /**最后一层的输出**/
}
void BP::AllLayer_D(int x1,int x2){
int i,j,k;
double temp;
D[Layer_Max-1][0]=Layer_Node[Layer_Max-1][0]*(1-Layer_Node[Layer_Max-1][0])
*(Layer_Node[Layer_Max-1][0]-Out_Exp[x1][x2]);/** Ok*(1-Ok)*(Ok-dk) **/
for(i=Layer_Max-1;i>0;i--){
for(j=0;j<Layer_number[i-1];j++){
temp=0;
for(k=0;k<Layer_number[i];k++) temp=temp+W[i][k][j]*D[i][k];/****/
D[i-1][j]=Layer_Node[i-1][j]*(1-Layer_Node[i-1][j])*temp;
}
}
}
void BP::Change_W(){
int i,j,k;
for(i=1;i<Layer_Max;i++){
for(j=0;j<Layer_number[i];j++){
for(k=0;k<Layer_number[i-1];k++){
W[i][j][k]=W[i][j][k]-Study_Speed*D[i][j]*Layer_Node[i-1][k];
}
W[i][j][k]=W[i][j][k]+Study_Speed*D[i][j]; /** 修改阈值,相当于-(-1)*Study_Speed*D[i][j] **/
}
}
}
void BP::Train(){
int i,j;
int ok=0;
double Out;
long int count=0;
double err;
ofstream Out_count("Out_count.txt",ios::out);
/**权系数变化保存在文件里**/
ofstream outWFile1("W[2][0][0].txt",ios::out);
ofstream outWFile2("W[2][1][1].txt",ios::out);
ofstream outWFile3("W[1][0][0].txt",ios::out);
ofstream outWFile4("W[1][1][0].txt",ios::out);
ofstream outWFile5("W[3][0][1].txt",ios::out);
while(ok<441){ /**训练21*21个样本,当所有的误差精度都满足要求才退出**/
count++;
for(i=0,ok=0;i<InMax;i++){
for(j=0;j<InMax;j++){
Out=NetWorkOut(i,j);
AllLayer_D(i,j);
err=Cost(Out,Out_Exp[i][j]); /**计算误差**/
if(err<e) ok++; /**是否满足误差精度**/
else Change_W(); /**修改权系数**/
}
}
if(count%1000==0){
cout<<count<<" "<<err<<endl;
Out_count<<count<<",";
Out_Error<<err<<",";
outWFile1<<W[2][0][0]<<",";
outWFile2<<W[2][1][1]<<",";
outWFile3<<W[1][0][0]<<",";
outWFile4<<W[1][1][0]<<",";
outWFile5<<W[3][0][1]<<",";
for(int p=1;p<Layer_Max;p++){
for(int j=0;j<Layer_number[p];j++){
for(int k=0;k<Layer_number[p-1]+1;k++){
Out_W_File<<'W'<<'['<<p<<']'
<<'['<<j<<']'
<<'['<<k<<']'
<<'='<<W[p][j][k]<<' '<<' ';
}
}
}
Out_W_File<<'
'<<'
';
}
}
cout<<err<<endl;
}
void BP::BP_Print(){
cout<<"训练后的权系数"<<endl;
for(int i=1;i<Layer_Max;i++){
for(int j=0;j<Layer_number[i];j++){
for(int k=0;k<Layer_number[i-1]+1;k++) cout<<W[i][j][k]<<" ";
cout<<endl;
}
}
cout<<endl<<endl;
}
void BP::After_Train_Out(){
int i,j;
ofstream Out_x1("Out_x1.txt",ios::out);
ofstream Out_x2("Out_x2.txt",ios::out);
ofstream Out_Net("Out_Net.txt",ios::out);
ofstream Out_Exp("Out_Exp.txt",ios::out);
ofstream W_End("W_End.txt",ios::out);
ofstream Q_End("Q_End.txt",ios::out);
ofstream Array("Array.txt",ios::out);
ofstream Out_x11("x1.txt",ios::out);
ofstream Out_x22("x2.txt",ios::out);
ofstream Result1("result1.txt",ios::out);
ofstream Out_x111("x11.txt",ios::out);
ofstream Out_x222("x22.txt",ios::out);
ofstream Result2("result2.txt",ios::out);
for(i=0;i<InMax;i++){
for(j=0;j<InMax;j++){
Out_x11<<Input_Net[0][i]<<",";
Out_x22<<Input_Net[1][j]<<",";
Result1<<3*NetWorkOut(i,j)<<",";
Out_x1<<Input_Net[0][i]<<",";
Array<<Input_Net[0][i]<<" ";
Out_x2<<Input_Net[1][j]<<",";
Array<<Input_Net[1][j]<<" ";
Out_Net<<3*NetWorkOut(i,j)<<",";
Array<<Y(Input_Net[0][i],Input_Net[1][j])<<" ";
Out_Exp<<Y(Input_Net[0][i],Input_Net[1][j])<<",";
Array<<3*NetWorkOut(i,j)<<" ";
Array<<'
';
}
Out_x1<<'
';
Out_x2<<'
';
Out_x11<<'
';
Out_x22<<'
';
Result1<<'
';
}
for(j=0;j<InMax;j++){
for(i=0;i<InMax;i++){
Out_x111<<Input_Net[0][i]<<",";
Out_x222<<Input_Net[1][j]<<",";
Result2<<3*NetWorkOut(i,j)<<",";
}
Out_x111<<'
';
Out_x222<<'
';
Result2<<'
';
}
for(i=0;i<Layer_Max;i++){
for(j=0;j<Layer_number[i];j++){
for(int k=0;k<Layer_number[i-1]+1;k++) W_End<<W[i][j][k]<<",";
}
}
}
int main(void){
/*
BP B;
B.Train();
B.BP_Print();
B.After_Train_Out();
*/
return 0;
}