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

本文主要是介绍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类的源码就先介绍到这里,还有一些补丁式的小函数,也就一两行代码,功能明确,实现简单,这里就不再赘述了。这个系列的博文截止到现在已经将所有与网络层相关的类都介绍完毕,在接下来的博文中将重点根据训练算法和测试算法来对程序进行解读。由于程序在前向/反向传播函数中大量用到了TBB编程相关的知识,我决定专门拿出一段时间来研究一下TBB的相关知识和基本用法,再加上这段时间需要忙论文的事,这个系列的博文可能要暂时停更一周左右的时间,望大家见谅。

 


如果觉得这篇文章对您有所启发,欢迎关注我的公众号,我会尽可能积极和大家交流,谢谢。


这篇关于C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115505

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1