之前在简书的文章,搬迁过来 ^-^
本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处。

#Caffe FeatureMap数据流的建立 ##用语解释

  • FeatureMap: 输入的图片信息或者经过多层处理后的图片信息。
  • weights: 只针对卷积层存在的权重系数。
  • caffe :文中提到的caffe均指caffed1.0,如果使用caffe2.0会特别指出。

在讲解FeatureMap的数据流之前,首先需要明确一下caffe的大体结构,caffe的整体逻辑结构分为3层,分别是Net,Layer和Blob,分别的作用如下:

  • Net: 该层处于CAFFE的最顶层,主要负责对模型文件的读写,根据模型文件的内容建立相应的Layer,填充对应层的数据并进行相关的调用。
  • Layer: 该层是实际的执行单元,常见的如卷积层,Pooling层都是处于这一逻辑层。
  • Blob:该层是一个内存管理的模块,为Layer和Net提供相应的存储空间,屏蔽上层对于内存分配,CPU,GPU切换的感知。

由上面的讲解分层关系不难看出,FeatureMap在整个Caffe框架中,不属于任何一个Layer,所以它被最顶层的Net层所持有。Net层就需要能够通过caffe的模型文件推倒出每一层所依赖的输入,这样才能构建出一个完整的数据链。在这种需求下Caffe引入了两个定义:

  • bottom: Layer的输入数据。
  • top: Layer的输出数据。 具体的形式如下图(单输入和多输入的情形):

所以Net在调用Layer之前就一定知道了Layer的所需要的输入数据,也就是需要Net层所持有的Blob变量需要被那些层所引用。这些在模型文件中也有直观的反应(为了方便截图,删除了下图proto中关于Convlution的参数配置):

上述的工作都在Net的Init(void Net::Init(const NetParameter& in_param))函数里面进行了处理,主要实现的就是根据上图左侧的模型文件得到需要建立的Layer的类型,并将各个Layer间的数据链接起来。函数中的关键参数如下:

名称 功能
in_param 存放由protobuf转换出的模型文件
bottom_vecs_ 存放每一层中的输入数据类型为:vector<vector<Blob*> >
top_vecs_ 存放每一层中的输出数据类型为:vector<vector<Blob*> >
available_blobs 存放每一层中的输出数据类型为:vector<vector<Blob*> >

##常规的数据链建立流程是(单输入单输出的场景):

  1. 链接本层的bottom数据( int Net::AppendBottom(const NetParameter& param, const int layer_id, const int bottom_id, set<string>* available_blobs, map<string, int>* blob_name_to_idx) ),该函数会使用从当前layer持有的bottom信息中得到对应bottom的层名,然后利用该名称找到对应的blob,并加入到bottom_vecs_。

  2. 链接本层的top数据(void Net::AppendTop(const NetParameter& param, const int layer_id,const int top_id, set<string>* available_blobs, map<string, int>* blob_name_to_idx)),该操作就是将本层的输出数据加入到top_vecs_中,并与 layer_id相关联,这里同时负责Blob对象的申请。 需要指出的是,新的Blob对象是在top中进行创建的,在Bottom中只是将上一层top的指针添加进来,同时在这个过程中CAFFE还利用available_blobs进行了异常校验,在每次新加入top的时候记录对应的Blob名称,在bottom中链接上一层top之后,在available_blobs中将对应的Blob名称剔除。相关伪代码如下:

     for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {AppendBottom();AppendTop();}
    复制代码

##多输入的数据链的建立: 细心的同学应该已经发现,当数据为多bottom输入的时候,因为available_blobs的数据被上一次的链接过程删掉,则再次链接相同bottom的时候,会出先异常告警,在这种情况下我们就要引入CAFFE的另外一处理函数 void InsertSplits(const NetParameter& param, NetParameter* param_split),该函数的主要功能就是对 top输出到多个 Layer的情况进行分割。 整个函数分为两个部分:

  1. 遍历整个网络,记录每一个Layer的top的使用情况,记录结构放在 top_idx_to_bottom_count中。

  2. 遍历整个网络,对 top_idx_to_bottom_count > 1 的情况进行处理: a. 首先是对top被多个层使用的Layer进行分割,主要的做法是在该层的后面新建一个Layer ,这个新的Layer的会按照 top_idx_to_bottom_count 的个数和约定的分割名称(SplitBlobName)去新建top,添加层的代码如下(此处只展示核心的创建过程,具体调用流程请自行跟踪):

     //该函数执行新层的添加void ConfigureSplitLayer(const string& layer_name, const string& blob_name,const int blob_idx, const int split_count, const float loss_weight,LayerParameter* split_layer_param) {split_layer_param->Clear();split_layer_param->add_bottom(blob_name);split_layer_param->set_name(SplitLayerName(layer_name, blob_name, blob_idx));split_layer_param->set_type("Split");for (int k = 0; k < split_count; ++k) {//split_count就是该top被引用的个数//添加了分割后的top//命名由SplitBlobName生成            split_layer_param->add_top(SplitBlobName(layer_name, blob_name, blob_idx, k));if (loss_weight) {if (k == 0) {split_layer_param->add_loss_weight(loss_weight);} else {split_layer_param->add_loss_weight(0);}}}}
    复制代码

    b. 之后,是对使用同一个top的后续层的bottom的blob进行改名,使用与上一步相同的命名规则进行改名。

下面以SqueezeNet1.1为例,展示了添加新的分割层的实例:

![Upload new_split_layer.jpg failed. Please try again.]

通过这样一个分割的转化,达到了对多输入数据流的建立。

##遗留问题 上面讲的是在初始化阶段对FeatureMap数据的链接关系的建立,但是对于weights的填充和初始图片的输入并没有进行分析。

深度学习 Caffe 初始化流程理解(数据流建立)相关推荐

  1. caffe模型文件解析_深度学习 Caffe 初始化流程理解(数据流建立)

    深度学习 Caffe 初始化流程理解(数据流建立) 之前在简书的文章,搬迁过来 ^-^ 本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处. #Caffe FeatureMap数据流的建 ...

  2. 什么是深度学习?45分钟理解深度神经网络和深度学习 刘利刚教授

    什么是深度学习? - 45分钟理解深度神经网络和深度学习 刘利刚 中国科学技术大学图形与几何计算实验室 http://staff.ustc.edu.cn/~lgliu [绪言] 近年来,人工智能(Ar ...

  3. 基于深度学习的三维语义理解(分割)综述列表

    基于深度学习的三维语义理解(分割)综述列表 文章目录 基于深度学习的三维语义理解(分割)综述列表 前言 基于深度学习的三维语义理解(分割)综述列表 一. 从单一三维模型中进行深度学习 1.1基于点云的 ...

  4. 方法 | 机器学习(深度学习)通用工作流程

    机器学习(深度学习)通用工作流程 Deep Learning with Python 4.5节 1. 定义问题并装载数据集(Defining the problem and assembling a ...

  5. 机器学习(深度学习)通用工作流程

    机器学习(深度学习)通用工作流程 翻译 Deep Learning with Python 4.5节 1. 定义问题并装载数据集(Defining the problem and assembling ...

  6. 【HSI】高光谱的数据集分类深度学习实战及代码理解

    [HSI]高光谱的数据集分类深度学习实战及代码理解 文章目录 [HSI]高光谱的数据集分类深度学习实战及代码理解 一.配置文件编写 二.高光谱图像的处理 2.1图像数据变换 2.2 数据整合 2.3 ...

  7. 深度学习解决机器阅读理解任务的研究进展

    /*版权声明:可以任意转载,转载时请标明文章原始出处和作者信息.*/ author: 张俊林 关于阅读理解,相信大家都不陌生,我们接受的传统语文教育中阅读理解是非常常规的考试内容,一般形式就是给你一篇 ...

  8. 深度学习——MSRA初始化

    转载自:MSRA初始化 本次简单介绍一下MSRA初始化方法,方法同样来自于何凯明paper <Delving Deep into Rectifiers:Surpassing Human-Leve ...

  9. 深度学习时代的视频理解综述

    深度学习时代的视频理解综述 本文为b站@bryanyzhu老师四期视频理解相关论文解读的汇总图文笔记. 我们先精读深度学习时代视频理解领域最为重要的两篇论文:双流网络和 I3D.它们分别是领域内两大类 ...

最新文章

  1. HDU-3177 Crixalis's Equipment 贪心
  2. Windows Service:用C#创建Windows Service
  3. linux命令学习之:ifconfig
  4. html输入密码自动隐藏,原生js实现密码输入框值的显示隐藏
  5. UML类图的6大关系
  6. python手机端秒杀_python实现淘宝秒杀脚本
  7. RIP RETE时间获得PHREAKY
  8. 【OpenCV 例程200篇】48. 图像增强—彩色直方图匹配
  9. 线性表、顺序表和链表,你还分不清?
  10. MySQL server has gone away报错原因分析
  11. 基于Kubernetes集群部署skyDNS服务
  12. struts 框架介绍 原理透析 struts概念说明
  13. flash mx拖拽实例_Flash MX 2004的ScatterBug命令面板
  14. java一个中文的验证码程序,Java中文验证码
  15. ASP.NET删除服务器端文件,asp.net删除服务器上的文件
  16. 【ROS入门21讲】Client客户端的编程实现
  17. python计算机视觉-图像处理基础章节第三章之根据仿射或单应性变换实现图像的扭曲,映射,融合
  18. pfSense安装和配置pfBlockerNg
  19. 亲爱的我把孩子放大了文案解说
  20. iOS 12 - iOS 15,如何在iPhone上设置“早上好”功能

热门文章

  1. C++和Rust_后端程序员一定要看的语言大比拼:Java vs. Go vs. Rust
  2. 在统计学中参数的含义是指_期刊论文中科研统计学缺陷分析及解决路径
  3. python自带的shell、其性能优于ipython吗_Python自带的shell,其性能优于IPython
  4. JAVA格式化当前日期或者取年月日
  5. 使用python的openpyxl模块操作excel
  6. Ajax同步和异步的区别?
  7. 用ASP.NET Core MVC 和 EF Core 构建Web应用 (一)
  8. 主流浏览器Cssjs hack写法
  9. 【转】VS2013中如何解决error C4996: 'fopen'问题
  10. 被LTRIM(RTRIM())害死了,差点