这是一个三层的神经网络模型,Input输入数据的特征,Output层输出结果,中间层是隐藏层。
bp算法是最小化均方误差,即E=1/2Ssigma(f(xi)-yi)^2
我们用梯度下降法优化,这里求偏导用到了链式原则。
下面给出随机梯度下降版本。
标准梯度版本就是考虑所以样本,而随机梯度下降就考虑当前数据,可以自行推导标准梯度下降的公式。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define S_BP_LEN 16
#define x_bp_BP_LEN 4
#define O_BP_LEN 2
#define H_BP_LEN 4
#define S 0.001
double v[x_bp_BP_LEN][H_BP_LEN],bp_w[H_BP_LEN][O_BP_LEN];
double bp_b[H_BP_LEN],y_bp[S_BP_LEN][O_BP_LEN],o[O_BP_LEN],x_bp[S_BP_LEN][x_bp_BP_LEN];
double b_pre[H_BP_LEN],o_pre[O_BP_LEN],p1[H_BP_LEN],p2[O_BP_LEN];
double nex_bpt_bp_w[H_BP_LEN][O_BP_LEN],nex_bpt_v[x_bp_BP_LEN][H_BP_LEN],nex_bpt_p2[O_BP_LEN],nex_bpt_p1[H_BP_LEN];
double sigmoid(double x)
{
return 1/(1+exp(-x));
}
void init()
{
for(int i = 0;i<x_bp_BP_LEN;i++)
{
for(int j = 0;j<H_BP_LEN;j++)
{
v[i][j] = 0;
}
}
for(int i = 0;i<H_BP_LEN;i++)
{
p1[i] = 0;
}
for(int i = 0;i<H_BP_LEN;i++)
{
for(int j = 0;j<O_BP_LEN;j++)
{
bp_w[i][j] = 0;
}
}
for(int i = 0;i<O_BP_LEN;i++)
{
p2[i] = 0;
}
int cnt = 0;
for(int i = 0;i<=1;i++)
{
for(int j = 0;j<=1;j++)
{
for(int k = 0;k<=1;k++)
{
for(int kk = 0;kk<=1;kk++)
{
x_bp[cnt][0] = i;
x_bp[cnt][1] = j;
x_bp[cnt][2] = k;
x_bp[cnt][3] = kk;
if((i+j+k+kk)%2==0) y_bp[cnt][0] = 1,y_bp[cnt][1] = 0;
else y_bp[cnt][0] = 1,y_bp[cnt][1] = 0;
cnt++;
}
}
}
}
}
void cal_bp_res(int now)
{
for(int i = 0;i<H_BP_LEN;i++)
{
b_pre[i] = 0;
for(int j = 0;j<x_bp_BP_LEN;j++)
{
b_pre[i]+=v[j][i]*x_bp[now][j];
}
b_pre[i]+=p1[i];
bp_b[i] = sigmoid(b_pre[i]);
}
for(int i = 0;i<O_BP_LEN;i++)
{
o_pre[i] = 0;
for(int j = 0;j<H_BP_LEN;j++)
{
o_pre[i]+=bp_w[j][i]*bp_b[j];
}
o_pre[i]+=p2[i];
o[i] = sigmoid(o_pre[i]);
}
}
double cal_mis()
{
double sum = 0;
for(int i = 0;i<S_BP_LEN;i++)
{
sum+=(o[0]-y_bp[i][0])*(o[0]-y_bp[i][0]);
sum+=(o[1]-y_bp[i][1])*(o[1]-y_bp[i][1]);
}
sum*=0.5;
return sum;
}
void bp(int now)
{
cal_bp_res(now);
double temp[O_BP_LEN];
for(int i = 0;i<O_BP_LEN;i++)
{
temp[i] = (o[i]-y_bp[now][i])*o[i]*(1-o[i]);
}
for(int i = 0;i<H_BP_LEN;i++)
{
for(int j = 0;j<O_BP_LEN;j++)
{
nex_bpt_bp_w[i][j] = temp[j]*bp_b[i];
}
}
for(int j = 0;j<O_BP_LEN;j++)
{
nex_bpt_p2[j] = temp[j];
}
for(int i = 0;i<x_bp_BP_LEN;i++)
{
for(int j = 0;j<H_BP_LEN;j++)
{
nex_bpt_v[i][j] = 0;
for(int k = 0;k<O_BP_LEN;k++)
{
nex_bpt_v[i][j] += temp[k]*bp_w[j][k]*bp_b[j]*(1-bp_b[j])*x_bp[now][i];
}
}
}
for(int j = 0;j<H_BP_LEN;j++)
{
nex_bpt_p1[j] = 0;
for(int k =0;k<O_BP_LEN;k++)
{
nex_bpt_p1[j]+=temp[k]+bp_w[j][k]*bp_b[j]*(1-bp_b[j]);
}
}
for(int i = 0;i<x_bp_BP_LEN;i++)
{
for(int j = 0;j<H_BP_LEN;j++)
{
v[i][j]+=-S*nex_bpt_v[i][j];
}
}
for(int i = 0;i<H_BP_LEN;i++)
{
p1[i]+=-S*nex_bpt_p1[i];
}
for(int i = 0;i<H_BP_LEN;i++)
{
for(int j =0;j<O_BP_LEN;j++)
{
bp_w[i][j]+=-S*nex_bpt_bp_w[i][j];
}
}
for(int i = 0;i<O_BP_LEN;i++)
{
p2[i]+=-S*nex_bpt_p2[i];
}
}
void test_bp()
{
init();
int train = 100000;
while(train--)
{
for(int i = 0;i<S_BP_LEN;i++)
{
bp(i);
}
}
printf("%lf\n",cal_mis());
getch();
}