Net的网络层的构建(源码分析)

简介: 概述网络层的构建是在Net::Init()函数中完成的,构建的流程图如下所示: 从图中可以看出网络层的构建分为三个主要部分:解析网络文件、开始建立网络层、网络层需要参与计算的位置。解析网络文件该部分主要有两个函数FilterNet()、InsertSplits()。

概述

网络层的构建是在Net<Dtype>::Init()函数中完成的,构建的流程图如下所示:

 

从图中可以看出网络层的构建分为三个主要部分:解析网络文件、开始建立网络层、网络层需要参与计算的位置。

解析网络文件

该部分主要有两个函数FilterNet()InsertSplits() 

1 void Net<Dtype>::Init(const NetParameter& in_param) {
2   CHECK(Caffe::root_solver() || root_net_)
3       << "root_net_ needs to be set for all non-root solvers";
4   // Set phase from the state.
5   phase_ = in_param.state().phase();
6   // Filter layers based on their include/exclude rules and
7   // the current NetState.
8   NetParameter filtered_param;
9   FilterNet(in_param, &filtered_param);

 FilterNet()的作用是模型参数文件(*.prototxt)中的不符合规则的层去掉。例如:在caffeexamples/mnist中的lenet网络中,如果只是用于网络的前向,则需要将包含train的数据层去掉。 

1 /*
2     *调用InsertSplits()函数,对于底层的一个输出blob对应多个上层的情况,
3     *则要在加入分裂层,形成新的网络。
4     *函数从filtered_param读入新网络到param
5     **/
6   InsertSplits(filtered_param, &param);

 InsertSplits()函数的作用是对于底层的一个输出blob对应多个上层的情况,则要在加入分裂层,形成新的网络。这么做的主要原因是多个层反传给该blob的梯度需要累加例如:LeNet网络中的数据层的top label blob对应两个输入层,分别是accuracy层和loss层,那么需要在数据层在插入一层。如下图:

 

建立网络层

 该部分重要的函数有CreateLayer()AppendBottom()AppendTop()SetUp() 

 1   ...............
 2   //(很大的一个for循环)对每一层处理
 3   for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {//开始遍历所有层
 4       ............
 5     // Setup layer.
 6     //param.layers(i)返回的是关于第当前层的参数:
 7     const LayerParameter& layer_param = param.layer(layer_id);
 8     if (share_from_root) {
 9       ............
10     } else {
11     /*
12      *把当前层的参数转换为shared_ptr<Layer<Dtype>>,
13       *创建一个具体的层,并压入到layers_中
14     */
15       layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));
16     }

 对于CreateLayer()函数,把解析的当前层调用CreatorRegistry类进行注册,从而获取到当前层。然后会调用AppendBottom()AppendTop()函数具体创建层结构。 

1 //下面开始产生当前层:分别处理bottom的blob和top的blob两个步骤
2     for (int bottom_id = 0; bottom_id < layer_param.bottom_size(); ++bottom_id) {
3       const int blob_id = AppendBottom(param, layer_id, bottom_id,
4 &available_blobs, &blob_name_to_idx);
5       need_backward |= blob_need_backward_[blob_id];
6     }

对于AppendBottom()函数,其作用是为该层创建bottom blob,由于网络是堆叠而成,即:当前层的输出 bottom是前一层的输出top blob,因此此函数并没没有真正的创建blob,只是在将前一层的指针压入到了bottom_vecs_中。

1 int num_top = layer_param.top_size();
2     for (int top_id = 0; top_id < num_top; ++top_id) {
3       AppendTop(param, layer_id, top_id, &available_blobs, &blob_name_to_idx);
4       ...............
5     }

 对于AppendBottom()函数,其作用是为该层创建top blob,该函数真正的new的一个blob的对象。并将top blob 的指针压入到top_vecs_中。经过这两个函数网络层创建出该层所有的输入、输出blob,接下来就是调用SetUp()函数,正式建立层结构,并为blob分配内存空间。

 1 //层已经连接完成,开始建立关系
 2     if (share_from_root) {
 3       // Set up size of top blobs using root_net_
 4       const vector<Blob<Dtype>*>& base_top = root_net_->top_vecs_[layer_id];
 5       const vector<Blob<Dtype>*>& this_top = this->top_vecs_[layer_id];
 6       for (int top_id = 0; top_id < base_top.size(); ++top_id) {
 7         this_top[top_id]->ReshapeLike(*base_top[top_id]);
 8       }
 9     } else {
10       layers_[layer_id]->SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]);
11 }
12 
13 //SetUp()函数的具体内容
14 void SetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
15     InitMutex();
16     CheckBlobCounts(bottom, top);
17     LayerSetUp(bottom, top);
18     Reshape(bottom, top);
19     SetLossWeights(top);
20   }

 对于SetUp()函数,包含了CheckBlobCounts()LayerSetUp()SetLossWeights()Reshape()等子函数,CheckBlobCounts()函数式读取Blob的数量,LayerSetUp()Reshape()是虚函数,会在相应的层中实现这两个函数,SetLossWeights(top)函数会把top(输出blob)loss weight进行初始化,loss weight是用来表不同Layer产生的loss的重要性,Layer名称中以Loss结尾表示这是一个会产生lossLayer,其他的Layer只是单纯的用于中间计算,同时每一层的loss值就是所有输出top blobloss值的和。到此当前层的结构建立完成。经过多次循环,就可以构建整个网络。

确定网络层需要计算的blob

该部分的作用是确定哪些层或哪些层的blob需要参与计算,比如前向时需要确定哪些层的blob需要计算loss,后向时确定哪些层的blob需要计算diff。一个layer是否需要backward computation,主要依据两个方面:

  (1)layertop blob 是否参与loss的计算;

  (2)layerbottom blob 是否需要backward computation,比如Data层一般就不需要backward computation

对于前向的过程,部分源码如下: 

 1     ..............
 2 for (int param_id = 0; param_id < num_param_blobs; ++param_id) {
 3       const ParamSpec* param_spec = (param_id < param_size) ?
 4           &layer_param.param(param_id) : &default_param_spec;
 5       const bool param_need_backward = param_spec->lr_mult() != 0;
 6       need_backward |= param_need_backward;
 7       layers_[layer_id]->set_param_propagate_down(param_id, param_need_backward);
 8     } 
 9  for (int param_id = 0; param_id < num_param_blobs; ++param_id) {
10      ...........
11       AppendParam(param, layer_id, param_id);
12     }

 AppendParam()函数的作用是记录带有参数的层或者blob对于某些有参数的层,例如:卷基层、全连接层有weightbias。该函数主要是修改和参数有关的变量,实际的层参数的blob在上面提到的setup()函数中已经创建。对于后向的过程和前向类似,部分源码如下:

 1 if (param.force_backward()) {
 2     for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) {//迭代所有层
 3       layer_need_backward_[layer_id] = true;//需要参与backward
 4       for (int bottom_id = 0;
 5            bottom_id < bottom_need_backward_[layer_id].size(); ++bottom_id) {//每一层下的需要计算diff的所有blob
 6         bottom_need_backward_[layer_id][bottom_id] =
 7             bottom_need_backward_[layer_id][bottom_id] ||
 8             layers_[layer_id]->AllowForceBackward(bottom_id);
 9         blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] =
10             blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] ||
11             bottom_need_backward_[layer_id][bottom_id];
12       }
13       for (int param_id = 0; param_id < layers_[layer_id]->blobs().size();
14            ++param_id) {//设置不需要计算参数的层
15         layers_[layer_id]->set_param_propagate_down(param_id, true);
16       }
17     }
18   }

 

当神已无能为力,那便是魔渡众生
目录
相关文章
|
6天前
|
存储 SQL 安全
网络安全与信息安全:构建安全防线的关键策略
本文深入探讨了网络安全与信息安全领域的核心要素,包括网络安全漏洞、加密技术以及安全意识的重要性。通过对这些关键领域的分析,旨在为读者提供一套综合性的防护策略,帮助企业和个人在日益复杂的网络环境中保障数据安全。
21 4
|
11天前
|
安全 算法 网络安全
网络安全与信息安全:构建数字世界的坚固防线在数字化浪潮席卷全球的今天,网络安全与信息安全已成为维系社会秩序、保障个人隐私和企业机密的关键防线。本文旨在深入探讨网络安全漏洞的本质、加密技术的前沿进展以及提升公众安全意识的重要性,通过一系列生动的案例和实用的建议,为读者揭示如何在日益复杂的网络环境中保护自己的数字资产。
本文聚焦于网络安全与信息安全领域的核心议题,包括网络安全漏洞的识别与防御、加密技术的应用与发展,以及公众安全意识的培养策略。通过分析近年来典型的网络安全事件,文章揭示了漏洞产生的深层原因,阐述了加密技术如何作为守护数据安全的利器,并强调了提高全社会网络安全素养的紧迫性。旨在为读者提供一套全面而实用的网络安全知识体系,助力构建更加安全的数字生活环境。
|
7天前
|
人工智能 安全 网络安全
云计算与网络安全:构建安全的数字基石##
在当今数字化时代,云计算已成为推动企业创新和效率的关键驱动力。然而,随着数据上云,网络安全威胁也日益增多,对信息的保护提出了更高要求。本文将深入探讨云计算服务模型、面临的主要网络安全挑战,以及如何通过技术手段和管理策略来强化信息安全,确保数据的完整性、可用性和保密性。 ##
|
9天前
|
存储 安全 网络安全
云计算与网络安全:构建安全的数字基石##
随着云计算技术的飞速发展,越来越多的企业和个人选择将数据和应用迁移到云端。然而,在享受云计算带来的便利和效率的同时,网络安全问题也日益凸显。本文将深入探讨云计算环境中的网络安全挑战,分析云服务、网络安全及信息安全等关键技术领域的现状与发展趋势,并提出相应的解决策略。 ##
|
1天前
|
数据采集 存储 JavaScript
构建你的第一个Python网络爬虫
【9月更文挑战第34天】在数字信息泛滥的时代,快速有效地获取和处理数据成为一项重要技能。本文将引导读者通过Python编写一个简易的网络爬虫,实现自动化地从网页上抓取数据。我们将一步步走过代码的编写过程,并探讨如何避免常见陷阱。无论你是编程新手还是想扩展你的技术工具箱,这篇文章都将为你提供有价值的指导。
30 18
|
8天前
|
人工智能 供应链 安全
网络安全与信息安全:构建数字世界的坚固防线在当今数字化时代,网络安全已成为维护个人隐私、企业机密和国家安全的重要基石。本文旨在探讨网络安全漏洞、加密技术及安全意识等关键领域,通过深入浅出的方式,引导读者理解网络安全的核心要素,并分享实用的防护策略,共同守护我们的数字世界。
随着互联网技术的飞速发展,网络安全威胁日益凸显,成为全球关注的焦点。本文聚焦网络安全的三大核心议题——网络安全漏洞、加密技术与安全意识,旨在揭示它们之间的相互关联与重要性。通过剖析真实案例,展现网络攻击的复杂性与破坏力;解析加密技术的原理与实践,强调其在保护数据安全中的关键作用;同时,倡导提升公众安全意识,构建多层次的网络安全防护体系。本文不仅为专业人士提供技术参考,也旨在提高普罗大众的网络安全认知,共同筑牢数字世界的安全防线。
|
6天前
|
机器学习/深度学习 安全 网络安全
云计算与网络安全的融合:构建安全高效的云服务体系
本文深入探讨了云计算与网络安全之间的紧密联系,特别是在云服务、网络安全和信息安全等关键技术领域。随着云计算技术的迅猛发展,数据安全成为企业和组织面临的主要挑战之一。通过分析当前云服务中的安全漏洞和威胁,本文提出了一系列增强云计算环境安全性的策略和技术措施,包括加密技术、访问控制、身份验证以及安全审计等。此外,还讨论了未来云计算和网络安全技术的发展趋势,强调了技术创新在提高数据处理效率和保护信息安全中的重要性。
|
9天前
|
SQL 安全 网络安全
网络安全与信息安全:构建数字世界的坚固防线
在数字化时代,网络安全与信息安全已成为维护数据完整性、保障隐私安全和确保业务连续性的关键。本文将深入探讨网络安全漏洞的形成原因、常见类型及其影响,解析加密技术的原理、分类及应用场景,强调个人和企业提升安全意识的重要性,并分享实用的防护措施。通过这些内容的学习,读者将能够更好地理解网络安全挑战,掌握保护自身免受网络威胁的方法,共同构建一个更加安全的网络环境。
|
11天前
|
数据采集 存储 JavaScript
构建您的第一个Python网络爬虫:抓取、解析与存储数据
【9月更文挑战第24天】在数字时代,数据是新的金矿。本文将引导您使用Python编写一个简单的网络爬虫,从互联网上自动抓取信息。我们将介绍如何使用requests库获取网页内容,BeautifulSoup进行HTML解析,以及如何将数据存储到文件或数据库中。无论您是数据分析师、研究人员还是对编程感兴趣的新手,这篇文章都将为您提供一个实用的入门指南。拿起键盘,让我们开始挖掘互联网的宝藏吧!
|
11天前
|
存储 安全 网络安全
网络安全与信息安全:构建安全的数字堡垒
在数字化时代,网络安全与信息安全已成为个人、企业乃至国家不可忽视的重要议题。本文旨在探讨网络安全漏洞的本质、加密技术的应用以及提升公众安全意识的重要性,帮助读者构建起一道坚固的数字防线。
下一篇
无影云桌面