[CLPR]卷积神经网络的C++实现
文章翻译自: http://www.codeproject.com/Articles/16650/Neural-Network-for-Recognition-of-Handwritten-Digi
如何在C++中实现一个神经网络类? 主要有四个不同的类需要我们来考虑:
- 层 - layers
- 层中的神经元 - neurons
- 神经元之间的连接 - connections
- 连接的权值 - weights
这四类都在下面的代码中体现, 集中应用于第五个类 - 神经网络(neural network)上. 它就像一个容器, 用于和外部交流的接口. 下面的代码大量使用了STL的vector.
// simplified view: some members have been omitted, // and some signatures have been altered // helpful typedef‘s typedef std::vector< NNLayer* > VectorLayers; typedef std::vector< NNWeight* > VectorWeights; typedef std::vector< NNNeuron* > VectorNeurons; typedef std::vector< NNConnection > VectorConnections; // Neural Network class class NeuralNetwork { public: NeuralNetwork(); virtual ~NeuralNetwork(); void Calculate( double* inputVector, UINT iCount, double* outputVector = NULL, UINT oCount = 0 ); void Backpropagate( double *actualOutput, double *desiredOutput, UINT count ); VectorLayers m_Layers; }; // Layer class class NNLayer { public: NNLayer( LPCTSTR str, NNLayer* pPrev = NULL ); virtual ~NNLayer(); void Calculate(); void Backpropagate( std::vector< double >& dErr_wrt_dXn /* in */, std::vector< double >& dErr_wrt_dXnm1 /* out */, double etaLearningRate ); NNLayer* m_pPrevLayer; VectorNeurons m_Neurons; VectorWeights m_Weights; }; // Neuron class class NNNeuron { public: NNNeuron( LPCTSTR str ); virtual ~NNNeuron(); void AddConnection( UINT iNeuron, UINT iWeight ); void AddConnection( NNConnection const & conn ); double output; VectorConnections m_Connections; }; // Connection class class NNConnection { public: NNConnection(UINT neuron = ULONG_MAX, UINT weight = ULONG_MAX); virtual ~NNConnection(); UINT NeuronIndex; UINT WeightIndex; }; // Weight class class NNWeight { public: NNWeight( LPCTSTR str, double val = 0.0 ); virtual ~NNWeight(); double value; };
类NeuralNetwork存储的是一个指针数组, 这些指针指向NN中的每一层, 即NNLayer. 没有专门的函数来增加层, 只需要使用std::vector::push_back()即可. NeuralNetwork类提供了两个基本的接口, 一个用来得到输出(Calculate), 一个用来训练(Backpropagete).
每一个NNLayer都保存一个指向前一层的指针, 使用这个指针可以获取上一层的输出作为输入. 另外它还保存了一个指针向量, 每个指针指向本层的神经元, 即NNNeuron, 当然, 还有连接的权值NNWeight. 和NeuralNetwork相似, 神经元和权值的增加都是通过std::vector::push_back()方法来执行的. NNLayer层还包含了函数Calculate()来计算神经元的输出, 以及Backpropagate()来训练它们. 实际上, NeuralNetwork类只是简单地调用每层的这些函数来实现上小节所说的2个同名方法.
每个NNNeuron保存了一个连接数组, 使用这个数组可以使得神经元能够获取输入. 使用NNNeuron::AddConnection()来增加一个Connection, 输入神经元的标号和权值的标号, 从而建立一个NNConnection对象, 并将它push_back()到神经元保存的连接数组中. 每个神经元同样保存着它自己的输出值(double). NNConnection和NNWeight类分别存储了一些信息.
你可能疑惑, 为何权值和连接要分开定义? 根据上述的原理, 每个连接都有一个权值, 为何不直接将它们放在一个类里?
原因是: 权值经常被连接共享.
实际上, 在卷积神经网络中就是共享连接的权值的. 所以, 举例来说, 就算一层可能有几百个神经元, 权值却可能只有几十个. 通过分离这两个概念, 这种共享可以很轻易地实现.
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。