// BP.cpp : Defines the entry point for the console application.
創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計、成都做網(wǎng)站、元寶網(wǎng)絡(luò)推廣、成都小程序開發(fā)、元寶網(wǎng)絡(luò)營銷、元寶企業(yè)策劃、元寶品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供元寶建站搭建服務(wù),24小時服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
//該程序?qū)崿F(xiàn)神經(jīng)網(wǎng)絡(luò)的BP算法,輸入節(jié)點數(shù),輸出節(jié)點數(shù),隱層數(shù),隱層節(jié)點數(shù)任意,由用戶決定。
//其中隱層數(shù)指的是總共層數(shù)包含輸出層,比如說異或算法為2層,第一層節(jié)點數(shù)為2,第二層也即輸出層節(jié)點數(shù)為1,輸入點數(shù)為2 。
//但是該程序?qū)Ξ惢蛩惴▽崿F(xiàn)并不理想,對多層多節(jié)點的神經(jīng)網(wǎng)絡(luò)有較好的結(jié)果
#include "stdafx.h"
#include "iostream.h"
#include time.h
#include stdlib.h
#include fstream
#include math.h
#include "stdio.h "
#define MAXCOUNT 1e5 //迭代訓(xùn)練次數(shù)上限 1的10的正5次冪
//精度0.001的隨機(jī)浮點數(shù),范圍在-0.5——0.5
//rand()取0到32767,最大為2147483647. %模運算表示余數(shù)為0到1000之間,所以乘上浮點數(shù)0。001f就是0-1之間的數(shù),再減去0.5,就是-0.5到+0.5
float randf()
{
return (float)((rand() % 1001) * 0.001f-0.5);
}
//高斯隨機(jī)數(shù)產(chǎn)生函數(shù)
//這樣生成的高斯分布隨機(jī)數(shù)序列的期望為0.0,方差為1.0。若指定期望為E,方差為V,則只需增加:X = X * V + E;
double gaussrand()
{
static double V1, V2, S;
static int phase = 0;
double X;
if(phase == 0) {
do {
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S = 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S );
phase = 1 - phase;
return X;
}
//定義一個多層前向BP網(wǎng)絡(luò)
class BP
{
public:
double ***p;//記錄所有的權(quán)值
double ***ddp;//記錄所有的權(quán)值增量
int *pnode;//記錄每一層的節(jié)點數(shù)
double **pnodey;//記錄每組每一層的節(jié)點的輸出值
double **ddlj;//記錄每組每一層的節(jié)點的ddlj
double **pX; //記錄輸入樣本
double **pY; //記錄輸入理想輸出值
int Sidenum; //隱層數(shù)目
int Inputnodenum;
int outputnodenum;
int yangbenzushu;
BP()
{
Sidenum=0;
Inputnodenum=0;
outputnodenum=0;
yangbenzushu=0;
}
~BP()
{
for(int m=0;mSidenum;m++)
{
for(int n=0;npnode[m+1];n++)
{
delete[] p[m][n];
delete[] ddp[m][n];
}
delete[] p[m];
delete[] ddp[m];
}
delete[] p;
delete[] ddp;
p=NULL;
ddp=NULL;
if(p==NULL)
delete [] pnode;
for(int M=0;MSidenum;M++)
{
delete[] pnodey[M];
delete[] ddlj[M];
}
delete[] pnodey;
delete[] ddlj;
pnodey=NULL;
ddlj=NULL;
}
//完成所有權(quán)值的初始化
void getW(int sidenum,int inputnodenum,int outputnodenum1,int yangbenzu)
{
Sidenum=sidenum;
yangbenzushu= yangbenzu;//樣本組數(shù)目
Inputnodenum=inputnodenum;
outputnodenum=outputnodenum1;
p=new double **[sidenum];//記錄所有權(quán)值
ddp=new double **[sidenum];//權(quán)值增量
pnode=new int [sidenum+1];//包含輸入層,輸出層每一層的節(jié)點數(shù).
for(int i=0;isidenum+1;i++)
{
int data=0;
cout"請輸入第"i"層節(jié)點數(shù)"endl;
cindata;
pnode[i]=data;
}
for (int j=0;jsidenum;j++) // 初始化權(quán)值, 不包含輸入層,但是包含輸出層.第0層表示第一個隱層
{
p[j]=new double* [pnode[j+1]]; //首先P[j]層有多少個節(jié)點,就有多少個指針,每個指針指向一個權(quán)值數(shù)組.因為p[j]是二級指針,存放的是某指針的地址,某指針可以指向一維數(shù)組.
ddp[j]=new double*[pnode[j+1]];//同上
for (int k=0;kpnode[j+1];k++)
{
ddp[j][k]=new double[pnode[j]+1];//表示第j層的第k個節(jié)點指向的是一個數(shù)組,這個數(shù)組里存的是這個節(jié)點的權(quán)值.
p[j][k]=new double[pnode[j]+1];
for (int t=0;tpnode[j]+1;t++) //pnode[j]+1 表示第j層的輸入點個數(shù).
{
ddp[j][k][t]=0;//每一層的權(quán)值初始化為0 表示的是第j層的第k個節(jié)點,第t個輸入的輸入權(quán)值.
if(t==0)p[j][k][t]=-fabs(randf());//每一層的閥值初始化 第0個元素.
else p[j][k][t]=randf();//每一層的權(quán)值初始化
}
}
}
//為記錄每一層的節(jié)點的輸出值和ddlj的指針開辟內(nèi)存
pnodey=new double *[Sidenum]; //一共有Sidenum層.
ddlj=new double *[Sidenum];
for(int p=0;pSidenum;p++)
{
pnodey[p] = new double [pnode[p+1]+1];//每層一共有節(jié)點數(shù)+1個輸出
ddlj[p]=new double [pnode[p+1]];// 這個是做什么的??
pnodey[p][0]=1;//每組每層的首值為1,這個值是為了與閾值相乘,這也是為什么會有上面+1個輸出
}
}
/**********************/
//每個節(jié)點輸出函數(shù)
double fas(double s)
{
double t;
t=1.0/(exp(-s)+1);
return t;
}
/************************************************/
//該函數(shù)用來記錄樣本值和理想輸出值
void INPUT(int yangbenzushu1 )
{
pY=new double*[yangbenzushu1];//yangbenzushu1數(shù)量個理想輸出
pX=new double*[yangbenzushu1];//yangbenzushu1數(shù)量個樣本
for(int yu=0;yuyangbenzushu1;yu++)
{
pX[yu]=new double[Inputnodenum+1];//每個樣本的維數(shù)是輸入點個數(shù)+1
pY[yu]=new double[outputnodenum+1];//輸出的維數(shù)也是輸出點個數(shù)+1
}
//每組樣本的首值賦為1, 這樣就可以使下標(biāo)對應(yīng)的比較好
for(int yu1=0;yu1yangbenzushu1;yu1++)
{
pX[yu1][0]=1;
pY[yu1][0]=1;
}
cout"請輸入樣本輸入值"endl;
for(int yuy=0;yuyyangbenzushu1;yuy++)
for(int yy=1;yy=Inputnodenum;yy++)
{
if(yy==Inputnodenum) coutendl;
cout"X["yuy"]""["yy"]="' ';
cinpX[yuy][yy];
}
cout"請輸入樣本理想輸出值"endl;
for(int yuy1=0;yuy1yangbenzushu1;yuy1++)
for(int yy1=1;yy1=outputnodenum;yy1++)
{ //if(yy==Inputnodenum) coutendl;
cout"Y["yuy1"]""["yy1"]="' ';
cinpY[yuy1][yy1];
}
}
/****************************************************************************/
//計算每個節(jié)點的輸出值
double computeYl(int KK)//KK代表第幾組組號
{
double sum1=0;
//把所有的層的每一個節(jié)點的輸出值算出來并記錄在pnodey里,不包含輸入點值
for(int y=0;ySidenum;y++)//層數(shù)
{
for(int r=1;rpnode[y+1]+1;r++)//本節(jié)點數(shù),加1是為了下標(biāo)好看
{
double sum=0;
for(int z=0;zpnode[y]+1;z++)//前一層的節(jié)點數(shù)
{
if(y==0)sum+= pX[KK][z]*p[y][r-1][z];
else
sum+=pnodey[y-1][z]*p[y][r-1][z];
}
pnodey[y][r]=fas(sum);
}
}
for(int j=1;j=outputnodenum;j++)
sum1+=pow(pY[KK][j]-pnodey[Sidenum-1][j],2);
return sum1;
}
/**********************************************************/
//Compute Back-Propagation-Errors
void ComputeBackPropagationErrors(int gf)//gf代表組號
{//計算所有的ddlj[][]
//for(int gf=0;gfyangbenzushu;gf++)//組數(shù)
for(int q=Sidenum-1;q=0;q--)//從最后一層開始
{
if(q==Sidenum-1)//如果是最外一層的話
{
for(int rt=0;rtpnode[q+1];rt++)//每層的節(jié)點數(shù)
ddlj[q][rt]=pnodey[q][rt+1]*(1-pnodey[q][rt+1])*(pY[gf][rt+1]-pnodey[q][rt+1]) ;
}
else
{
for(int ry=0;rypnode[q+1];ry++)
{
double sumtemp=0;
for(int fg=0;fgpnode[q+2];fg++)
sumtemp+=ddlj[q+1][fg]*p[q+1][fg][ry+1];
ddlj[q][ry] = pnodey[q][ry+1]*(1-pnodey[q][ry+1])* sumtemp;
}
}
}
//計算所有的ddp[][]
//for(int gf1=0;gf1yangbenzushu;gf1++)//組數(shù)
for(int l=0;lSidenum;l++)//層數(shù)
for(int JJ=0;JJpnode[l+1];JJ++)//每一層的節(jié)點數(shù)
for(int i=0;ipnode[l]+1;i++)//前一層的節(jié)點數(shù)
{
if(l==0)//如果是第一層的話,y值為輸入的X值
ddp[l][JJ][i]=ddlj[l][JJ]*pX[gf][i];
else
ddp[l][JJ][i]=ddlj[l][JJ]*pnodey[l-1][i];
}
}
/*************************************************************************/
void UpdatetheWeightsusingBPAlgorithm()
{
for(int cent=0;centSidenum;cent++)//層數(shù)
for(int J=0;Jpnode[cent+1];J++)//每一層的節(jié)點數(shù)
for(int i=0;ipnode[cent]+1;i++)//前一層的節(jié)點數(shù)
p[cent][J][i]+=0.2*ddp[cent][J][i];
}
/***************************************************************************/
double xunlianErrors()//定義訓(xùn)練誤差函數(shù)
{
double error=0;
double sum=0;
double temp=0;
double temp1=0;
for(int gf1=0;gf1yangbenzushu;gf1++)//組數(shù)
{
temp= computeYl(gf1);
//temp1=zhengquelv(gf1);
//sum+=temp1;
for(int jj=1;jj=outputnodenum;jj++)
coutpnodey[Sidenum-1][jj];
error+=temp;
}
// sum=sum/yangbenzushu;
cout"用訓(xùn)練集所得到的正確率:"sumendl;
return error/yangbenzushu;
}
/****************************************************************************/
double jiaoyanErrors(int yangbenzushu1 )//定義校驗誤差函數(shù)
{
double error=0;
double sum=0;
double temp=0;
double temp1=0;
for(int gf1=0;gf1yangbenzushu1;gf1++)//組數(shù)
{
temp= computeYl(gf1);
for(int jj=1;jj=outputnodenum;jj++)
coutpnodey[Sidenum-1][jj];
//temp1=zhengquelv(gf1);
//sum+=temp1;
error+=temp;
}
//sum=sum/yangbenzushu1;
//cout"用校驗集所得到的正確率:"sumendl;
return error/yangbenzushu1;
}
/********************************************************************/
double zhengquelv(int KK)
{
int count=0;
double av=0;
//for(int gf1=0;gf1yangbenzushu;gf1++)//組數(shù)
for(int jj=1;jj=outputnodenum;jj++)
{
if (pnodey[Sidenum-1][jj]0) pnodey[Sidenum-1][jj]=1;
else pnodey[Sidenum-1][jj]=0;
if(pY[KK][jj]==pnodey[Sidenum-1][jj])count++;
}
av=(double)count/outputnodenum;
return av;
}
/***********************************************************************/
void freeINput()
{
if(pX!=NULL)
{
for(int u=0;uyangbenzushu;u++)
delete []pX[u];
delete []pX;
pX=NULL;
}
if(pY!=NULL)
{
for(int u1=0;u1yangbenzushu;u1++)
delete []pY[u1];
delete []pY;
pY=NULL;
}
}
/***************************************************************/
//輸出所有的權(quán)值
void wputout()
{
for (int j=0;jSidenum;j++)
{
cout"第["j+1"]層權(quán)值為:"endl;
for (int k=0;kpnode[j+1];k++)
{
//if(k==pnode[j+1]-1) coutendl;
for (int t=0;tpnode[j]+1;t++)
{
coutp[j][k][t]' ';
if(t==pnode[j]) coutendl;
}
}
}
}
/**********************************************************/
};
void main()
{
BP bp;
int count=0;//用來統(tǒng)計所用的迭代次數(shù)
//FILE *fp;
int inputnodenum,outnodenum,sidenum,yangbenzunum;
double error;
cout"請輸入:輸入點數(shù),輸出點數(shù),隱層數(shù)"endl;
cininputnodenumoutnodenumsidenum;
cout"請輸入樣本組數(shù)"endl;
cinyangbenzunum;
//第一步初始化所有的權(quán)值
bp.getW(sidenum,inputnodenum,outnodenum,yangbenzunum);
//第二步輸入樣本組
bp.INPUT(yangbenzunum);
for(count++)
{
double sum=0;
double temp=0;
for(int fuzu=0;fuzuyangbenzunum;fuzu++)
{
//第三步計算所有y值
temp=bp點抗 puteYl(fuzu);
//第四步Compute Back-Propagation-Errors
bp.ComputeBackPropagationErrors(fuzu);
//第五步Update the Weights using BP Algorithm
bp.UpdatetheWeightsusingBPAlgorithm();
sum+=temp;
}
//第六步判斷是否收斂
error=sum/2*yangbenzunum;
//freopen("debug\\out.txt","w",stdout);
//fp=freopen( "out.txt", "w", stdout) ;
// coutcount' 'errorendl;
// fclose(stdout);//關(guān)閉文件
/*if(count==1000)couterrorendl;
if(count==1500)couterrorendl;
if(count==1600)couterrorendl;*/
//if(count==10000)couterrorendl;
if(error1.02)
{
cout"循環(huán)收斂""迭代次數(shù)為:"countendl;
//bp.freeINput();//釋放X Y空間
break;
}
}
cout"權(quán)值為:"endl;
bp.wputout();
double XUNLIANER=bp.xunlianErrors();
//cout"訓(xùn)練誤差為:"XUNLIANERendl;
bp.freeINput();//釋放X Y空間
/*
cout"請輸入校驗樣本: "endl;
int jiaoyannum=0;
cinjiaoyannum;
bp.INPUT(jiaoyannum);
double jiaoyanER=bp.jiaoyanErrors(jiaoyannum);
cout"校驗誤差為:"jiaoyanERendl;
//fclose( stdout ) ;*/
}
見附件,一個基本的用java編寫的BP網(wǎng)絡(luò)代碼。
BP(Back Propagation)神經(jīng)網(wǎng)絡(luò)是86年由Rumelhart和McCelland為首的科學(xué)家小組提出,是一種按誤差逆?zhèn)鞑ニ惴ㄓ?xùn)練的多層前饋網(wǎng)絡(luò),是目前應(yīng)用最廣泛的神經(jīng)網(wǎng)絡(luò)模型之一。BP網(wǎng)絡(luò)能學(xué)習(xí)和存貯大量的輸入-輸出模式映射關(guān)系,而無需事前揭示描述這種映射關(guān)系的數(shù)學(xué)方程。它的學(xué)習(xí)規(guī)則是使用最速下降法,通過反向傳播來不斷調(diào)整網(wǎng)絡(luò)的權(quán)值和閾值,使網(wǎng)絡(luò)的誤差平方和最小。BP神經(jīng)網(wǎng)絡(luò)模型拓?fù)浣Y(jié)構(gòu)包括輸入層(input)、隱層(hidden layer)和輸出層(output layer)。
你“行”的概念是什么? 用C++之后在matlab中編譯成mex后,使用的時候一行代碼就可以了。
同理,實現(xiàn)算法本身中基本的運算過程是不是展開,用什么、語言?
再者,什么類型的網(wǎng)絡(luò)? 普通的全連接? 局部連接的卷積神經(jīng)網(wǎng)絡(luò)? Deep Residual Network? 不同類型的網(wǎng)絡(luò)結(jié)構(gòu)上會不一樣。