BP 神经网络 C++实现

BP.h

#ifndef _BP_H_
#define _BP_H_
 
#include 
 
#define LAYER    3        //三层神经网络
#define NUM      10       //每层的最多节点数
 
#define A        30.0
#define B        10.0     //A和B是S型函数的参数
#define ITERS    1000     //最大训练次数
#define ETA_W    0.0035   //权值调整率
#define ETA_B    0.001    //阀值调整率
#define ERROR    0.002    //单个样本允许的误差
#define ACCU     0.005    //每次迭代允许的误差
 
#define Type double
#define Vector std::vector
 
struct Data
{
    Vector x;       //输入数据
    Vector y;       //输出数据
};
 
class BP{
 
public:
 
    void GetData(const Vector);
    void Train();
    Vector ForeCast(const Vector);
 
private:
 
    void InitNetWork();         //初始化网络
    void GetNums();             //获取输入、输出和隐含层节点数
    void ForwardTransfer();     //正向传播子过程
    void ReverseTransfer(int);  //逆向传播子过程
    void CalcDelta(int);        //计算w和b的调整量
    void UpdateNetWork();       //更新权值和阀值
    Type GetError(int);         //计算单个样本的误差
    Type GetAccu();             //计算所有样本的精度
    Type Sigmoid(const Type);   //计算Sigmoid的值
 
private:
    int in_num;                 //输入层节点数
    int ou_num;                 //输出层节点数
    int hd_num;                 //隐含层节点数
 
    Vector data;          //输入输出数据
 
    Type w[LAYER][NUM][NUM];    //BP网络的权值
    Type b[LAYER][NUM];         //BP网络节点的阀值
     
    Type x[LAYER][NUM];         //每个神经元的值经S型函数转化后的输出值,输入层就为原值
    Type d[LAYER][NUM];         //记录delta学习规则中delta的值
};
 
#endif  //_BP_H_


BP.CPP

#include 
#include 
#include 
#include 
#include "BP.h"

//获取训练所有样本数据
void BP::GetData(const Vector _data)
{
	data = _data;
}

//开始进行训练
void BP::Train()
{
	printf("Begin to train BP NetWork!\n");
	GetNums();
	InitNetWork();
    int num = data.size();

	for(int iter = 0; iter <= ITERS; iter++)
	{
		for(int cnt = 0; cnt < num; cnt++)
		{
			//第一层输入节点赋值
			for(int i = 0; i < in_num; i++)
				x[0][i] = data.at(cnt).x[i];

			while(1)
			{
				ForwardTransfer();     
                if(GetError(cnt) < ERROR)    //如果误差比较小,则针对单个样本跳出循环
					break;
                ReverseTransfer(cnt);  
			}
		}
		printf("This is the %d th trainning NetWork !\n", iter);

		Type accu = GetAccu();
		printf("All Samples Accuracy is %lf\n", accu);
		if(accu < ACCU) break;
	}
	printf("The BP NetWork train End!\n");
}

//根据训练好的网络来预测输出值
Vector BP::ForeCast(const Vector data)
{
	int n = data.size();
	assert(n == in_num);
    for(int i = 0; i < in_num; i++)
		x[0][i] = data[i];
    
	ForwardTransfer();
	Vector v;
	for(int i = 0; i < ou_num; i++)
		v.push_back(x[2][i]);
	return v;
}

//获取网络节点数
void BP::GetNums()
{
	in_num = data[0].x.size();                         //获取输入层节点数
	ou_num = data[0].y.size();                         //获取输出层节点数
    hd_num = (int)sqrt((in_num + ou_num) * 1.0) + 5;   //获取隐含层节点数
	if(hd_num > NUM) hd_num = NUM;                     //隐含层数目不能超过最大设置
}

//初始化网络
void BP::InitNetWork()
{
    memset(w, 0, sizeof(w));      //初始化权值和阀值为0,也可以初始化随机值
	memset(b, 0, sizeof(b));
}

//工作信号正向传递子过程
void BP::ForwardTransfer()
{
	//计算隐含层各个节点的输出值
	for(int j = 0; j < hd_num; j++)
	{
		Type t = 0;
		for(int i = 0; i < in_num; i++)
			t += w[1][i][j] * x[0][i];
		t += b[1][j];
		x[1][j] = Sigmoid(t);
	}

	//计算输出层各节点的输出值
	for(int j = 0; j < ou_num; j++)
	{
		Type t = 0;
		for(int i = 0; i < hd_num; i++)
			t += w[2][i][j] * x[1][i];
		t += b[2][j];
		x[2][j] = Sigmoid(t);
	}
}

//计算单个样本的误差
Type BP::GetError(int cnt)
{
	Type ans = 0;
	for(int i = 0; i < ou_num; i++)
		ans += 0.5 * (x[2][i] - data.at(cnt).y[i]) * (x[2][i] - data.at(cnt).y[i]);
	return ans;
}

//误差信号反向传递子过程
void BP::ReverseTransfer(int cnt)
{
	CalcDelta(cnt);   
	UpdateNetWork();
}

//计算所有样本的精度
Type BP::GetAccu()
{
	Type ans = 0;
	int num = data.size();
	for(int i = 0; i < num; i++)
	{
		int m = data.at(i).x.size();
		for(int j = 0; j < m; j++)
			x[0][j] = data.at(i).x[j];
        ForwardTransfer();
		int n = data.at(i).y.size();
		for(int j = 0; j < n; j++)
            ans += 0.5 * (x[2][j] - data.at(i).y[j]) * (x[2][j] - data.at(i).y[j]);
	}
	return ans / num;
}

//计算调整量
void BP::CalcDelta(int cnt)
{
	//计算输出层的delta值
	for(int i = 0; i < ou_num; i++)
		d[2][i] = (x[2][i] - data.at(cnt).y[i]) * x[2][i] * (A - x[2][i]) / (A * B);
	//计算隐含层的delta值
	for(int i = 0; i < hd_num; i++)
	{
		Type t = 0;
		for(int j = 0; j < ou_num; j++)
			t += w[2][i][j] * d[2][j];
		d[1][i] = t * x[1][i] * (A - x[1][i]) / (A * B);
	}
}

//根据计算出的调整量对BP网络进行调整
void BP::UpdateNetWork()
{
	//隐含层和输出层之间权值和阀值调整
	for(int i = 0; i < hd_num; i++)
	{
		for(int j = 0; j < ou_num; j++)
			w[2][i][j] -= ETA_W * d[2][j] * x[1][i]; 
	}
	for(int i = 0; i < ou_num; i++)
		b[2][i] -= ETA_B * d[2][i];

	//输入层和隐含层之间权值和阀值调整
	for(int i = 0; i < in_num; i++)
	{
		for(int j = 0; j < hd_num; j++)
			w[1][i][j] -= ETA_W * d[1][j] * x[0][i];
	}
	for(int i = 0; i < hd_num; i++)
		b[1][i] -= ETA_B * d[1][i];
}

//计算Sigmoid函数的值
Type BP::Sigmoid(const Type x)
{
	return A / (1 + exp(-x / B));
}

Test.CPP

#include 
#include 
#include 
 
#include "BP.h"
 
using namespace std;
 
double sample[41][4]= 
{ 
    {0,0,0,0}, 
    {5,1,4,19.020}, 
    {5,3,3,14.150}, 
    {5,5,2,14.360}, 
    {5,3,3,14.150}, 
    {5,3,2,15.390}, 
    {5,3,2,15.390}, 
    {5,5,1,19.680}, 
    {5,1,2,21.060}, 
    {5,3,3,14.150}, 
    {5,5,4,12.680}, 
    {5,5,2,14.360}, 
    {5,1,3,19.610}, 
    {5,3,4,13.650}, 
    {5,5,5,12.430}, 
    {5,1,4,19.020}, 
    {5,1,4,19.020}, 
    {5,3,5,13.390}, 
    {5,5,4,12.680}, 
    {5,1,3,19.610}, 
    {5,3,2,15.390}, 
    {1,3,1,11.110}, 
    {1,5,2,6.521}, 
    {1,1,3,10.190}, 
    {1,3,4,6.043}, 
    {1,5,5,5.242}, 
    {1,5,3,5.724}, 
    {1,1,4,9.766}, 
    {1,3,5,5.870}, 
    {1,5,4,5.406}, 
    {1,1,3,10.190}, 
    {1,1,5,9.545}, 
    {1,3,4,6.043}, 
    {1,5,3,5.724}, 
    {1,1,2,11.250}, 
    {1,3,1,11.110}, 
    {1,3,3,6.380}, 
    {1,5,2,6.521}, 
    {1,1,1,16.000}, 
    {1,3,2,7.219}, 
    {1,5,3,5.724} 
}; 
 
int main()
{
    Vector data;
    for(int i = 0; i < 41; i++)
    {
        Data t;
        for(int j = 0; j < 3; j++)
            t.x.push_back(sample[i][j]);
        t.y.push_back(sample[i][3]);
        data.push_back(t);
    }
    BP *bp = new BP();
    bp->GetData(data);
    bp->Train();
 
    while(1)
    {
        Vector in;
        for(int i = 0; i < 3; i++)
        {
            Type v;
            scanf("%lf", &v);
            in.push_back(v);
        }
        Vector ou;
        ou = bp->ForeCast(in);
        printf("%lf\n", ou[0]);
    }
    return 0;
}









你可能感兴趣的:(caffe)