BP理论部分参考:http://blog.csdn.net/itplus/article/details/11022243

参考http://www.cnblogs.com/ronny/p/ann_02.html#!comments,结合BP算法的理论部分,可以真正理解了ANN。

代码部分我加了部分注释

#include<vector>
using namespace std; //单个连接线
class NNconnection
{
public:
//两个索引,一个与该结点相连(前一层)的前一层结点的索引,
//一个对应的权值索引在整个单层网络中权值向量中的索引
unsigned weightIdx;
unsigned neuralIdx;
}; //单个神经元,包括一个输出和多个连接线
class NNneural
{
public:
double output;//输出
vector<NNconnection> m_connection;
}; //单层网络
class NNlayer
{
public:
NNlayer *preLayer;//该层网络的前一层
NNlayer(){ preLayer = NULL; }
vector<NNneural> m_neurals;//每层网络多个神经元
vector<double> m_weights;//权值向量
//加多少个神经元,及经前一层神经元的个数
void addNeurals(unsigned num, unsigned preNumNeurals);
//反向传播
void backPropagate(vector<double>& ,vector<double>&,double); }; class NeuralNetwork
{
private:
unsigned nLayer;//网络层数
vector<unsigned> nodes;//每层的结点数
vector<double> actualOutput;//每次迭代的输出结果
double etaLearningRate;//权值学习率
unsigned iterNum;//迭代次数
public:
vector<NNlayer*>m_layers;//由多个单层网络组成
//创建网络,第二个参数为[48,25,30],则表明该网络有三层,每层结点数分别为48,25,30
void create(unsigned num_layers, unsigned *ar_nodes);
void initializeNetwork();//初始化网络,包括权值设置等 void forwardCalculate(vector<double> &invect, vector<double> &outvect);//向前计算 void backPropagate(vector<double>& tVect, vector<double>& oVect);//反向传播 void train(vector<vector<double>>& inputVec, vector<vector<double>>& outputVec);//训练 void classifier(vector<vector<double>>& inputVec, vector<vector<double>>& outputVec);//分类 }; void NeuralNetwork::initializeNetwork()
{
//初始化网络,创建各层和各层结点,初始化权值
// i为何如此定义?
for (vector<NNlayer*>::size_type i = ; i != nLayer; i++)
{
NNlayer *ptrLayer = new NNlayer;
if (i == )
{
ptrLayer->addNeurals(nodes[i], );//第一层之前的结点数为0
}
else
{
ptrLayer->preLayer = m_layers[i - ];
//每个神经元的初值包括与前一层神经元的连接索引和该层权重索引
ptrLayer->addNeurals(nodes[i], nodes[i - ]);
//连结权重个数
unsigned num_weights = nodes[i] * (nodes[i - ] + );//+bias
//初始化权重
for (vector<NNlayer*>::size_type k = ; k != num_weights; k++)
{ ptrLayer->m_weights.push_back(0.05*rand() / RAND_MAX);//0~0.05
}
}
m_layers.push_back(ptrLayer);
}
} void NNlayer::addNeurals(unsigned num, unsigned preNumNeural)
{
for (vector<NNneural>::size_type i = ; i != num; i++)
{
NNneural sneural;
sneural.output = ;
for (vector<NNconnection>::size_type k = ; k != preNumNeural; k++)
{
NNconnection sconnection;
//给该神经元加上连接索引和权值索引
sconnection.weightIdx = i*(preNumNeural + ) + k;//加1给偏置留一个索引位置
sconnection.neuralIdx = k;
sneural.m_connection.push_back(sconnection);
}
m_neurals.push_back(sneural);
}
}
void NeuralNetwork::forwardCalculate(vector<double> &invect, vector<double> &outvect)
{
actualOutput.clear();
vector<NNlayer*>::iterator layerIt = m_layers.begin();
while (layerIt != m_layers.end())
{
if (layerIt == m_layers.begin())
{
for (vector<NNneural>::size_type k = ; k != (*layerIt)->m_neurals.size(); k++)
{
//对第一层的神经元来说,输出即为输入
(*layerIt)->m_neurals[k].output = invect[k];
}
}
else
{
vector<NNneural>::iterator neuralIt = (*layerIt)->m_neurals.begin();
int neuralIdx = ;
while (neuralIt != (*layerIt)->m_neurals.end())
{
//每个神经元的连接线数
vector<NNconnection>::size_type num_connection = (*neuralIt).m_connection.size();
//偏置
double dsum = (*layerIt)->m_weights[num_connection*(neuralIdx + ) - ];
for (vector<NNconnection>::size_type i = ; i != num_connection; i++)
{
//sum=sum+w*x;
unsigned wgtIdx = (*neuralIt).m_connection[i].weightIdx;
unsigned neuralIdx = (*neuralIt).m_connection[i].neuralIdx; dsum += (*layerIt)->preLayer->m_neurals[neuralIdx].output*
(*layerIt)->m_weights[wgtIdx];
}
neuralIt->output = SIGMOID(dsum); neuralIt++;//下一个神经元
neuralIdx++;//每个神经元的偏置不同
}
}
layerIt++;//下一层网络
}
//将最后一层的结果保存至输出
NNlayer * lastLayer = m_layers[m_layers.size() - ];
vector<NNneural>::iterator neuralIt = lastLayer->m_neurals.begin();
while (neuralIt != lastLayer->m_neurals.end())
{
outvect.push_back(neuralIt->output);
neuralIt++;
}
} void NeuralNetwork::backPropagate(vector<double>& tVect, vector<double>& oVect)
{
//首先取得最后一层迭代器
vector<NNlayer *>::iterator lit = m_layers.end() - ;
//用于保存最后一层所有结点误差
vector<double> dErrWrtDxLast((*lit)->m_neurals.size());
for (vector<NNneural>::size_type i = ; i != (*lit)->m_neurals.size(); i++)
{
dErrWrtDxLast[i]=oVect[i] - tVect[i];
}
//所有层的误差
vector<vector<double>> diffVect(nLayer);
diffVect[nLayer - ] = dErrWrtDxLast; //先将其他层误差设为0
for (unsigned int i = ; i < nLayer - ; i++)
{
//每层误差的个数要与神经元相等
diffVect[i].resize(m_layers[i]->m_neurals.size(), 0.0);
} vector<NNlayer>::size_type i = m_layers.size() - ;
//对每一层调用BP算法,第一个参数为第i层输出误差
//第二个参数可作为下次调用的返回值
for (lit; lit>m_layers.begin(); lit--)
{
(*lit)->backPropagate(diffVect[i], diffVect[i - ], etaLearningRate);
i--;
}
diffVect.clear();
} void NNlayer::backPropagate(vector<double>& dErrWrtDxn, vector<double>& dErrWrtDxnm, double eta)
{
//三个参数分别代表第i层的误差,第i-1层的误差,学习速率
//计算每个神经元的误差
double output;
vector<double> dErrWrtDyn(dErrWrtDxn.size());//每个神经元的残差
for (vector<NNneural>::size_type i = ; i != m_neurals.size(); i++)
{
output = m_neurals[i].output;
//计算第i层的残差,对于输出层,dErrWrtDxn表示误差,对于
//其他层,dErrWrtDxn表示w*(i+1层残差)
dErrWrtDyn[i] = DSIGMOD(output)*dErrWrtDxn[i];
}
//计算每个w的偏导数
unsigned ii();
vector<NNneural>::iterator nit = m_neurals.begin();
vector<double> dErrWrtDwn(m_weights.size(), ); while (nit != m_neurals.end())
{
//对于每个神经元
for (vector<NNconnection>::size_type k = ; k != (*nit).m_connection.size(); k++)
{
//对于每个权重连接
if (k == (*nit).m_connection.size() - )
output = ;//如果是偏置,则为1
else//与该权重相连的前一层神经元的输出
output = preLayer->m_neurals[(*nit).m_connection[k].neuralIdx].output;
//计算该权重的偏导数值(随着迭代的进行,偏导也是逐渐累加的)
dErrWrtDwn[((*nit).m_connection[k].weightIdx)] += output*dErrWrtDyn[ii];
}
nit++;
ii++;
} //dErrWrtDxnm作为下一层的dErrWrtDxn,用于计算残差
unsigned j();
nit = m_neurals.begin();
while (nit != m_neurals.end())
{
for (vector<NNconnection>::size_type k = ; k != (*nit).m_connection.size()-; k++)
{
dErrWrtDxnm[(*nit).m_connection[k].neuralIdx] += dErrWrtDyn[j] *
m_weights[(*nit).m_connection[k].weightIdx];
}
j++;
nit++;
} for (vector<double>::size_type i = ; i != m_weights.size(); i++)
{
m_weights[i] -= eta*dErrWrtDwn[i];
}
}

多层神经网络与C++实现的更多相关文章

  1. 多层神经网络BP算法 原理及推导

    首先什么是人工神经网络?简单来说就是将单个感知器作为一个神经网络节点,然后用此类节点组成一个层次网络结构,我们称此网络即为人工神经网络(本人自己的理解).当网络的层次大于等于3层(输入层+隐藏层(大于 ...

  2. TensorFlow 训练MNIST数据集(2)—— 多层神经网络

    在我的上一篇随笔中,采用了单层神经网络来对MNIST进行训练,在测试集中只有约90%的正确率.这次换一种神经网络(多层神经网络)来进行训练和测试. 1.获取MNIST数据 MNIST数据集只要一行代码 ...

  3. 用Tensorflow实现多层神经网络

    用Tensorflow实现多层神经网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 Tensorflow机器学习实战指南 源代码请点击下方链接欢迎加星 ReLU激活函数/L1范数 ...

  4. Spark2.0机器学习系列之7: MLPC(多层神经网络)

    Spark2.0 MLPC(多层神经网络分类器)算法概述 MultilayerPerceptronClassifier(MLPC)这是一个基于前馈神经网络的分类器,它是一种在输入层与输出层之间含有一层 ...

  5. ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程)

    ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程) ufldl出了新教程,感觉比之前的好,从基础讲起,系统清晰,又有编程实践. 在dee ...

  6. MXNET:多层神经网络

    多层感知机(multilayer perceptron,简称MLP)是最基础的深度学习模型. 多层感知机在单层神经网络的基础上引入了一到多个隐藏层(hidden layer).隐藏层位于输入层和输出层 ...

  7. MLP(多层神经网络)介绍

    写在前面的 接触神经网络(ANN)的时间很长了,以前也只是学了学原理,做过一个BPN的练习,没有系统的总结过,最近看Torch的源码,对MLP有了更多的了解,写写自己学到的东西吧,算是做了一次总结! ...

  8. 学习笔记TF011:多层神经网络

    线性回归.对数几率回归模型,本质上是单个神经元.计算输入特征加权和.偏置视为每个样本输入特征为1权重,计算特征线性组合.激活(传递)函数 计算输出.线性回归,恒等式(值不变).对数几率回归,sigmo ...

  9. 简单多层神经网络实现异或XOR

    最近在看<Neural Network Design_Hagan> 然后想自己实现一个XOR 的网络. 由于单层神经网络不能将异或的判定分为两类. 根据 a^b=(a&~b)|(~ ...

  10. ubuntu之路——day14 只用python的numpy在底层实现多层神经网络

    首先感谢这位博主整理的Andrew Ng的deeplearning.ai的相关作业:https://blog.csdn.net/u013733326/article/details/79827273 ...

随机推荐

  1. Jquery实现异步上传图片

    利用jQuery的ajax函数就可以实现异步上传图片了.一开始我是想在处理程序中,直接用context.Request.Files来获取页面中的input file,但是不知道为什么一次获取不了.网上 ...

  2. oracle-2-sql数据操作和查询

    主要内容: >oracle 数据类型 >sql建表和约束 >sql对数九的增删改 >sql查询 >oracle伪例 1.oracle的数据类型 oracle数据库的核心是 ...

  3. iOS开发中的错误整理,重写的构造函数中,没有通过self调用

  4. Svn-在eclipse中安装svn插件

    在eclipse中安装svn有两种方式 1:直接下载svn的插件包安装 使用的版本为1.8.x Links for 1.8.x Release: Eclipse update site URL: ht ...

  5. Day1 login

    使用流程: 1.程序启动后,显示欢迎信息,提示用户输入用户名: 2.判断用户是否存在,不存在则提示重新输入,或者关闭程序:客户存在则提示客户输入密码: 3.判断密码是否正确,如果不正确则提示用户重新输 ...

  6. JEECMS页面中常用标签

    (1)在段落前给每一行加序号 从0开始:${a_index}从1开始:${a_index+1} (2)标记说明 [文章导航]:[@cms.Position /] [文章标题]:${arti.title ...

  7. BZOJ3172 后缀数组

    题意:求出一篇文章中每个单词的出现次数 对样例的解释: 原文是这样的: a aa aaa 注意每个单词后都会换行 所以a出现次数为6,aa为3 (aa中一次,aaa中两次),aaa为1 标准解法好像是 ...

  8. POJ3264 Balanced Lineup

    Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 44720   Accepted: 20995 ...

  9. TYVJP1933 绿豆蛙的归宿

    背景 随着新版百度空间的上线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 描述 给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出发能够到达所有的点,所有的点也都能够到达 ...

  10. 无线安全: 通过伪AP进行DHCP+DNS劫持的钓鱼攻击

    有了之前学习802.11的数据帧格式.芯片硬件参数学习的基础后,我们接下来继续学习无线安全中黑客是怎样进行流量劫持攻击的 相关学习资料 http://www.freebuf.com/articles/ ...