Caffe源碼解析3:Layer

轉載請註明出處,樓燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/

layer這個類能夠說是裏面最終的一個基本類了,深度網絡呢就是一層一層的layer,相互之間經過blob傳輸數據鏈接起來。首先layer必需要實現一個forward function,前遞函數固然功能能夠本身定義啦,在forward中呢他會從input也就是Layer的bottom,對了caffe裏面網絡的前一層是叫bottom的,從bottom中獲取blob,而且計算輸出的Blob,固然他們也會實現一個反向傳播,根據他們的input的blob以及output blob的error gradient 梯度偏差計算獲得該層的梯度偏差。從公式中也能夠看到:
\[\delta^l=((w^{l+1})^T\delta^{l+1}) \sigma'(z^l)\]網絡

首先來看layer類的構造部分,以及Public部分的函數函數

template <typename Dtype>
class Layer {
 public:
  explicit Layer(const LayerParameter& param)
    : layer_param_(param), is_shared_(false) {
      // Set phase and copy blobs (if there are any).
      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() {}

首先得到當前網絡的Phase,是train仍是test,在初始化列表初始化LayerParameter,以後blobs_這裏存放的是一個指向blob類的shared_ptr指針的一個vector,在這裏是申請空間,而後將傳入的layer_param中的blob拷貝過來。spa

void SetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
    InitMutex();
    CheckBlobCounts(bottom, top);
    LayerSetUp(bottom, top);
    Reshape(bottom, top);
    SetLossWeights(top);
  }

這裏是Setup函數,首先check 這個bottom和top的blob是否正確,再調用Layersetup對每一具體的層作進一步設置,以後再作reshape來設置top blobs和internal buffer。最後再設置loss weight multiplier 的blob對每個非零的loss和weight,通常這個方法被繼承以後是不會被重寫的。scala

virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top)
virtual inline bool ShareInParallel() 
inline bool IsShared() const
inline void SetShared(bool is_shared)

LayerSetup就是對具體某一個layer的setup,被上面的那個函數所調用,ShareInParallel和IsShared和SetShared分別是用來返回並行狀態和得到這一layer是否被多個nets所共享,默認是除了data layer都是關閉的。在多個GPU下的Train階段以及share是true的狀況下,is_shared將會被置成true。指針

virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) = 0;

這個reshape主要是layer用來根據輸入的blob調節Internal buffer以及輸出的Blob的code

注意

接下來是幾個最重要的函數,首先是Forward.這實際上是一個裝飾器,繼承以後在調用的調用其相應的forward_cpu或者forward_gpu,根據輸入的input data blob計算相應的output data blob,同時會反應這一層layer的total loss.blog

inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

這裏是BackWard,實現的是反向傳播,也就是給定top blob額error gradient 計算獲得bottom的error gradient。其輸入時 output blobs ,在Ouput blobs裏面的diff存儲的就是其相應的error gradients。其中propagate_down這個參數跟Bottom的長度是同樣的,每個Index用來指定是否須要反向傳播error gradients 到對應的bottom blob。而bottom 這裏面的diff 區域存放的就是BackWard計算出來相應的gradient error.繼承

inline void Backward(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down,
      const vector<Blob<Dtype>*>& bottom);

若是本身你要實現一個Layer的話,那麼Forward_cpu和Backward_cpu 以及gpu(可選),應該要有本身的實現。ip

傑下來幾個函數比較簡單,統一作說明ci

vector<shared_ptr<Blob<Dtype> > >& blobs()\\返回blobs
const LayerParameter& layer_param() \\返回layer 的參數parameter
virtual void ToProto(LayerParameter* param, bool write_diff = false)\\將層參數寫到Protobuffer裏
inline Dtype loss(const int top_index) const \\給定index返回相應的scalar loss
inline void set_loss(const int top_index, const Dtype value)\\給定Index設置loss
virtual inline const char* type()\\返回layer的type

一下幾個函數主要得到bottom或者top blob的數量狀態,比較簡單,看名字便可

virtual inline int ExactNumBottomBlobs() 
virtual inline int MinBottomBlobs() 
virtual inline int MaxBottomBlobs() 
virtual inline int ExactNumTopBlobs() 
virtual inline int MinTopBlobs() 
virtual inline int MaxTopBlobs() 
virtual inline bool EqualNumBottomTopBlobs()
virtual inline bool AutoTopBlobs()

AllowforceBackward用來設置是否強制梯度返回,由於有些層其實不須要梯度信息 ,後面兩個函數分別查看以及設置是是否須要計算梯度。

virtual inline bool AllowForceBackward(const int bottom_index)
inline bool param_propagate_down(const int param_id)
inline void set_param_propagate_down(const int param_id, const bool value)

好,咱們再後下面看,幾個變量和函數都是保護變量

LayerParameter layer_param_; \\保存layer的參數 parameter
Phase phase_; \\標定階段是train仍是test
vector<shared_ptr<Blob<Dtype> > > blobs_; \\是Blob的一個集合,保存了learnbale參數
vector<bool> param_propagate_down_;\\標誌位是否要計算param blob的梯度
vector<Dtype> loss_;\\用來代表那個top blob 有非零的權重

下面這幾個函數,分別是計算cpu和gpu模式下的正向和反向傳播

virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down,const vector<Blob<Dtype>*>& bottom) = 0;
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down,const vector<Blob<Dtype>*>& bottom)

這個函數被setup調用,主要是check bottom和top 的blob是否match,這裏面用了上面提到的ExactBottomBlobs()等函數

virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)

SetLoss是很是重要的一個步驟,是被SetUp調用來初始化top bottom的weights,而且存儲非零的loss weights 在diff blob裏面

inline void SetLossWeights(const vector<Blob<Dtype>*>& top)

私有變量和函數以下,東西比較少,主要是對並行中的鎖進行控制

bool is_shared_; //標記該layer是否被其餘nets所共享
shared_ptr<boost::mutex> forward_mutex_;//若該layer被shared,則須要這個mutex序列保持forward過程的正常運行
void InitMutex();//初始化forward 的 mutex
void Lock();//locak mutex
void Unlock();//unlock mutex這一看就明白了

最後其實proto裏面有個layer_parameter是挺重要的一個結構,存儲了layer的大量信息,這個具體能夠到proto文件夾下查看,這裏就暫時不列出了。

相關文章
相關標籤/搜索