Eltwise_layer简介

http://www.voidcn.com/blog/thy_2014/article/p-6117416.html

common_layer:

ArgMaxLayer类;

ConcatLayer类:

EltwiseLayer类;

FlattenLayer类;

InnerProductLayer类;

MVNLayer类;

SilenceLayer类;

SoftmaxLayer类,CuDNNSoftmaxLayer类;

SplitLayer类;

SliceLayer类。

呃,貌似就晓得全链接一样!!一个个的来看看这些是可以用在什么地方?

1 ArgMaxLayer:

Compute the index of the @f$ K @f$ max values for each datum across all dimensions @f$ (C \times H \times W) @f$.

Intended for use after a classification layer to produce a prediction. If parameter out_max_val is set to true, output is a vector of pairs (max_ind, max_val) for each image.

 NOTE: does not implement Backwards operation.

1.1 原理介绍:

在做分类之后,也就是经过全链接层之后,对每组数据计算其最大的前K个值。

感觉上有点像:例如我们在使用caffeNet做预测的时候,通常会输出概率最大的5个值,感觉上就是这个层在起作用。(这句话是乱说的哈,没有得到确认!)

所以也不需要反馈什么的了。

1.2 属性变量:

  bool out_max_val_;size_t top_k_;

从下面的构造函数里面可以看到,当out_max_val_赋值为true的时候,输出包括下标和值;赋值为false的时候,就只输出下标。

top_k_的话,用于表明找到前top_k_个最大值吧。

1.3 构造函数:

template <typename Dtype>
void ArgMaxLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {out_max_val_ = this->layer_param_.argmax_param().out_max_val();top_k_ = this->layer_param_.argmax_param().top_k();CHECK_GE(top_k_, 1) << " top k must not be less than 1.";CHECK_LE(top_k_, bottom[0]->count() / bottom[0]->num())<< "top_k must be less than or equal to the number of classes.";
}template <typename Dtype>
void ArgMaxLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {if (out_max_val_) {// Produces max_ind and max_val(*top)[0]->Reshape(bottom[0]->num(), 2, top_k_, 1);} else {// Produces only max_ind(*top)[0]->Reshape(bottom[0]->num(), 1, top_k_, 1);}
}

这两个函数没什么好说的嘛,很好理解。只是好像最开始学习使用caffe,并试着训练一些模型,试着写模型的配置文件时,没有用过这个层一样?! 

1.4 前馈函数:

template <typename Dtype>
void ArgMaxLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {const Dtype* bottom_data = bottom[0]->cpu_data();Dtype* top_data = (*top)[0]->mutable_cpu_data();int num = bottom[0]->num();int dim = bottom[0]->count() / bottom[0]->num();for (int i = 0; i < num; ++i) {std::vector<std::pair<Dtype, int> > bottom_data_vector;for (int j = 0; j < dim; ++j) {bottom_data_vector.push_back(std::make_pair(bottom_data[i * dim + j], j));}std::partial_sort(bottom_data_vector.begin(), bottom_data_vector.begin() + top_k_,bottom_data_vector.end(), std::greater<std::pair<Dtype, int> >());for (int j = 0; j < top_k_; ++j) {top_data[(*top)[0]->offset(i, 0, j)] = bottom_data_vector[j].second;}if (out_max_val_) {for (int j = 0; j < top_k_; ++j) {top_data[(*top)[0]->offset(i, 1, j)] = bottom_data_vector[j].first;}}}
}

我想可以用下面这样一个图来表述ArgMaxLayer的作用:

这个图的最有端,也表明了其计算过程,所以再去读一下上面的前馈函数,就很容易理解了吧。

2 ConcatLayer:

Takes at least two Blob%s and concatenates them along either the num or channel dimension, outputting the result.

2.1 原理介绍:

前馈:(矩阵合并)


反馈:(矩阵分割)


有没有觉得奇怪,什么地方会用这种层呢?其实至少在google的论文中看到了确实用得上这种层,也就是那个“盗梦空间”结构。

2.2 属性变量:

  Blob<Dtype> col_bob_;int count_;int num_;int channels_;int height_;int width_;int concat_dim_;

其中两个变量不怎么认识:

col_bob_:

concat_dim_:指定在链接Blob时的维度,例如当concat_dim_,表示从第2个维度链接Blob。

其余的几个变量都是比较熟悉了,不过需要注意的是,这里的几个值都是用于设置top层Blob大小的。

2.3 构造函数:

template <typename Dtype>
void ConcatLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {concat_dim_ = this->layer_param_.concat_param().concat_dim();CHECK_GE(concat_dim_, 0) <<"concat_dim should be >= 0";CHECK_LE(concat_dim_, 1) <<"For now concat_dim <=1, it can only concat num and channels";
}template <typename Dtype>
void ConcatLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {// Initialize with the first blob.count_ = bottom[0]->count();num_ = bottom[0]->num();channels_ = bottom[0]->channels();height_ = bottom[0]->height();width_ = bottom[0]->width();for (int i = 1; i < bottom.size(); ++i) {count_ += bottom[i]->count();if (concat_dim_== 0) {num_ += bottom[i]->num();} else if (concat_dim_ == 1) {channels_ += bottom[i]->channels();} else if (concat_dim_ == 2) {height_ += bottom[i]->height();} else if (concat_dim_ == 3) {width_ += bottom[i]->width();}}(*top)[0]->Reshape(num_, channels_, height_, width_);CHECK_EQ(count_, (*top)[0]->count());
}

这里在初始化的时候,  Reshape() 中,注意到那个for了吧。假设bottom中有K个Blob,链接的维度是1,那么自然top层Blob的channels_维等于bottom中K个channels之和。 

2.4 前馈反馈函数:

前馈:

template <typename Dtype>
void ConcatLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {Dtype* top_data = (*top)[0]->mutable_cpu_data();if (concat_dim_== 0) {int offset_num = 0;for (int i = 0; i < bottom.size(); ++i) {const Dtype* bottom_data = bottom[i]->cpu_data();int num_elem = bottom[i]->count();caffe_copy(num_elem, bottom_data, top_data+(*top)[0]->offset(offset_num));offset_num += bottom[i]->num();}} else if (concat_dim_ == 1) {int offset_channel = 0;for (int i = 0; i < bottom.size(); ++i) {const Dtype* bottom_data = bottom[i]->cpu_data();int num_elem =bottom[i]->channels()*bottom[i]->height()*bottom[i]->width();for (int n = 0; n < num_; ++n) {caffe_copy(num_elem, bottom_data+bottom[i]->offset(n),top_data+(*top)[0]->offset(n, offset_channel));}offset_channel += bottom[i]->channels();}  // concat_dim_ is guaranteed to be 0 or 1 by LayerSetUp.}
}

这里的实现中,算是默认了,链接的维度只可能是第0维和第1维。既然这样的话,Reshape中也没有必要写那么多了嘛。

其它的就相当于是矩阵的拼接。

反馈:

template <typename Dtype>
void ConcatLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {const Dtype* top_diff = top[0]->cpu_diff();if (concat_dim_ == 0) {int offset_num = 0;for (int i = 0; i < bottom->size(); ++i) {Blob<Dtype>* blob = (*bottom)[i];if (propagate_down[i]) {Dtype* bottom_diff = blob->mutable_cpu_diff();caffe_copy(blob->count(), top_diff + top[0]->offset(offset_num),bottom_diff);}offset_num += blob->num();}} else if (concat_dim_ == 1) {int offset_channel = 0;for (int i = 0; i < bottom->size(); ++i) {Blob<Dtype>* blob = (*bottom)[i];if (propagate_down[i]) {Dtype* bottom_diff = blob->mutable_cpu_diff();int num_elem = blob->channels()*blob->height()*blob->width();for (int n = 0; n < num_; ++n) {caffe_copy(num_elem, top_diff + top[0]->offset(n, offset_channel),bottom_diff + blob->offset(n));}}offset_channel += blob->channels();}}  // concat_dim_ is guaranteed to be 0 or 1 by LayerSetUp.
}

同样,反馈的时候,就是矩阵分割的问题。

3 EltwiseLayer:

Compute elementwise operations, such as product and sum, along multiple input Blobs.

3.1 原理介绍:

对多个矩阵之间按元素进行某种操作,通过源码可以看到,一共提供了:乘以,求和,取最大值,三种操作。

前面介绍了那么多前馈和反馈的原理,这里理解起来应该很容易。这里三种操作,分别进行就好了。

3.2 属性变量:

  EltwiseParameter_EltwiseOp op_;vector<Dtype> coeffs_;Blob<int> max_idx_;bool stable_prod_grad_;

既然实现的是多个Blob之间的某种操作,那么自然会定义是什么操作,所以有了变量op_,但是EltwiseParameter_EltwiseOp类型是在什么地方定义的?

coeffs_:该变量的大小应该是和bottom层的Blob个数是相同的,也就是说如果在进行求和的时候,是按照加权求和的。也就是:

其中的 y 和 x_i 都是矩阵,而coeffs_i是一个值。

max_idx_:如果是进行取最大值操作,为了在反馈的时候,能够反馈得回去,所以需要记录最大值来源于哪个Blob。从后面会看到top层的Blob和bottom的Blob尺寸大小是相同的,但是top层只有一个Blob,而bottom层有多个Blob。

stable_prod_grad_:在乘积方式反馈的时候,控制反馈的方式。

3.3 构造函数:

template <typename Dtype>
void EltwiseLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {CHECK(this->layer_param().eltwise_param().coeff_size() == 0|| this->layer_param().eltwise_param().coeff_size() == bottom.size()) <<"Eltwise Layer takes one coefficient per bottom blob.";CHECK(!(this->layer_param().eltwise_param().operation()== EltwiseParameter_EltwiseOp_PROD&& this->layer_param().eltwise_param().coeff_size())) <<"Eltwise layer only takes coefficients for summation.";op_ = this->layer_param_.eltwise_param().operation();// Blob-wise coefficients for the elementwise operation.coeffs_ = vector<Dtype>(bottom.size(), 1);if (this->layer_param().eltwise_param().coeff_size()) {for (int i = 0; i < bottom.size(); ++i) {coeffs_[i] = this->layer_param().eltwise_param().coeff(i);}}stable_prod_grad_ = this->layer_param_.eltwise_param().stable_prod_grad();
}template <typename Dtype>
void EltwiseLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,vector<Blob<Dtype>*>* top) {const int num = bottom[0]->num();const int channels = bottom[0]->channels();const int height = bottom[0]->height();const int width = bottom[0]->width();for (int i = 1; i < bottom.size(); ++i) {CHECK_EQ(num, bottom[i]->num());CHECK_EQ(channels, bottom[i]->channels());CHECK_EQ(height, bottom[i]->height());CHECK_EQ(width, bottom[i]->width());}(*top)[0]->Reshape(num, channels, height, width);// If max operation, we will initialize the vector index part.if (this->layer_param_.eltwise_param().operation() ==EltwiseParameter_EltwiseOp_MAX && top->size() == 1) {max_idx_.Reshape(bottom[0]->num(), channels, height, width);}
}

从这里的  Reshape() 中看到,该层的所有输入Blob的尺寸必须相同。 

3.4 前馈反馈函数:

前馈:

template <typename Dtype>
void EltwiseLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {int* mask = NULL;const Dtype* bottom_data_a = NULL;const Dtype* bottom_data_b = NULL;const int count = (*top)[0]->count();Dtype* top_data = (*top)[0]->mutable_cpu_data();switch (op_) {case EltwiseParameter_EltwiseOp_PROD:caffe_mul(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), top_data);for (int i = 2; i < bottom.size(); ++i) {caffe_mul(count, top_data, bottom[i]->cpu_data(), top_data);}break;case EltwiseParameter_EltwiseOp_SUM:caffe_set(count, Dtype(0), top_data);// TODO(shelhamer) does BLAS optimize to sum for coeff = 1?for (int i = 0; i < bottom.size(); ++i) {caffe_axpy(count, coeffs_[i], bottom[i]->cpu_data(), top_data);}break;case EltwiseParameter_EltwiseOp_MAX:// Initializemask = max_idx_.mutable_cpu_data();caffe_set(count, -1, mask);caffe_set(count, Dtype(-FLT_MAX), top_data);// bottom 0 & 1bottom_data_a = bottom[0]->cpu_data();bottom_data_b = bottom[1]->cpu_data();for (int idx = 0; idx < count; ++idx) {if (bottom_data_a[idx] > bottom_data_b[idx]) {top_data[idx] = bottom_data_a[idx];  // maxvalmask[idx] = 0;  // maxid} else {top_data[idx] = bottom_data_b[idx];  // maxvalmask[idx] = 1;  // maxid}}// bottom 2++for (int blob_idx = 2; blob_idx < bottom.size(); ++blob_idx) {bottom_data_b = bottom[blob_idx]->cpu_data();for (int idx = 0; idx < count; ++idx) {if (bottom_data_b[idx] > top_data[idx]) {top_data[idx] = bottom_data_b[idx];  // maxvalmask[idx] = blob_idx;  // maxid}}}break;default:LOG(FATAL) << "Unknown elementwise operation.";}
}

这里的代码直接看,容易理解。

反馈:

template <typename Dtype>
void EltwiseLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {const int* mask = NULL;const int count = top[0]->count();const Dtype* top_data = top[0]->cpu_data();const Dtype* top_diff = top[0]->cpu_diff();for (int i = 0; i < bottom->size(); ++i) {if (propagate_down[i]) {const Dtype* bottom_data = (*bottom)[i]->cpu_data();Dtype* bottom_diff = (*bottom)[i]->mutable_cpu_diff();switch (op_) {case EltwiseParameter_EltwiseOp_PROD:if (stable_prod_grad_) {bool initialized = false;for (int j = 0; j < bottom->size(); ++j) {if (i == j) { continue; }if (!initialized) {caffe_copy(count, (*bottom)[j]->cpu_data(), bottom_diff);initialized = true;} else {caffe_mul(count, (*bottom)[j]->cpu_data(), bottom_diff,bottom_diff);}}} else {caffe_div(count, top_data, bottom_data, bottom_diff);}caffe_mul(count, bottom_diff, top_diff, bottom_diff);break;case EltwiseParameter_EltwiseOp_SUM:if (coeffs_[i] == Dtype(1)) {caffe_copy(count, top_diff, bottom_diff);} else {caffe_cpu_scale(count, coeffs_[i], top_diff, bottom_diff);}break;case EltwiseParameter_EltwiseOp_MAX:mask = max_idx_.cpu_data();for (int index = 0; index < count; ++index) {Dtype gradient = 0;if (mask[index] == i) {gradient += top_diff[index];}bottom_diff[index] = gradient;}break;default:LOG(FATAL) << "Unknown elementwise operation.";}}}
}

反馈中的 求和反馈,取最大值的反馈,都还是很好理解。

乘积的反馈好像有点怪怪的。首先来看看成绩反馈时的基本原理:



所以直接使用top_data/bottom_data再乘以top_diff,这个是很好理解的。

可是源代码中提供了两种方式:

第1中方式是:计算mul(x_i),i=0...k-1且i != j

第2种方式就是:top_data/bottom_data

只要数据不是很多0,结果应该是差不多的,那么为什么会用这两种方式呢?不理解。

4 FlattenLayer:


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313163.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PowerBI 秒级实时大屏展示方案 全面助力双十一

双十一来了&#xff0c;你准备好了吗&#xff1f;不管你是否准备完毕&#xff0c;我们带来了全网首发的 PowerBI 秒级实时大屏展示方案&#xff0c;你可以直接用来展示双十一的实时状况。我们一步步来说明这个套件模板教程。真实效果功能如下&#xff1a;全实时展示 双十一 当天…

优化 .net core 应用的 dockerfile

优化 .net core 应用的 dockerfileIntro在给 .net core 应用的写 dockerfile 的时候一直有个苦恼&#xff0c;就是如果有很多个项目&#xff0c;在 dockerfile 里写起来就会很繁琐&#xff0c;有很多项目文件要 copy&#xff0c;dockerfile 还不支持直接批量复制项目文件&#…

C# 8 新特性 - 静态本地方法

从C# 8 开始&#xff0c;本地方法就可以是静态的了。 与其他的本地方法不同&#xff0c;静态的本地方法无法捕获任何本地状态量。 直接看例子&#xff1a; 这段代码里有两个本地方法&#xff0c;他们分别对实例的一个字段和方法里的一个本地变量进行了修改操作&#xff0c;也就…

​.NET手撸2048小游戏

前言2048是一款益智小游戏&#xff0c;得益于其规则简单&#xff0c;又和 2的倍数有关&#xff0c;因此广为人知&#xff0c;特别是广受程序员的喜爱。本文将再次使用我自制的“准游戏引擎” FlysEngine&#xff0c;从空白窗口开始&#xff0c;演示如何“手撸” 2048小游戏&…

自行实现高性能MVC

wcf虽然功能多、扩展性强但是也面临配置忒多&#xff0c;而且restful的功能相当怪异&#xff0c;并且目前没法移植。asp.net core虽然支持webapi&#xff0c;但是功能也相对繁多、配置复杂。就没有一个能让码农们安安心心的写webapi&#xff0c;无需考虑性能、配置、甚至根据问…

caffe matio问题

http://blog.csdn.net/houqiqi/article/details/46469981 注&#xff1a;如果指令行模式实在解决不了/lib/libcaffe.so: undefined reference to Mat_VarReadDataLinear问题&#xff0c;可以尝试在QT下进行训练和测试。 1&#xff0c; 下载matio(http://sourceforge.NET/pro…

技术管理者怎样跳出“泥潭”

近几年面试了不少新人&#xff0c;当问到职业规划时&#xff0c;大多都会说先积累技术&#xff0c;然后往架构师的方向发展。这可能是技术人的一个特质&#xff0c;喜欢跟机器相处&#xff0c;沉浸在代码之中&#xff0c;而不喜欢跟人打交道。现实的情况是&#xff0c;一些中小…

你或许以为你不需要领域驱动设计

作者&#xff1a;邹溪源&#xff0c;长沙资深互联网从业者&#xff0c;架构师社区合伙人&#xff01;一犹记得刚刚参加工作时&#xff0c;是地图厂商四维图新集团旗下的一家子公司&#xff0c;主要从事规划测绘相关软件研发的公司。当时我的项目是为勘测设计院提供相对应的应用…

redis为什么这么火该怎么用

最近一些人在介绍方案时&#xff0c;经常会出现redis这个词&#xff0c;于是很多小伙伴百度完redis也就觉得它是一个缓存&#xff0c;然后项目里面把数据丢进去完事&#xff0c;甚至有例如将实体属性拆分塞进redis hash里面的奇怪用法等等&#xff01;原因是什么呢&#xff1f;…

.Net Core实现健康检查

ASP.NET Core 提供运行状况检查中间件和库&#xff0c;以用于报告应用基础结构组件的运行状况。运行状况探测可以由容器业务流程协调程和负载均衡器用于检查应用的状态。例如&#xff0c;容器业务流程协调程序可以通过停止滚动部署或重新启动容器来响应失败的运行状况检查。负载…

微软宣布加入 OpenJDK,看网上各派的热闹

微软宣布加入 OpenJDK 项目&#xff08;https://www.oschina.net/news/111036/microsoft-to-participate-in-openidk&#xff09;&#xff0c;这两天在微信公众号里面有几种论调&#xff1a;上面这些都是Javaer的观点&#xff0c;在CSharper 对这件事情的反应更奇怪了&#xff…

这6点解释了罗永浩为什么要卖艺

01是的&#xff0c;我们的‘老赖又上热搜了。&#xff08;ps:还是传统的语法&#xff0c;换了个人而已&#xff0c;味道有点改变&#xff09;11 月 3 日下午&#xff0c;罗永浩因锤子科技的 375 万欠款被江苏丹阳法院限制高消费&#xff0c;他不得乘坐飞机头等舱、软卧、高铁等…

微软发布研究报告:企业数据管理普遍混乱,揭秘大数据分析趋势以及PowerBI的崛起机遇...

本文非常重要&#xff0c;忽略者责任自负。我们时常看到很多新闻说企业的数据分析或大数据如何如何高大上&#xff0c;但你自己感觉你自己所处的环境呢&#xff1f;很多小伙伴在群里真切的抱怨到&#xff1a;感觉是一坨祥云。为什么你看到的和你感受到的有如此巨大的反差&#…

Magicodes.Pay,打造开箱即用的统一支付库,已提供ABP模块封装

Magicodes.Pay&#xff0c;打造开箱即用的统一支付库&#xff0c;已提供ABP模块封装简介Magicodes.Pay&#xff0c;是心莱科技团队提供的统一支付库&#xff0c;相关库均使用.NET标准库编写&#xff0c;支持.NET Framework以及.NET Core。目前已提供Abp模块的封装&#xff0c;支…

在.NET Core 3.0中发布单个Exe文件(PublishSingleFile)

假设我有一个简单的“ Hello World”控制台应用程序&#xff0c;我想发送给朋友来运行。朋友没有安装.NET Core&#xff0c;所以我知道我需要为他构建一个独立的应用程序。很简单&#xff0c;我只需在项目目录中运行以下命令&#xff1a;dotnet publish -r win-x64 -c Release …

python import 问题

https://my.oschina.net/leejun2005/blog/109679 python中&#xff0c;每个py文件被称之为模块&#xff0c;每个具有__init__.py文件的目录被称为包。只要模块或者包所在的目录在sys.path中&#xff0c;就可以使用import 模块或import 包来使用。 如果想使用非当前模块中的…

.NET如何写正确的“抽奖”——数组乱序算法

.NET如何写正确的“抽奖”——数组乱序算法数组乱序算法常用于抽奖等生成临时数据操作。就拿年会抽奖来说&#xff0c;如果你的算法有任何瑕疵&#xff0c;造成了任何不公平&#xff0c;在年会现场 code review时&#xff0c;搞不好不能活着走出去。这个算法听起来很简单&#…

maximum mean discrepancy

http://blog.csdn.net/a1154761720/article/details/51516273 MMD&#xff1a;maximum mean discrepancy。最大平均差异。最先提出的时候用于双样本的检测&#xff08;two-sample test&#xff09;问题&#xff0c;用于判断两个分布p和q是否相同。它的基本假设是&#xff1a;如…

FineUICore基础版部署到docker实战

文 | 蒙古海军司令 合作者FineUI用了好多年&#xff0c;最近出了FineUICore版本&#xff0c;一直没时间是试一下docker&#xff0c;前几天买了一个腾讯云服务器&#xff0c;1核2g&#xff0c;装了centos7.6&#xff0c;开始的时候主要是整个个人博客&#xff0c;在腾讯云安装了…

2019全球Microsoft 365开发者训练营(北京站)

Microsoft365介绍&#xff1a;Microsoft365不仅仅是Office 365&#xff0c;它还包括Windows 10操作系统&#xff0c;以及诸多企业级移动和安全应用。它是一套可用于从小型到集团化企业的办公、协作、沟通的企业信息化解决方案。在2017年7月11日举行的Inspire年度合作伙伴大会上…