C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析
Posted 山在岭就在
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析相关的知识,希望对你有一定的参考价值。
在这篇博文中我们对tiny_cnn卷积神经网络模型中的最后一个网络结构方面的类——layers做简要分析。
首先,layers通俗的讲可以被称为是层结构的vector,即层结构容器。由于卷积神经网络是一个多层的网络模型,因此有必要将网络中各个层进行统一管理,这便引出了本篇博文中所要介绍的layers类。layers类是一个vector类型的变量,其中压入的元素就是网络中的各个层模型,这里给出一个简单的结构图,一目了然:
从上图中可以清晰的看到layers的vector结构,说白了就是一个层结构类的容器,彼此之间通过prev_(指向后一层)和next_(指向前一层)两个指针相联系。接下来开始着重分析layers的内部代码结构。首先给出layers的结构示意图:
同样我们按照成员变量、成员函数的思路对这个类的结构和代码进行解读。
一、成员变量
layers有两个成员变量,一个是vector容器变量,用来保存各个压栈的层结构类;一个是input_layer类型变量,用来保存网络模型中输入层的结构信息:
这个有两个问题需要强调:
(1)容器元素的类型。从上图中可以看出,layers_容器中的基本元素类型是layer_base*类型,原因很明确,layer_base是卷积层、下采样层、全连接层等层结构的公共基类,声明成指针形式是为了方便使用前向指针和反向指针进行连接。
(2)输入层的独特性。这里之所以将输入层单独拿出来作为一个成员变量,主要是考虑到在任何卷积神经网络的网络模型(无论是单层模型还是多层模型)中,输入层都是必不可少的,并且都处于网络模型的最前端。对于这个存在性和位置都已经确定的层成员,这里选择将其放在layers中进行默认添加构造,使得用户在指定层结构模型时无需再一成不变的添加输入层。
二、构造函数
layers类内提供了两种功能的构造函数:
第一个构造函数用于构造单层网络模型,即只有一个输入层(first_是一个input_layer类型变量);第二个构造函数用于按照指定的层类型来构造多层网络模型,构造函数的实现机制主要通过add()和construct()两个函数,有关这两个函数的具体功能稍后介绍。
三、模型构造方法
layers在对网络模型执行构造的过程中,主要依赖于add()和construct()这两个构造方法,这里稍作分析。
3.1 add()函数
顾名思义,add()函数的作用是将指定的层类型类添加到当前的layers结构体中,类似于vector中的压栈操作(实际上也确实借用了push_back):
add()函数在执行过程中主要分为两大部分,即建立连接关系和层结构压栈。首先需要调用connect()函数来建立待加入层(new_tail)与已有模型之间的关系。connect()函数是定义在基类layer_base中的成员函数,目的就是建立网络模型中前后两层之间的指针联系:
在connect函数中,首先针对前后层之间的连接关系进行判断,在连接匹配的情况下,通过“next_ = tail”语句将当前层的下一层指定为tail(新加入的层),再通过“tail->prev_ = this”将新加入的层的前一层指定为当前层。从这种意义上将,connect()的构造方式与指针队列的构造方式很像。
继续分析add()函数。在通过connect函数建立新加入层与已有模型的最后一层之间的指针联系之后,直接调用push_back将待加入的层结构类压栈即可,完成新层的构造和存储。
3.2 construct()函数
construct()函数旨在完成多层模型的构造,包括建立连接和压栈等等,其基本的工作原理就是循环调用add()函数:
这里同样可以分为两个过程。首先,向layers容器中加入输入层first_,因为对于所有的模型,输入层都是必不可少的,因此与其让用户在每次构建模型时都先在第一个位置写上Input_layer,还不如将这一步放到构造函数内部来自动执行。接下来就循环调用add()函数,将需要添加的层逐个的建连接、压栈、建连接、压栈。
四、权重操作
由于layers属于对层结构类的再封装,因此需要提供与各个网络层共有功能相对应的接口,比如说权重操作。这里的权重操作主要包括权重的初始化、重置以及权重更新等操作。这些操作函数一般都是只提供一个接口,具体实现过程中主要还是调用各个类内部的对应的功能函数,比如说权重的初始化和重置:
再比如说权重的更新update:
五、属性返回
由于layers是用户所能接触到的最上层的层结构封装,因此其有必要提供一些属性返回的接口函数,供用户查看网络层的输出以及权重核的具体情况等等,当然这里的接口函数同样作为一个桥梁式的存在,一方面连接用户,一方面调用各个元素类的对应功能函数。除此之外还需要添加一些与整体层结构相关的属性返回函数,来告诉用户这个保存着layer_base的vector实际上有多少层,第一层是什么,最后一层是什么,怎么访问到指定层。
首先是如何访问第一层和最后一层,这里提供了两个函数head()和tail(),具体实现机制很简单,相信大家一看就懂:
至于如何访问指定层,tiny_cnn提供两个手段,一是定义at函数,并通过dynamic_cast进行类型转换:
另一种手段是重载“[]”运算发,类数组形式访问
以上两种访问方式都是通过索引(index)来完成,比较方便。
OK,有关层结构容器layers类的源码就先介绍到这里,还有一些补丁式的小函数,也就一两行代码,功能明确,实现简单,这里就不再赘述了,还有三个月就研三了,要好好想想工作的事了,嘿嘿。
以上是关于C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析的主要内容,如果未能解决你的问题,请参考以下文章
C++卷积神经网络实例:tiny_cnn代码详解(12)——从CNN中看多态性
C++卷积神经网络实例:tiny_cnn代码详解——fully_connected_layer层结构类分析
C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析
C++卷积神经网络实例:tiny_cnn代码详解(12)——从CNN中看多态性