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. 微信小程序开发常见问题分析

    距离微信小程序内测版发布已经有十几天的时间了,网上对微信小程序的讨论也异常火爆,从发布到现在微信小程序一直占领着各种技术论坛的头条,当然各种平台也对微信小程序有新闻报道,毕竟腾讯在国内影响力还是很大的 ...

  2. c# 关于浅拷贝和深拷贝

    class Program { static void Main(string[] args) { //浅拷贝 Person p1 = new Person(); p1.Name = "张三 ...

  3. WPF中资源引用方式汇总

    在WPF应用程序开发中,总是难以记住各种访问资源的方法,遂逐一记下. 先从资源是否编译到程序集分类 一.程序集资源 资源在编译的时候嵌入到程序集中.WPF中的XAML会被编译为BAML,图片等其他资源 ...

  4. 【Moqui业务逻辑翻译系列】Sales Representative Seeks Prospects and Opportunities 销售代表寻找期望合作对象和机会

    h1. Sales Representative Seeks Prospects and Opportunities 销售代表寻找期望合作对象和合作机会 h4. Ideas to incorporat ...

  5. 微信支付PHP SDK —— 公众号支付代码详解

    在微信支付 开发者文档页面 下载最新的 php SDK http://mch.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1 这里假设你已经申请完微 ...

  6. ovs-agent流程

    1. 代码流程分析 neutron/plugins/openvswitch/agent/ovs_neutron_agent.py:main() plugin = OVSNeutronAgent(**a ...

  7. Html-Css-div标签嵌套浮动div标签时无法撑开外部div的解决

    当DIV1里面嵌套有一个DIV2,当DIV2设置了浮动,那么DIV1是无法被撑开的 当DIV1里面嵌套有一个DIV2,当DIV2设置了浮动,那么DIV1是无法被撑开的,也就是说DIV2在这里相当于浮在 ...

  8. Java编程思想学习(六) 多态

    1.Java语言的三大特性:继承.封装和多态. 继承:复用类的一种方法,可以简省很多代码: 封装:通过合并特征和行为来创建新的数据类型.[这种“数据类型”跟Java本身提供的8大“基本数据类型”的地位 ...

  9. 8.Android之日期DatePicker和时间TimeTicker控件学习

    手机设置时间日期很普遍,今天就梳理下. 首先在拖入一个按钮 ,日期和时间控件到工程里,如图: 代码如下: <?xml version="1.0" encoding=" ...

  10. Linux/Unix System Level Attack、Privilege Escalation(undone)

    目录 . How To Start A System Level Attack . Remote Access Attack . Local Access Attack . After Get Roo ...