神经网络-3层BP网的VC动态库封装
来源:互联网 发布:单片机仿真软件下载 编辑:程序博客网 时间:2024/04/29 04:35
神经网络-3层BP网的VC动态库封装实现
神经网络是一个大范畴,这里讨论 误差反向传播网络(BP网络) ,基本原理是通过分析网络输出的误差来调整网络的自由参数,使网络的大量自由参数平衡到一个收敛值,参数的收敛过程是训练过程,训练完成后网络基本稳定就可以投入应用.
网络运作过程:
简单的单层BP网具有N0个输入x,还含有N0个自由参数w(权值)
1.正向变换输出
x和w求内积记为v,v再通过一个激活函数后输出即为网络输出,一般的激活函数要求为sigmoid非线性函数.而具有sigmoid非线性性的其中一个广泛应用的函数为logistic函数,表达式为
logistic(v)=1/(1+exp(-av))
其中a为函数斜率.如此即得到网络的输出值
另外比较常用的还可以是双曲正切函数.根据需要选择.
2.误差反向传播
误差计算为e=d-o ,其中d为期望的网络输出收敛值,o为网络实际输出.
首先计算输出结点的 局部梯度域
s=e*f’(v)
f为激活函数,f’表示导数
权值调整值
delta=n*s*y
n为学习率,取值0.01~0.9
s是上面计算的局部梯度域
y是此结点的上次输出
然后进行权值调整
w=w+delta
迭代足够多次后网络即可收敛,达到训练目的.
训练过程就像教育一个小孩一样,通过不断教育教会小孩什么使对的什么是错的,因此神经网络又属于人工智能范畴.
训练的本质是使网络的自由参数w收敛到一个期望的水平,收敛使通过误差反向传播实现的,通过误差计算自由参数的调整值,误差将越来越小.
网络的本质是低维特征空间逼近高维特征空间的高度非线性映射.
BP网络不单只可以有一层,还可以设置多层,当然误差的计算就复杂一点.
下面是我用VC.NET制作的3层BP网络的DLL库,一个输入层,一个输出层和一个隐藏层,各层神经元数可以根据需要调整.网络为全连接结构,采用logistic函数作为激活函数.函数斜率固定为1,学习率可以自由调整.
//--------------VC.NET DLL
//---------------------------以下开始为实际代码.
int N0,N1,N2; //------结点数
double *a1,*a2;//-------权值
double *x;//------输入
double a;//----logistic 函数参数
double *o1,*o2;//-------各神经元输出标量
double *s1,*s2;//---------局部梯度域
double n; //-----------学习率
//----------网络参数初始化
extern "C" __declspec(dllexport)
bool InitNetwork(int n0,int n1,int n2,double nn=0.8)
{
N0=n0;
N1=n1;
N2=n2;
a1=new double[(N1+1)*(N0+1)];
a2=new double[N2*(N1+1)];
x=new double[(N0+1)];
o1=new double[(N1+1)];
o2=new double [N2];
s1=new double [(N1+1)];
s2=new double [N2];
//----------网络初始化
for(int i=0;i<(N1+1)*(N0+1);i++)
{
a1[i]=1;
}
for(int i=0;i<(N2)*(N1+1);i++)
{
a2[i]=1;
}
a=1;//----logistic 函数参数
n=nn; //---------学习率
return true;
}
//-------------释放网络内存
extern "C" __declspec(dllexport)
bool ReleaseNetwork()
{
delete a1;
delete a2;
delete x;
delete o1;
delete o2;
delete s1;
delete s2;
return true;
}
//-----------------网络公共计算
bool CommonWork()
{
int i,j;
//----------------网络公共计算
//---------计算隐藏层的输出/输出层端的输入
double v=0;
for(i=0;i<N1;i++)
{
v=0;
for(j=0;j<N0+1;j++)
{
v+=(a1[i*(N0+1)+j]*x[j]);//线性求和
}
//logistic函数(sigmoid)
o1[i]=(double)1.0/(1.0+exp(-a*v));
}
o1[N1]=1; //--------隐藏层固定偏置=1
//------------计算输出层输出
for(i=0;i<N2;i++)
{
v=0;
for(j=0;j<N1+1;j++)
{
v+=(a2[i*(N1+1)+j]*o1[j]);//线性求和
}
//logistic函数(sigmoid)
o2[i]=(double)1.0/(1.0+exp(-a*v));
}
return true;
}
//---------------网络分类,输入范围为[0,1],输出为N2个神经元量化后的输出.
extern "C" __declspec(dllexport)
bool Work(double *input,int *output)
{
int i;
for(i=0;i<N0;i++)
{
x[i]=input[i];
}
x[N0]=1;//-------输入层固定偏置
CommonWork();
//------对输出层神经元的输出量化到0或1
for(i=0;i<N2;i++)
{
if(o2[i]<0.5)
output[i]=0;
else
output[i]=1;
}
return true;
}
//------------训练
extern "C" __declspec(dllexport)
bool Tran(double *input,int *expected)
{
int i=0,j=0;
for(i=0;i<N0;i++)
{
x[i]=input[i];
}
x[N0]=1;//-------输入层固定偏置
CommonWork();
//-------------输出层调节
//----------计算输出层的局部梯度域
for(i=0;i<N2;i++)
{
s2[i]=a*((double)expected[i]-o2[i])*o2[i]*(1-o2[i]);
}
///-------------调整权值
for(i=0;i<N2;i++)
{
for(j=0;j<N1+1;j++)
{
a2[i*(N1+1)+j]+=(n*s2[i]*o1[j]);
}
}
//----------------隐藏层调节
//----------计算隐藏层结点局部梯度域
for(i=0;i<N1+1;i++)
{
double ek=0;
for(j=0;j<N2;j++)
{
ek+=(s2[j]*a1[j*(N1+1)+i]);
}
s1[i]=a*o1[i]*(1-o1[i])*ek;
}
///-------------调整权值
for(i=0;i<N1+1;i++)
{
for(j=0;j<N0+1;j++)
{
a1[i*(N0+1)+j]+=(n*s1[i]*x[j]);
}
}
return true;
}
extern "C" __declspec(dllexport)
bool SaveNetwork(char *filePath)
{
fstream f;
f.open(filePath,ios_base::out|ios_base::trunc);
int i;
for(i=0;i<(N1+1)*(N0+1);i++)
{
f<<a1[i]<<" ";
}
for(i=0;i<N2*(N1+1);i++)
{
f<<a2[i]<<" ";
}
f.close();
return true;
}
extern "C" __declspec(dllexport)
bool LoadNetwork(char *filePath)
{
fstream f;
f.open(filePath,ios_base::in);
int i;
for(i=0;i<(N1+1)*(N0+1);i++)
{
f>>a1[i];
}
for(i=0;i<N2*(N1+1);i++)
{
f>>a2[i];
}
f.close();
return true;
}
//---------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
附带一个使用SAMPLE
设置8各输入信号,4各隐藏层神经元,1个输出神经元
//-----------------------VC.NET 控制台程序
#include<iostream>
#include<Windows.h>
typedef bool (*pInitNetwork)(int n0,int n1,int n2,double nn);
typedef bool (*pReleaseNetwork)();
typedef bool (*pWork)(double *input,int *output);
typedef bool (*pTran)(double *input,int *expected);
typedef bool (*pSaveNetwork)(char *filePath);
typedef bool (*pLoadNetwork)(char *filePath);
pInitNetwork InitNetwork=NULL;
pReleaseNetwork ReleaseNetwork=NULL;
pWork Work=NULL;
pTran Tran=NULL;
pSaveNetwork SaveNetwork=NULL;
pLoadNetwork LoadNetwork=NULL;
int main(int argc, char* argv[])
{
int i=0,j=0,k=0;
HMODULE h=::LoadLibrary("F://projects//BPNetwork3//Release//BPNetwork3.dll");
if(h==NULL)
{
std::cout<<"装载DLL错误/n";
system("pause");
return -1;
}
InitNetwork=(pInitNetwork)::GetProcAddress(h,"InitNetwork");
ReleaseNetwork=(pReleaseNetwork)::GetProcAddress(h,"ReleaseNetwork");
Work=(pWork)::GetProcAddress(h,"Work");
Tran=(pTran)::GetProcAddress(h,"Tran");
SaveNetwork=(pSaveNetwork)::GetProcAddress(h,"SaveNetwork");
LoadNetwork=(pLoadNetwork)::GetProcAddress(h,"LoadNetwork");
if(InitNetwork==NULL||ReleaseNetwork==NULL||Work==NULL||Tran==NULL||SaveNetwork==NULL||LoadNetwork==NULL)
{
std::cout<<"取函数地址错误/n";
::FreeLibrary(h);
system("pause");
return -1;
}
InitNetwork(8,4,1,0.8);//-----------初始化 8个输入,4个隐藏神经元,1个输出,学习率0.8
double x[8];//8个输入
int y[1];//1个输出
//-------------训练前
for(i=0;i<10;i++)
{
//-----------转换成8位2进制数输入
for(k=0;k<8;k++)
{
x[k]=(double)((i>>k) & 1);
}
Work(x,y);//送入网络分类
std::cout<<"输入"<<i<<"/t输出"<<y[0]<<"/n";//显示输出
}
std::cout<<"/n/n/n/n";
//-----------------开始100轮训练,目标是训练网络具有区分0到9的数是奇数还是偶数的能力,奇数输出1,偶数输出0
int expected=0;//期望值
for(i=0;i<1000;i++)
{
for(j=0;j<10;j++)
{
//转成8位2进制数作为网络的8个输入
for(k=0;k<8;k++)
{
x[k]=(double)((j>>k) & 1);
}
expected=j%2;//期望结果
Tran(x,&expected);//训练
}
}
//-------------训练完成,下面检验训练成果
for(i=0;i<10;i++)
{
//-----------转换成8位2进制数输入
for(k=0;k<8;k++)
{
x[k]=(double)((i>>k) & 1);
}
Work(x,y);//送入网络分类
std::cout<<"输入"<<i<<"/t输出"<<y[0]<<"/n";//显示网络输出
}
ReleaseNetwork();
::FreeLibrary(h);
system("pause");
return 0;
}
//--------------------------------
经过实际运行,这个程序学会了区分0到9之间的数字是奇数还是偶数的能力.实验成功.
程序的下载地址为
http://www.lingch.net/myproducts/BPNetwork.rar
此网络的结构如图
神经网络已经广泛应用于模式识别和模式分类上.
- 神经网络-3层BP网的VC动态库封装
- c语言实现3层bp神经网络
- 神经网络BP推导及caffe中卷积层的实现
- BP神经网络的优缺点
- BP神经网络的基本原理
- BP神经网络的实现
- BP神经网络的学习
- BP神经网络的理解
- BP神经网络的分类
- BP神经网络的应用
- BP神经网络的结构
- BP神经网络的优缺点
- BP神经网络的讲解
- BP神经网络的缺点
- 基础的BP神经网络
- BP神经网络的实现
- 神经网络学习笔记3:BP神经网络的实现及其应用
- BP神经网络的Java实现
- 【推荐实例】一个典型的多线程的程序
- 如何调用NetMessageBufferSend发送消息?(改编)
- 浅谈PB使用心得(一)(原创)
- 如何在PB中使用ASCII码为0的字符?(原创)
- 如何在PB中统计EXCEL文件的行列数?(原创)
- 神经网络-3层BP网的VC动态库封装
- java线程并发包util.concurrent的研究(五)
- 如何跨进程发送字符串?(收藏)
- 2个三角了,呵呵
- 管理故事:猴子爬山
- 我的开场白
- 字符串转为16进制
- Java更新XML的四种常用方法简介 (转)
- 16进制和字符串之间转换