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类的源码就先介绍到这里,还有一些补丁式的小函数,也就一两行代码,功能明确,实现简单,这里就不再赘述了,还有三个月就研三了,要好好想想工作的事了,嘿嘿。

时间: 2024-08-01 02:16:49

C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析的相关文章

DeepLearning tutorial(4)CNN卷积神经网络原理简介+代码详解

DeepLearning tutorial(4)CNN卷积神经网络原理简介+代码详解 @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43225445 本文介绍多层感知机算法,特别是详细解读其代码实现,基于python theano,代码来自:Convolutional Neural Networks (LeNet).经详细注释的代码和原始代码:放在我的github地址上,可下载. 一.CNN卷积神经网络原理

Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/IVN4EuFlmKk/优酷:http://v.youku.com/v_show/id_

tiny_cnn代码详解(3)——层间继承关系

在上一篇博文中我们顺利将tiny_cnn的程序调试通过,在这篇博文中我们尝试从整体角度给出对tiny_cnn这个深度学习框架的解读,重点论述一下其各个层直接类封装的继承关系. 一.卷积神经网络快速入门 tiny_cnn作为卷积神经网络的一种实现形式,在探讨其框架结构之前,首先需要简要介绍一些卷积神经网络相关的知识.首先,给出经典卷积神经网络的网络结构: 这个是经典的LeNet-5的网络结构图,五层网络.最早用于支票上的手写数字识别,也是最早的商业化的深度学习模型.从上图中可以看出,卷积神经网络主

C++卷积神经网络实例:tiny_cnn代码详解(7)——fully_connected_layer层结构类分析

之前的博文中已经将卷积层.下采样层进行了分析,在这篇博文中我们对最后一个顶层层结构fully_connected_layer类(全连接层)进行分析: 一.卷积神经网路中的全连接层 在卷积神经网络中全连接层位于网络模型的最后部分,负责对网络最终输出的特征进行分类预测,得出分类结果: LeNet-5模型中的全连接层分为全连接和高斯连接,该层的最终输出结果即为预测标签,例如这里我们需要对MNIST数据库中的数据进行分类预测,其中的数据一共有10类(数字0~9),因此全全连接层的最终输出就是一个10维的

C++卷积神经网络实例:tiny_cnn代码详解(12)——从CNN中看多态性

最近由于在准备论文的相关事宜,导致博客的更新速度有点缓慢,望大家见谅.不过该更新还是要更新的,所以今天我就挤出一点时间来更新一篇.由于之前的博文已经将tiny_cnn中相关的网络层结构介绍的差不多,接下来的博文中着重介绍卷积神经网络的训练流程和测试流程,重点就是前向传播算法和反向传播算法.不过我在研究CNN前向传播算法的流程时,发现作者在前向传播算法的调用过程中,很好的体现了C++的多态性特点,考虑到多态性是各个招聘单位面试时饱受青睐的一道考题,于是决定单独拿出一篇博文来从tiny_cnn的角度

C++卷积神经网络实例:tiny_cnn代码详解(9)——partial_connected_layer层结构类分析(下)

在上一篇博文中我们着重分析了partial_connected_layer类的成员变量的结构,在这篇博文中我们将继续对partial_connected_layer类中的其他成员函数做一下简要介绍. 一.构造函数 由于partial_connected_layer类是继承自基类layer,因此在构造函数中同样分为两部分,即调用基类构造函数以及初始化自身成员变量: partial_connected_layer(layer_size_t in_dim, layer_size_t out_dim,

深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)[转]

上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根节点下面,可配置properties.typeAliases.plugins.objectFactory.objectWrapperFactory.settings.environments.databaseIdProvider.typeHandlers.mappers这些节点.那么本次,就会先介绍prope

详解稳定h5房卡版牛牛源码平台教程

如何搭建一个网站,我估计很多程序员都有这个冲动想去搭建一个属于自己的网络小天地,但是苦于不知道从何下手,或者因为不知道水有多深,而望而却步,其实搭建网站没有你想的那么复杂,且听我细细分解, 一共就五步:h5房卡版牛牛源码 Q 2171793408 1.注册域名 2.购买空间 3.代码部署 4.提交备案 5.域名解析 下面我就以构建 窝窝头源码论坛 的收藏夹http://wowotouba.com/h5这个网站的为例来讲一下搭建过程 服务器选用阿里云,为什么选择阿里云,主要是他最近比较火,也比较成

Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析之Scala学习笔记-51

package com.leegh.implicits /** * @author Guohui Li */ object Implicit_Conversions_with_Implicit_Parameters { def main(args: Array[String]): Unit = { def bigger[T](a: T, b: T)(implicit ordered: T => Ordered[T]) = if (ordered(a) > b) a else b println