caffe layer基类函数理解

class Layer {
 public:
  /**
   * You should not implement your own constructor. Any set up code should go
   * to SetUp(), where the dimensions of the bottom blobs are provided to the
   * layer.
   */
  explicit Layer(const LayerParameter& param)
    : layer_param_(param) {
      // Set phase and copy blobs (if there are any).
      phase_ = param.phase();
	  // If the prototxt file has been set up blobs parameter,blobs parameters is used to initialize,
	  // otherwise, the LayerSetUp() is used to initialized.Here, blobs_ is used to save weight and bias
      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>());
		  // read the blobs value in the prototxt file ,and to initialize the blobs_,
		  // which is saved weight and bias 
      <span style="color:#ff0000;">    blobs_[i]->FromProto(layer_param_.blobs(i));// 这句话改怎么理解,从哪里来</span>
        }
      }
    }
layer基类代码 
 explicit Layer(const LayerParameter& param)
    : layer_param_(param) {
      // 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));
        }
      }
    }
 
在抽象layer的初始化构造函数,有 if (layer_param_.blobs_size() > 0) 又因为: repeated 是可供选择的
 repeated float data = 5 [packed = true];
  repeated float diff = 6 [packed = true];  repeated表示可以重复设置。 根据设置大小
即,如果配置文件,哪一层不去配置这个,那么基类初始化构造函数则不去设置 blobs(i)。而是在具体类的实现中设置
 
例如:在inner_product_layer.cpp 中有如下:
 if (this->blobs_.size() > 0) { //  这里大于0,即在基类构造函数中已经初始化了。也就是在配置文件中配置了。
    LOG(INFO) << "Skipping parameter initialization";
  } else { // 如果配置文件没有配置。 即基类构造没有初始化。所有这里需要初始化。
    if (bias_term_) {
      this->blobs_.resize(2);
    } else {
      this->blobs_.resize(1);
    }
同样在base_conv_layer.cpp中看到如下:
 if (this->blobs_.size() > 0) {
    LOG(INFO) << "Skipping parameter initialization";
  } else {
    if (bias_term_) {
      this->blobs_.resize(2);
    } else {
      this->blobs_.resize(1);
    }
 
综上所述,我理解是,根据在配置文件中,每层的BlobProto blobs 这个参数是否配置,如果配置,那么就是在layer的构造函数中 进行读取初始化,如果没有配置,那么就是在具体的类的LayerSetUp()函数中初始化。我们平时很少在别人模型上继续训练,所以没有配置这个
  这个功能可能是在迁移学习中应用的,在别人训练好的模型基础上,训练自己的模型,可以通过这个去设置, 同时我们可以选择在某一层用别人训练好的结果。


---------------------------------------------------------------------------------------------------------------------------------------------

下面是个人理解,不对地方还请您指点

(1) void Blob<Dtype>::FromProto(const BlobProto& proto, bool reshape) {

........
   Dtype* data_vec = mutable_cpu_data();
for (int i = 0; i < count_; ++i) {
    data_vec[i] = proto.data(i);
  }
  if (proto.diff_size() > 0) {
    Dtype* diff_vec = mutable_cpu_diff();
    for (int i = 0; i < count_; ++i) {
      diff_vec[i] = proto.diff(i);
    }
  }

.......
}

 

函数中,proto.data(i)和proto.diff(i);是通过BlobProto& proto 参数传入的。

 

(2) 传参函数在net.cpp的Forward()函数中

string Net<Dtype>::Forward(const string& input_blob_protos, Dtype* loss) {
  BlobProtoVector blob_proto_vec;
  if (net_input_blobs_.size()) {
    blob_proto_vec.ParseFromString(input_blob_protos);
    CHECK_EQ(blob_proto_vec.blobs_size(), net_input_blobs_.size())
        << "Incorrect input size.";
    for (int i = 0; i < blob_proto_vec.blobs_size(); ++i) {
      net_input_blobs_[i]->FromProto(blob_proto_vec.blobs(i));
    }
  }
(3)
通过solver.cpp

void Solver<Dtype>::Test(const int test_net_id) {

  CHECK_NOTNULL(test_nets_[test_net_id].get())->
      ShareTrainedLayersWith(net_.get());
  vector<Dtype> test_score;
  vector<int> test_score_output_id;
  vector<Blob<Dtype>*> bottom_vec;
  const shared_ptr<Net<Dtype> >& test_net = test_nets_[test_net_id];
  Dtype loss = 0;
   for (int i = 0; i < param_.test_iter(test_net_id); ++i) {
    Dtype iter_loss;
    const vector<Blob<Dtype>*>& result =
        test_net->Forward(bottom_vec, &iter_loss);
    }

 ..........
  }

所以 每一层的data和diff 是从下一层 的blobs 传入,进行设置data和diff。现在对net类和solver类 还有些不明白, 可能理解不好。

    不对地方还请您指点。

----------------------------------------------------------------------------------------

每一层的data和diff 是从下一层 的blobs 传入

-------------------------------------------

  explicit Layer(const LayerParameter& param)

    : layer_param_(param) {

      // 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));

        }

      }

}

这个函数里面,blobs_[i]表示的是可学习参数,其实就是weightbias.

由下面一句可知,blobs_[i]是从layer_param_.blobs(i)传入的:

blobs_[i]->FromProto(layer_param_.blobs(i));

我的问题是:layer_param_.blobs(i)中的datadiff是哪儿来的?

 

每一层的inputdata

----------------------------------------------------------------------------------------------------------------

blobs_[i]->FromProto(layer_param_.blobs(i)); 分析

 

一、BlobShape 在proto中定义:四个属性(num,channels,height,width)为optional类型,是可供选择的, 这个需要自己在配置文件中设置,

 

二、 而 data和diff数据,定义为 repeated float data = 5 [packed = true];repeated类型。因为每一层都需要这两个数据。所以定义为repeated 类型, 即在配置每一层之后,网络就自动设置data和diff数据。

 

至于如何网络如何读取的,从proto定义可以看出, 

即,比如data层, 输入过程 : SolverParameter  <----NetParameter <--LayerParameterBlobProto DataParameter

所以创建data层的时候,不需要设置data和diff, 但是num,channels,height,width这几个是optional 类型,需要设置。

 

message SolverParameter {

  optional NetParameter net_param = 25;

}

message NetParameter {

 

  repeated LayerParameter layer = 100;  // ID 100 so layers are printed last.

 

}

message LayerParameter {

  repeated BlobProto blobs = 7;

 

  optional DataParameter data_param = 107;

}

 

、从代码角度看

从代码里同样可以看出

代码中的数据流, 比如:layer(如具体类:datalayer)----> net.cpp ----->solver.cpp ,建立整个网络。

(1)solver.cpp

 

  if (param_.has_net_param()) {
    LOG(INFO) << "Creating training net specified in net_param.";
    net_param.CopyFrom(param_.net_param());
  }

 

(2)net.cpp init()函数中

for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {
    // Inherit phase from net if unset.
  .....
    layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param)); //获取每层param,
    layer_names_.push_back(layer_param.name());

    ...

}

(3) 在 layer.hpp 中调用 blob.cpp FromProto()函数读取(FromProto函数分析 在上个邮件

void Blob<Dtype>::FromProto(const BlobProto& proto, bool reshape) {

........
   Dtype* data_vec = mutable_cpu_data();
for (int i = 0; i < count_; ++i) {
    data_vec[i] = proto.data(i);
  }
  if (proto.diff_size() > 0) {
    Dtype* diff_vec = mutable_cpu_diff();
    for (int i = 0; i < count_; ++i) {
      diff_vec[i] = proto.diff(i);
    }
  }

.......
}

 

总之,从上边分析可以得到: 为什么参数data和diff不需要设置, 还有参数如何读入网络过程。

 


 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值