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拷貝過來。

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,一般這個方法被繼承之后是不會被重寫的。

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的

注意###

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

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(可選),應該要有自己的實現。

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

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文件夾下查看,這里就暫時不列出了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM