BP神经网络学习笔记_附源代码
BP神经网络基本原理:
误差逆传播(back propagation, BP)算法是一种计算单个权值变化引起网络性能变化的较为简单的方法。由于BP算法过程包含从输出节点开始,反向地向第一隐含层(即最接近输入层的隐含层)传播由总误差引起的权值修正,所以称为“反向传播”。BP神经网络是有教师指导训练方式的多层前馈网络,其基本思想是:从网络输入节点输入的样本信号向前传播,经隐含层节点和输出层节点处的非线性函数作用后,从输出节点获得输出。若在输出节点得不到样本的期望输出,则建立样本的网络输出与其期望输出的误差信号,并将此误差信号沿原连接路径逆向传播,去逐层修改网络的权值和节点处阈值,这种信号正向传播与误差信号逆向传播修改权值和阈值的过程反复进行,直训练样本集的网络输出误差满足一定精度要求为止。
以下是使用C/C++(大多数是C语言代码,只有数据读取部分是C++)完成的一个实际案例。
要求:
将Iris(鸢尾花)数据集分为训练集(Iris-train.txt)和测试集(Iris-test.txt),分别含75个样本,每个集合中每种花各有25个样本。为了方便训练,将3类花分别编号为1,2,3 。使用这些数据训练一个4输入(分别对应4个特征)、隐含层(10个神经元)、3输出(分别对应该样本属于某一品种的可能性大小)的神经网络(4*10*3)。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <fstream>
#include <iomanip> #define innode 4//输入层结点数
#define hidenode 10//隐层结点数
#define outnode 3//输出层结点数
#define trainsample 75//训练样本数
#define testsample 75//测试样本数 double trainData[trainsample][innode];//输入样本
double outData[trainsample][outnode];//输出样本 double testData[testsample][innode];//测试样本 double w[innode][hidenode];//输入层到隐层的权值
double w1[hidenode][outnode];//隐层到输出层的权值
double b1[hidenode];//隐层阈值
double b2[outnode];//输出层阈值 double e=0.0;//误差计算
double error=1.0;//允许的最大误差 double rate_w=0.9;//输入层到隐层的学习率
double rate_w1=0.9;//隐层到输出层的学习率
double rate_b1=0.9;//隐层阈值学习率
double rate_b2=0.9;//输出层阈值学习率 double result[outnode];//bp输出 //初始化函数
void init(double w[], int n);
//Bp训练函数
void train(double trainData[trainsample][innode], double label[trainsample][outnode]);
//Bp识别
double *recognize(double *p);
//从文件夹读取数据
void readData(std::string filename, double data[][innode], int x);
//数据归一化处理
void changeData(double data[][innode], int x); int main()
{
int i,j;
int trainNum=;//样本训练次数
double *r; //测试结果
int count=;//正确测试结果数
double maxRate = 1.0;//输出结果中的最大概率
//对权值和阈值进行初始化
init((double*)w, innode*hidenode);
init((double*)w1, hidenode*outnode);
init(b1, hidenode);
init(b2, outnode); //读取训练数据
readData("./Iris-train.txt", trainData, trainsample);
//对训练数据进行归一化处理
changeData(trainData, trainsample); /*for(i=0; i<trainsample; i++)
{
printf("%d: ",i+1);
for(j=0; j<innode; j++)
printf("%5.2lf",trainData[i][j]);
printf("\n");
}*/
//准备输出样本
for(i=; i<trainsample; i++)
{
if(i<)
{
outData[i][] = ;
outData[i][] = ;
outData[i][] = ;
}
else if(i<)
{
outData[i][] = ;
outData[i][] = ;
outData[i][] = ;
}
else
{
outData[i][] = ;
outData[i][] = ;
outData[i][] = ;
}
} printf("开始训练\n");
while(trainNum < )
{
e = 0.0;
trainNum++;
train(trainData, outData);
printf("训练第%d次, error=%8.4lf\n", trainNum, error);
}
printf("训练完成\n\n"); //读入测试数据
readData("./Iris-test.txt", testData, testsample);
//归一化测试数据
changeData(testData, testsample);
for(i=; i<testsample; i++)
{
r = recognize(testData[i]);
for(j=; j<outnode; j++)
printf("\t%7.4lf\t",r[j]);
printf("\n");
//判断检测结果是否正确
if(i< && r[]>r[] && r[]>r[])
count++;
if(i>= && i< && r[]>r[] && r[]>r[])
count++;
if(i>= && r[]>r[] && r[]>r[])
count++;
} printf("\n\n共有%d个检测样本, 正确检测出%d个, 准确率: %7.4lf\n\n",testsample, count, (double)count/testsample);
system("pause");
return ;
} //初始化函数(0到1之间的数)
void init(double w[], int n)
{
int i;
srand((unsigned int)time(NULL));
for(i=; i<n; i++)
{
w[i] = 2.0*((double)rand()/RAND_MAX)-;
}
} //BP训练函数
void train(double trainData[trainsample][innode], double label[trainsample][outnode])
{
double x[innode];//输入层的个输入值
double yd[outnode];//期望的输出值 double o1[hidenode];//隐层结点激活值
double o2[hidenode];//输出层结点激活值
double x1[hidenode];//隐层向输出层的输入
double x2[outnode];//输出结点的输出
/*********************************************************************
o1: 隐层各结点的激活值等于与该结点相连的各路径上权值与该路径上的输入相乘后全部相加
**********************************************************************
x1: 隐层结点的输出,计算出o1后才能计算x1,等于 1.0/(1.0 + exp-(激活值+该结点的阈值))
***********************************************************************
o2: 输出层结点的激活值等于与该结点相连的各路径上的权值与该路径的输入相乘后全部相加
***********************************************************************
x2: 输出层结点的输出,计算出o2后才能计算x2,等于 1.0/(1.0 + exp-(激活值+该结点的阈值))
***********************************************************************/ /*qq计算方式 (期望输出 - 实际输出)乘上 实际输出 乘上 (1-实际输出) */
double qq[outnode];//期望的输出与实际输出的偏差 double pp[hidenode];//隐含结点校正误差 int issamp;
int i,j,k;
for(issamp=; issamp<trainsample; issamp++)
{
for(i=; i<innode; i++)
x[i] = trainData[issamp][i]; for(i=; i<outnode; i++)
yd[i] = label[issamp][i]; //计算隐层各结点的激活值和隐层的输出值
for(i=; i<hidenode; i++)
{
o1[i] = 0.0;
for(j=; j<innode; j++)
o1[i] = o1[i]+w[j][i]*x[j];
x1[i] = 1.0/(1.0+exp(-o1[i]-b1[i]));
} //计算输出层各结点的激活值和输出值
for(i=; i<outnode; i++)
{
o2[i] = 0.0;
for(j=; j<hidenode; j++)
o2[i] = o2[i]+w1[j][i]*x1[j];
x2[i] = 1.0/(1.0+exp(-o2[i]-b2[i]));
} //得到了x2输出后接下来就要进行反向传播了 //计算实际输出与期望输出的偏差,反向调节隐层到输出层的路径上的权值
for(i=; i<outnode; i++)
{
qq[i] = (yd[i]-x2[i]) * x2[i] * (-x2[i]);
for(j=; j<hidenode; j++)
w1[j][i] = w1[j][i]+rate_w1*qq[i]*x1[j];
} //继续反向传播调整输出层到隐层的各路径上的权值
for(i=; i<hidenode; i++)
{
pp[i] = 0.0;
for(j=; j<outnode; j++)
pp[i] = pp[i]+qq[j]*w1[i][j];
pp[i] = pp[i]*x1[i]*(1.0-x1[i]); for(k=; k<innode; k++)
w[k][i] = w[k][i] + rate_w*pp[i]*x[k];
} //调整允许的最大误差
for(k=; k<outnode; k++)
{
e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]); //计算均方差
}
error=e/2.0; //调整输出层各结点的阈值
for(k=; k<outnode; k++)
b2[k]=b2[k]+rate_b2*qq[k]; //调整隐层各结点的阈值
for(j=; j<hidenode; j++)
b1[j]=b1[j]+rate_b1*pp[j];
}
} //Bp识别
double *recognize(double *p)
{
double x[innode];//输入层的个输入值
double o1[hidenode];//隐层结点激活值
double o2[hidenode];//输出层结点激活值
double x1[hidenode];//隐层向输出层的输入
double x2[outnode];//输出结点的输出 int i,j,k; for(i=;i<innode;i++)
x[i]=p[i]; for(j=;j<hidenode;j++)
{
o1[j]=0.0;
for(i=;i<innode;i++)
o1[j]=o1[j]+w[i][j]*x[i]; //隐含层各单元激活值
x1[j]=1.0/(1.0+exp(-o1[j]-b1[j])); //隐含层各单元输出
} for(k=;k<outnode;k++)
{
o2[k]=0.0;
for(j=;j<hidenode;j++)
o2[k]=o2[k]+w1[j][k]*x1[j];//输出层各单元激活值
x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
} for(k=;k<outnode;k++)
{
result[k]=x2[k];
}
return result;
} //从文件夹读取数据
void readData(std::string filename, double data[][innode], int x)
{
std::ifstream inData(filename, std::ios::in);
int i,j;
double dataLabel;
for(i=; i<x; i++)
{
for(j=; j<innode; j++)
{
inData >>data[i][j];
}
inData >>dataLabel;
}
inData.close();
} //数据归一化处理
void changeData(double data[][innode], int x)
{
//归一化公式:(x-min)/(max-min)
double minNum,maxNum;
int i,j;
minNum = data[][];
maxNum = data[][];
//找最大最小值
for(i=; i<x; i++)
{
for(j=; j<innode; j++)
{
if(minNum > data[i][j])
minNum = data[i][j];
if(maxNum < data[i][j])
maxNum = data[i][j];
}
}
//归一化
for(i=; i<x; i++)
{
for(j=; j<innode; j++)
data[i][j] = (data[i][j]-minNum)/(maxNum-minNum);
}
} 使用时把以下数据集复制粘贴到txt文件,分别命名为Iris-train.txt, Iris-test.txt
训练数据:
5.1 3.5 1.4 0.2 0
4.9 3.0 1.4 0.2 0
4.7 3.2 1.3 0.2 0
4.6 3.1 1.5 0.2 0
5.0 3.6 1.4 0.2 0
5.4 3.9 1.7 0.4 0
4.6 3.4 1.4 0.3 0
5.0 3.4 1.5 0.2 0
4.4 2.9 1.4 0.2 0
4.9 3.1 1.5 0.1 0
5.4 3.7 1.5 0.2 0
4.8 3.4 1.6 0.2 0
4.8 3.0 1.4 0.1 0
4.3 3.0 1.1 0.1 0
5.8 4.0 1.2 0.2 0
5.7 4.4 1.5 0.4 0
5.4 3.9 1.3 0.4 0
5.1 3.5 1.4 0.3 0
5.7 3.8 1.7 0.3 0
5.1 3.8 1.5 0.3 0
5.4 3.4 1.7 0.2 0
5.1 3.7 1.5 0.4 0
4.6 3.6 1.0 0.2 0
5.1 3.3 1.7 0.5 0
4.8 3.4 1.9 0.2 0
7.0 3.2 4.7 1.4 1
6.4 3.2 4.5 1.5 1
6.9 3.1 4.9 1.5 1
5.5 2.3 4.0 1.3 1
6.5 2.8 4.6 1.5 1
5.7 2.8 4.5 1.3 1
6.3 3.3 4.7 1.6 1
4.9 2.4 3.3 1.0 1
6.6 2.9 4.6 1.3 1
5.2 2.7 3.9 1.4 1
5.0 2.0 3.5 1.0 1
5.9 3.0 4.2 1.5 1
6.0 2.2 4.0 1.0 1
6.1 2.9 4.7 1.4 1
5.6 2.9 3.6 1.3 1
6.7 3.1 4.4 1.4 1
5.6 3.0 4.5 1.5 1
5.8 2.7 4.1 1.0 1
6.2 2.2 4.5 1.5 1
5.6 2.5 3.9 1.1 1
5.9 3.2 4.8 1.8 1
6.1 2.8 4.0 1.3 1
6.3 2.5 4.9 1.5 1
6.1 2.8 4.7 1.2 1
6.4 2.9 4.3 1.3 1
6.3 3.3 6.0 2.5 2
5.8 2.7 5.1 1.9 2
7.1 3.0 5.9 2.1 2
6.3 2.9 5.6 1.8 2
6.5 3.0 5.8 2.2 2
7.6 3.0 6.6 2.1 2
4.9 2.5 4.5 1.7 2
7.3 2.9 6.3 1.8 2
6.7 2.5 5.8 1.8 2
7.2 3.6 6.1 2.5 2
6.5 3.2 5.1 2.0 2
6.4 2.7 5.3 1.9 2
6.8 3.0 5.5 2.1 2
5.7 2.5 5.0 2.0 2
5.8 2.8 5.1 2.4 2
6.4 3.2 5.3 2.3 2
6.5 3.0 5.5 1.8 2
7.7 3.8 6.7 2.2 2
7.7 2.6 6.9 2.3 2
6.0 2.2 5.0 1.5 2
6.9 3.2 5.7 2.3 2
5.6 2.8 4.9 2.0 2
7.7 2.8 6.7 2.0 2
6.3 2.7 4.9 1.8 2
6.7 3.3 5.7 2.1 2
测试数据:
5.0 3.0 1.6 0.2 0
5.0 3.4 1.6 0.4 0
5.2 3.5 1.5 0.2 0
5.2 3.4 1.4 0.2 0
4.7 3.2 1.6 0.2 0
4.8 3.1 1.6 0.2 0
5.4 3.4 1.5 0.4 0
5.2 4.1 1.5 0.1 0
5.5 4.2 1.4 0.2 0
4.9 3.1 1.5 0.1 0
5.0 3.2 1.2 0.2 0
5.5 3.5 1.3 0.2 0
4.9 3.1 1.5 0.1 0
4.4 3.0 1.3 0.2 0
5.1 3.4 1.5 0.2 0
5.0 3.5 1.3 0.3 0
4.5 2.3 1.3 0.3 0
4.4 3.2 1.3 0.2 0
5.0 3.5 1.6 0.6 0
5.1 3.8 1.9 0.4 0
4.8 3.0 1.4 0.3 0
5.1 3.8 1.6 0.2 0
4.6 3.2 1.4 0.2 0
5.3 3.7 1.5 0.2 0
5.0 3.3 1.4 0.2 0
6.6 3.0 4.4 1.4 1
6.8 2.8 4.8 1.4 1
6.7 3.0 5.0 1.7 1
6.0 2.9 4.5 1.5 1
5.7 2.6 3.5 1.0 1
5.5 2.4 3.8 1.1 1
5.5 2.4 3.7 1.0 1
5.8 2.7 3.9 1.2 1
6.0 2.7 5.1 1.6 1
5.4 3.0 4.5 1.5 1
6.0 3.4 4.5 1.6 1
6.7 3.1 4.7 1.5 1
6.3 2.3 4.4 1.3 1
5.6 3.0 4.1 1.3 1
5.5 2.5 4.0 1.3 1
5.5 2.6 4.4 1.2 1
6.1 3.0 4.6 1.4 1
5.8 2.6 4.0 1.2 1
5.0 2.3 3.3 1.0 1
5.6 2.7 4.2 1.3 1
5.7 3.0 4.2 1.2 1
5.7 2.9 4.2 1.3 1
6.2 2.9 4.3 1.3 1
5.1 2.5 3.0 1.1 1
5.7 2.8 4.1 1.3 1
7.2 3.2 6.0 1.8 2
6.2 2.8 4.8 1.8 2
6.1 3.0 4.9 1.8 2
6.4 2.8 5.6 2.1 2
7.2 3.0 5.8 1.6 2
7.4 2.8 6.1 1.9 2
7.9 3.8 6.4 2.0 2
6.4 2.8 5.6 2.2 2
6.3 2.8 5.1 1.5 2
6.1 2.6 5.6 1.4 2
7.7 3.0 6.1 2.3 2
6.3 3.4 5.6 2.4 2
6.4 3.1 5.5 1.8 2
6.0 3.0 4.8 1.8 2
6.9 3.1 5.4 2.1 2
6.7 3.1 5.6 2.4 2
6.9 3.1 5.1 2.3 2
5.8 2.7 5.1 1.9 2
6.8 3.2 5.9 2.3 2
6.7 3.3 5.7 2.5 2
6.7 3.0 5.2 2.3 2
6.3 2.5 5.0 1.9 2
6.5 3.0 5.2 2.0 2
6.2 3.4 5.4 2.3 2
5.9 3.0 5.1 1.8 2
BP神经网络学习笔记_附源代码的更多相关文章
- jQuery源代码学习笔记_工具函数_noop/error/now/trim
jQuery源代码学习笔记_工具函数_noop/error/now/trim jquery提供了一系列的工具函数,用于支持其运行,今天主要分析noop/error/now/trim这4个函数: 1.n ...
- C++基础 学习笔记之一:源代码的格式化
C++基础 学习笔记之一:源代码的格式化 1. 源代码中的标记与空白 C++中的语句是以分号表示语句的结束.在C++中空格和回车以及制表符均为相同作用,即三者通常可以互相替代. 例如可以将一个简单的m ...
- tensorflow中使用mnist数据集训练全连接神经网络-学习笔记
tensorflow中使用mnist数据集训练全连接神经网络 ——学习曹健老师“人工智能实践:tensorflow笔记”的学习笔记, 感谢曹老师 前期准备:mnist数据集下载,并存入data目录: ...
- BP神经网络学习
人工神经元模型 S型函数(Sigmoid) 双极S型函数 神经网络可以分为哪些? 按照连接方式,可以分为:前向神经网络 vs. 反馈(递归)神经网络 按照学习方式,可以分为:有导师学习神经网络 ...
- 【cs231n】神经网络学习笔记3
+ mu) * v # 位置更新变了形式 对于NAG(Nesterov's Accelerated Momentum)的来源和数学公式推导,我们推荐以下的拓展阅读: Yoshua Bengio的Adv ...
- 【cs231n】神经网络学习笔记1
神经网络推荐博客: 深度学习概述 神经网络基础之逻辑回归 神经网络基础之Python与向量化 浅层神经网络 深层神经网络 前言 首先声明,以下内容绝大部分转自知乎智能单元,他们将官方学习笔记进行了很专 ...
- SSM框架学习笔记_第1章_SpringIOC概述
第1章 SpringIOC概述 Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架. 1.1 控制反转IOC IOC(inversion of controller)是一种概念 ...
- 雨痕 的《Python学习笔记》--附脑图(转)
原文:http://www.pythoner.com/148.html 近日,在某微博上看到有人推荐了 雨痕 的<Python学习笔记>,从github上下载下来看了下,确实很不错. 注意 ...
- Python学习笔记_我的参考网址
Python学习笔记, 下面记录网上搜到的可参考的网址: 一.关于Tkinter 1.Python3中tkinter模块使用方法详解 https://blog.csdn.net/Fighting_Bo ...
随机推荐
- C++的头文件和实现文件分别写什么
在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析.于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念. 对于以C起步,C#作为& ...
- 黄聪:wordpress如何获取当前页面的URL
一行代码搞定 <? echo home_url( add_query_arg( array() ) ); ?>
- 黄聪:wordpress后台导致fonts.googleapis.com、ajax.googleapis.com加载慢的解决方法
方法1.使用我做的插件.[googleapis-to-useso] 方法2.在functions.php文件里面添加下面的代码就行了. if(is_admin()) { function hcsem_ ...
- Java的安全性和可移植性
Java的这两个特性,关键在于Java编译器的输出并不是可执行的代码,而是字节码 bytecode. 字节码是一套设计用来在Java运行时系统下执行的高度优化的指令集,该Java运行 ...
- storm的数据源编程单元Spout学习整理
Spout呢,是Topology中数据流的源头,也是Storm针对数据源的编程单元.一般数据的来源,是通过外部数据源来读取数据项(Tuple),并读取的数据项传输至作业的其他组件.编程人员一般可通过O ...
- xhprof 安装使用
1.安装扩展 windows下把 xhprof.dll 放到extensions目录下 修改配置文件 [xhprof] extension=xhprof.so; ; directory used by ...
- JAVA 一个特殊的类 Object
一个特殊的类Object:它是java中所有对象的直接或间接父类,根父类(基类),它里面定义的功能是所有对象都应该具备的(所有的类,都是继承这个类的) 记住:当定义一个新类时,没有指明要继承某类,它默 ...
- css针对(各大浏览器、各版本)调兼容
ie6\ie7\firefox之下各自识别的CSS符号 #1 { color: #333; } /* firefox */ * html #1 { color: #666; } /* IE6 */ * ...
- sqlserver函数大全
一旦成功地从表中检索出数据,就需要进一步操纵这些数据,以获得有用或有意义的结果.这些要求包括:执行计算与数学运算.转换数据.解析数值.组合值和聚合一个范围内的值等. 下表给出了T-SQL函数的类别和描 ...
- javascript代码注意事项
1 代码行末要加分好.原因<<javascript高级程序设计第三版21页第三行>> 2 初始化变量应该加上默认值因为使用typeof时 未声明和声明为初始化的值都返回unde ...