Caffe Layer.hpp学习

该博文是我自己学习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

然后看一下成员函数:

//显式的构造函数不需要重写,任何初始工作在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)

                
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值