1. 程式人生 > >Caffe源碼解析3:Layer

Caffe源碼解析3:Layer

ons tor typename log cpu AR 申請 int 當前

轉載:http://home.cnblogs.com/louyihang-loves-baiyan/

layer這個類可以說是裏面最終的一個基本類,深度網絡就是一層一層的layer,相互之間通過blob傳輸數據連接起來。首先layer必須要實現一個forward function,前遞函數功能可以自己定義,在forward中他會從input也就是layer的bottom中獲取blob,caffe裏面網絡的前一層是叫bottom,並且計算輸出的blob,當然他們也會實現一個反向傳播,根據他們的input的blob以及output blob 的error gradient梯度誤差計算得到該層的梯度誤差。

首先來看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,在初始化列表初始化LayerParaneter,之後blibs_這裏存放的是一個指向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和計算得到bottom的error gradient.其輸入是output blobs,在Output blobs裏面的diff存儲的就是其相應的error gradients。其中propagate_down這個參數跟Bottom的長度是一樣的,每一個index用來指定是否需要反向傳播error gradients到對應的bootom blob。而botton這裏賣弄的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這一看就明白了

Caffe源碼解析3:Layer