首页 > 代码库 > 【Caffe代码解析】Layer网络层

【Caffe代码解析】Layer网络层

Layer 功能:

是全部的网络层的基类,当中。定义了一些通用的接口,比方前馈。反馈。reshape,setup等。

#ifndef CAFFE_LAYER_H_
#define CAFFE_LAYER_H_

#include <algorithm>
#include <string>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/device_alternate.hpp"

namespace caffe {
 // 功能:全部的网络层的基类,定义的全部的网络层的通用接口。

// 前馈接口,必须实现 // 反馈接口,须要的时候实现,计算梯度。

template <typename Dtype> class Layer { public: /** * 每个网络层须要自定义它的setup而不须要构造函数 */ explicit Layer(const LayerParameter& param) : layer_param_(param) { //通过网络层參数来构造网络层 phase_ = param.phase(); 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_[i]->FromProto(layer_param_.blobs(i)); } } } // 析构函数 virtual ~Layer() {} /** * 实现一些通用的设置功能 * * @param bottom 网络层的输入的shape * @param top 网络层的输出,须要被reshape * 调用 LayerSetUp 来对每个网络层进行特殊化的处理, * 调用reshape top * 设置 数值权重 * 这种方法能够不被重载。

*/ void SetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { CheckBlobCounts(bottom, top); LayerSetUp(bottom, top); Reshape(bottom, top); SetLossWeights(top); } /** * @brief 设置一些层相关的设置,定义的层须要实现这种方法以及Reshape方法 */ //设置网络层 virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {} /** * @brief 调整top blob以适应bottom blob。 */ virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) = 0; /** * @brief 给定 bottom blobs, 计算 top blobs 以及 loss. * 每个网络层都须要定义cpu版本号的前馈,可选gpu版本号的前馈 */ //前馈 inline Dtype Forward(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); /** * @brief 给定 top blob 的梯度, 计算 bottom blob 梯度. * @param propagate_down 向量,长度为ibottom 的个数。每个索引值表示是是否将损失梯度值反馈到该bottom中 */ //反馈 inline void Backward(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom); /** * @brief 返回可学习的參数 blobs. */ vector<shared_ptr<Blob<Dtype> > >& blobs() { return blobs_; } /** * @brief 返回网络层參数 */ const LayerParameter& layer_param() const { return layer_param_; } //序列化 virtual void ToProto(LayerParameter* param, bool write_diff = false); /** * @brief 返回指定索引的标量损失值。 */ inline Dtype loss(const int top_index) const { return (loss_.size() > top_index) ?

loss_[top_index] : Dtype(0); } /** * @brief 设置网络层制定索引位置的loss */ inline void set_loss(const int top_index, const Dtype value) { if (loss_.size() <= top_index) { loss_.resize(top_index + 1, Dtype(0)); } loss_[top_index] = value; } /** * @brief 返回网络层名字,字符串描写叙述u */ virtual inline const char* type() const { return ""; } //Bottom的blob的确切数目 virtual inline int ExactNumBottomBlobs() const { return -1; } //Bottom blob的最小数目 virtual inline int MinBottomBlobs() const { return -1; } //Botttom的确切数目 virtual inline int MaxBottomBlobs() const { return -1; } //Top Blob的确切数目 virtual inline int ExactNumTopBlobs() const { return -1; } //最小的blob的数目 virtual inline int MinTopBlobs() const { return -1; } // 最大的blob的数目 virtual inline int MaxTopBlobs() const { return -1; } // 是否bottom 和top的数目同样 virtual inline bool EqualNumBottomTopBlobs() const { return false; } // 是否自己主动Top blob virtual inline bool AutoTopBlobs() const { return false; } //查询某一个bottom是否强制bp virtual inline bool AllowForceBackward(const int bottom_index) const { return true; } //查询某一个blob是否bp inline bool param_propagate_down(const int param_id) { return (param_propagate_down_.size() > param_id) ? param_propagate_down_[param_id] : false; } //设置某一个blob是否bp。 inline void set_param_propagate_down(const int param_id, const bool value) { if (param_propagate_down_.size() <= param_id) { param_propagate_down_.resize(param_id + 1, true); } param_propagate_down_[param_id] = value; } protected: // 网络层參数 LayerParameter layer_param_; // 模式 Phase phase_; //用blob来存储一系列向量 vector<shared_ptr<Blob<Dtype> > > blobs_; //是否bp的向量 vector<bool> param_propagate_down_; //存储top的loss vector<Dtype> loss_; //cpu版本号的前馈实现 virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) = 0; //gpu版本号的前馈实现 virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // LOG(WARNING) << "Using CPU code as backup."; return Forward_cpu(bottom, top); } //cpu版本号的前馈实现 virtual void Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) = 0; //gpu版本号的反馈实现 virtual void Backward_gpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { // LOG(WARNING) << "Using CPU code as backup."; Backward_cpu(top, propagate_down, bottom); } // 核查bootom和top的大小是否与该layer层指定的一致。

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."; } } // 用blob初始化损失权重。 inline void SetLossWeights(const vector<Blob<Dtype>*>& top) { const int num_loss_weights = layer_param_.loss_weight_size(); 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); const int count = top[top_id]->count(); Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff(); caffe_set(count, loss_weight, loss_multiplier); } } } DISABLE_COPY_AND_ASSIGN(Layer); }; // class Layer // 前馈。依据caffe的mode 调用相相应的cpu实现或者是gpu实现。而且计算损失函数值。

template <typename Dtype> inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { 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 = http://www.mamicode.com/top[top_id]->cpu_data();"hljs-keyword">const Dtype* loss_weights = top[top_id]->cpu_diff(); loss += caffe_cpu_dot(count, data, loss_weights); } 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 = http://www.mamicode.com/top[top_id]->gpu_data();"hljs-keyword">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."; } return loss; } //反向传播梯度。依据Caffe的mode是在GPU还是CPU,调用相相应版本号的函数 //propagate_down 用于控制相应的层是否bp template <typename Dtype> inline void Layer<Dtype>::Backward(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { switch (Caffe::mode()) { case Caffe::CPU: Backward_cpu(top, propagate_down, bottom); break; case Caffe::GPU: Backward_gpu(top, propagate_down, bottom); break; default: LOG(FATAL) << "Unknown caffe mode."; } } // 序列化网络层參数到协议缓存。终于是调用blob写入协议缓存。 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); } } } // namespace caffe #endif // CAFFE_LAYER_H_

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

【Caffe代码解析】Layer网络层