Caffe Layer.hpp学习
2016-01-11 21:55
323 查看
该博文是我自己学习Layer.hpp所做的笔记以及一些思考,第一次学习这种高质量的代码,感觉压力颇大。如有错误或者疑问,欢迎指正,后续也会即使修改更新!
主要定义了一个模板类Layer
首先,看一下数据成员,主要有:
protected:
LayerParameter layer_param_ : The protobuf that stores the layer parameters——caffe.proto文件里定义的message,相应的caffe.pb.h里定义的一个类。
Phase phase_ :The phase: TRAIN or TEST——Phase是caffe.pb.h里定义的一个枚举类型
vector<shared_ptr<Blob<Dtype> > > blobs_ :The vector that stores the learnable parameters as a set of blobs——所定义的向量blobs_里存储的是指向Blob<Dtyp>的智能指针,Blob<Dtype>里面存储的是learnable
parameter, 使用向量是因为weight和bias是分开保存再两个blob中。
vector<bool> param_propagate_down_ : Vector indicating whether to compute the diff of each param blob——决定是否为param blob计算梯度diff,标志每个top blob是否需要计算反向传递的梯度值。
vector<Dtype> loss_ : The vector that indicates whether each top blob has a non-zero weight in the objective function——决定每个top blob 在 objective function是否non-zero weigh,即Losslayer中表示每个top blob计算的loss的权重。
private:
bool is_shared_ : Whether this layer is actually shared by other nets
shared_ptr<boost::mutex> forward_mutex_ : The mutex(互斥锁) for sequential forward if this layer is shared
然后看一下成员函数:
主要定义了一个模板类Layer
首先,看一下数据成员,主要有:
protected:
LayerParameter layer_param_ : The protobuf that stores the layer parameters——caffe.proto文件里定义的message,相应的caffe.pb.h里定义的一个类。
Phase phase_ :The phase: TRAIN or TEST——Phase是caffe.pb.h里定义的一个枚举类型
vector<shared_ptr<Blob<Dtype> > > blobs_ :The vector that stores the learnable parameters as a set of blobs——所定义的向量blobs_里存储的是指向Blob<Dtyp>的智能指针,Blob<Dtype>里面存储的是learnable
parameter, 使用向量是因为weight和bias是分开保存再两个blob中。
vector<bool> param_propagate_down_ : Vector indicating whether to compute the diff of each param blob——决定是否为param blob计算梯度diff,标志每个top blob是否需要计算反向传递的梯度值。
vector<Dtype> loss_ : The vector that indicates whether each top blob has a non-zero weight in the objective function——决定每个top blob 在 objective function是否non-zero weigh,即Losslayer中表示每个top blob计算的loss的权重。
private:
bool is_shared_ : Whether this layer is actually shared by other nets
shared_ptr<boost::mutex> forward_mutex_ : The mutex(互斥锁) for sequential forward if this layer is shared
然后看一下成员函数:
//显式的构造函数不需要重写,任何初始工作在SetUp()中完成;构造方法只是获取phase值,并且如果层说明参数(layer_param_)中提供了权值和偏置参数,也复制。 explicit Layer(const LayerParameter& param) : layer_param_(param), is_shared_(false) { // Set phase and copy blobs (if there are any). phase_ = param.phase(); //在message Layerparameter中,<code>repeated BlobProto blobs</code>表示的是"The blobs containing the numeric parameters of the layer", //也就是说,在Layer中,blob存储的是参数numeric parameters,(当然参数也可以算是一种数据了,毕竟Blob是用来存储数据的)而Layer的input bottom blob以及output top blob 里面存放的才是我们通常所说的数据数据。 if (layer_param_.blobs_size() > 0) { blobs_.resize(layer_param_.blobs_size()); for (int i = 0; i < layer_param_.blobs_size(); ++i) { blobs_[i].reset(new Blob<Dtype>());//blobs_的元素是指向Blob<Dtype>的智能指针,需要注意的是这句代码采用的是成员运算符,下一句代码使用的是箭头运算符。reset是因为数据类型Dtype可能会发生变化 blobs_[i]->FromProto(layer_param_.blobs(i));//调用的是Blob类型的FromProto函数 }//读取的是权值和偏置参数 } }
/** * @brief Implements common layer setup functionality. * 实现每个layer对象的setup函数 * * @param bottom the preshaped input blobs * 层的输入数据,blob中的存储空间已申请 * @param top * the allocated but unshaped output blobs, to be shaped by Reshape * 层的输出数据,blob对象已构造但是其中的存储空间未申请,具体在Reshape函数现实现 * * Checks that the number of bottom and top blobs is correct. * Calls LayerSetUp to do special layer setup for individual layer types, * followed by Reshape to set up sizes of top blobs and internal buffers. * S<strong>ets up the loss weight multiplier blobs for any non-zero loss weights</strong>. * This method may not be overridden. * 初始化构造函数SetUp * 1. 检查输入输出blob个数是否满足要求,每个层能处理的输入输出数据不一样 * 2. 调用LayerSetUp函数初始化特殊的层,每个Layer子类需重写这个函数完成定制的初始化 * 3. 调用Reshape函数为top blob分配合适大小的存储空间 * 4. 为每个top blob设置loss weight multiplier blobs(损失权重乘子blobs),非LossLayer的top blob的loss weight值为零.<strong>---!!!Sets up the loss weight multiplier blobs for any non-zero loss weights!!!---</strong> * * 此方法非虚函数,不用重写,模式固定 */ void SetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { InitMutex(); CheckBlobCounts(bottom, top); LayerSetUp(bottom, top); Reshape(bottom, top); SetLossWeights(top); }
/** * Called by the parent Layer's SetUp to check that the number of bottom * and top Blobs provided as input match the expected numbers specified by * the {ExactNum,Min,Max}{Bottom,Top}Blobs() functions.检查Layer的top blob以及bottom blob的个数。 */ virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { if (ExactNumBottomBlobs() >= 0) { CHECK_EQ(ExactNumBottomBlobs(), bottom.size()) << type() << " Layer takes " << ExactNumBottomBlobs() << " bottom blob(s) as input."; } if (MinBottomBlobs() >= 0) { CHECK_LE(MinBottomBlobs(), bottom.size()) << type() << " Layer takes at least " << MinBottomBlobs() << " bottom blob(s) as input."; } if (MaxBottomBlobs() >= 0) { CHECK_GE(MaxBottomBlobs(), bottom.size()) << type() << " Layer takes at most " << MaxBottomBlobs() << " bottom blob(s) as input."; } if (ExactNumTopBlobs() >= 0) { CHECK_EQ(ExactNumTopBlobs(), top.size()) << type() << " Layer produces " << ExactNumTopBlobs() << " top blob(s) as output."; } if (MinTopBlobs() >= 0) { CHECK_LE(MinTopBlobs(), top.size()) << type() << " Layer produces at least " << MinTopBlobs() << " top blob(s) as output."; } if (MaxTopBlobs() >= 0) { CHECK_GE(MaxTopBlobs(), top.size()) << type() << " Layer produces at most " << MaxTopBlobs() << " top blob(s) as output."; } if (EqualNumBottomTopBlobs()) { CHECK_EQ(bottom.size(), top.size()) << type() << " Layer produces one top blob as output for each " << "bottom blob input."; } }
/** * @brief Does layer-specific setup: your layer should implement this function * as well as Reshape. * 定制初始化,每个子类layer必须实现此虚函数!!! * * @param bottom * the preshaped input blobs, whose data fields store the input data for * this layer * 输入blob, 数据成员data_和diff_存储了相关数据 * @param top * the allocated but unshaped output blobs * 输出blob, blob对象已构造但数据成员的空间尚未申请 * * This method should do one-time layer specific setup. This includes reading * and processing relevent parameters from the <code>layer_param_</code>. * Setting up the shapes of top blobs and internal buffers should be done in * <code>Reshape</code>, which will be called before the forward pass to * adjust the top blob sizes. * 此方法执行一次定制化的层初始化,包括从layer_param_读入并处理相关的层权值和偏置参数, * 调用Reshape函数申请top blob的存储空间 */ virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {}
/** * @brief Adjust the shapes of top blobs and internal buffers to accommodate * the shapes of the bottom blobs. * * @param bottom the input blobs, with the requested input shapes * @param top the top blobs, which should be reshaped as needed * * This method should reshape top blobs as needed according to the shapes * of the bottom (input) blobs, as well as reshaping any internal buffers * and making any other necessary adjustments so that the layer can * accommodate the bottom blobs. * * <strong>-----reshape top blobs 以及 internal buffers以适应bottom (input) blobs-----bottom和top都有多个blob</strong> */ virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) = 0;
/** * Called by SetUp to initialize the weights associated with any top blobs in * the loss function. Store non-zero loss weights in the diff blob. * 初始化损失权重---<strong>为每个top blob设置loss weight multiplier blobs(损失权重乘子blobs)</strong>,非LossLayer的top blob的loss weight值为零 * <strong>=====!!!! Store non-zero loss weights in the diff blob !!!!=====</strong> */ inline void SetLossWeights(const vector<Blob<Dtype>*>& top) { const int num_loss_weights = layer_param_.loss_weight_size();<em><strong>//message Layerparameter中的<code>repeated float loss_weight = 5;</code>表示的是“The amount of weight to assign each top blob in the objective”</strong></em> if (num_loss_weights) { CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be " "unspecified or specified once per top blob."; for (int top_id = 0; top_id < top.size(); ++top_id) { const Dtype loss_weight = layer_param_.loss_weight(top_id); if (loss_weight == Dtype(0)) { continue; } this->set_loss(top_id, loss_weight);<em>//修改Layer的数据成员loss_,其存储的是loss_weight</em> const int count = top[top_id]->count(); Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff();//返回指向某块Blob的diff所对应的内存空间的指针,并且由于mutable_cpu_diff返回的是void*指针,so,还有一个类型转换过程 caffe_set(count, loss_weight, loss_multiplier);<strong><em>//loss_multiplier是一个void指针,caffe_set函数表示用loss_weight初始化这块内存,<span style="font-family: Arial, Helvetica, sans-serif;">使其能够存储count个loss_weight(when loss_weight!=0),if loss_weight=0,则用0值来初始化.-----这里为blob的每个元素都初始化了一个loss_weight, 那么在后面计算loss时,只要sum(top)就可以了(我觉得是这样,后面的代码还没看)</span></em></strong> } } }
// Forward and backward wrappers. You should implement the cpu and // gpu specific implementations instead, and should not change these // functions. // 有一点需要记住的是:在模板类Layer的forward函数里面,会再次调用调用Reshape()函数,也就是说,即使我们每次迭代每个minibatch里的图像(或者特征)的shape不一致,也没有关系, // 因为在真正调用forward_cpu / forward_gpu 之前都会重新Reshape;SetUp里面的Reshape只是设置了初始的Top blobs 的shape template <typename Dtype> inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Lock during forward to ensure sequential forward Lock(); Dtype loss = 0; Reshape(bottom, top); switch (Caffe::mode()) { case Caffe::CPU: Forward_cpu(bottom, top); for (int top_id = 0; top_id < top.size(); ++top_id) { if (!this->loss(top_id)) { continue; } const int count = top[top_id]->count(); const Dtype* data = top[top_id]->cpu_data(); const Dtype* loss_weights = top[top_id]->cpu_diff(); loss += caffe_cpu_dot(count, data, loss_weights);//这里的loss_weights我觉得应该是SetLossWeights()方法中模板函数caffe_set()所初始化的loss_weight } break; case Caffe::GPU: Forward_gpu(bottom, top); #ifndef CPU_ONLY for (int top_id = 0; top_id < top.size(); ++top_id) { if (!this->loss(top_id)) { continue; } const int count = top[top_id]->count(); const Dtype* data = top[top_id]->gpu_data(); const Dtype* loss_weights = top[top_id]->gpu_diff(); Dtype blob_loss = 0; caffe_gpu_dot(count, data, loss_weights, &blob_loss); loss += blob_loss; } #endif break; default: LOG(FATAL) << "Unknown caffe mode."; } Unlock(); return loss; }
// Serialize LayerParameter to protocol buffer template <typename Dtype> void Layer<Dtype>::ToProto(LayerParameter* param, bool write_diff) { param->Clear(); param->CopyFrom(layer_param_); param->clear_blobs(); for (int i = 0; i < blobs_.size(); ++i) { blobs_[i]->ToProto(param->add_blobs(), write_diff);//调用Blob的ToProto方法。param->add_blobs()返回Blobproto*,从而将Blob的shape_,data_,diff_分别copy到BlobProto的shape,data,diff,完成序列化 } }
</pre><pre name="code" class="cpp">在layer.hpp中 代码“DISABLE_COPY_AND_ASSIGN(layer)”是为了阻止编译器自动生成copy构造函数和重载赋值运算操作符函数 (参考http://blog.csdn.net/lingerlanlan/article/details/24379607)
相关文章推荐
- extjs desktop startmenu (開始菜单)
- nodejs Tips5
- JQuery datepicker 用法
- html5响应式
- jquery上传图片到服务器
- Js-Html 前端系列--显示有格式的文本
- Jquery动态添加节点,绑定事件失效的解决方法
- 登录时前端用户名和密码为空时提示
- Parse终极总结
- 简单jQuery插件实现
- Node.js的Hashish模块
- 前端工程师与SEO搜索引擎优化(笔记总结)
- jquery 显示/ 隐藏 页面中部分内容
- jquery 显示/ 隐藏 页面中部分内容
- struts +bootstrap+freemarker实现的后台黑名单管理。
- nodejs Tips4
- html5 Canvas画图3:1px线条模糊问题
- LeetCode-- Swap Nodes in Pairs
- POJ_P1274 The Perfect Stall(二分图匹配+匈牙利算法)
- pace.js和NProgress.js两个加载进度插件的一点小总结