Caffe: Net类解析(1)--原创

Net类是Caffe中的一个核心类, 他将各个Layer和Blob组织到一起, 完成前向和反响传播计算


下面详细解读Net.cpp的代码:

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

Net<Dtype>::Net 构造函数,在训练一个网络时,涉及到多次迭代的设置和参数调优的策略,往往由更上一层的Solver来构造生成Net; 在用一个网络进行预测时,由于只需操作简单的前向计算,不需要参数调优,往往不使用Solver,直接由自己写的代码来构造Net 

//构造函数。NetParameter是在Solver构造Net时传入的网络结构参数
//本构造函数一般在训练阶段由Solver调用
//root_net是根net, 如果本net非根net, 可以从root_net中复制layer
template <typename Dtype>
Net<Dtype>::Net(const NetParameter& param, const Net* root_net)
    : root_net_(root_net) {
  Init(param);
}

//构造函数。通过prototxt文件来传入网络结构参数
//本构造函数一般在测试阶段由开发者自己写的代码来调用
//phase: 当前net是进行TEST还是TRAIN
//stage: 指明当前net中哪些layer要包含在net中(通过在prototxt为各个layer的include/exclude中指明stage/not_stage,来确定某个layer是否要包含)
//level: 指明当前net中哪些layer要包含在net中(通过在prototxt为各个layer的include/exclude中指明level,来确定某个layer是否要包含)
template <typename Dtype>
Net<Dtype>::Net(const string& param_file, Phase phase,
    const int level, const vector<string>* stages,
    const Net* root_net)
    : root_net_(root_net) {
  NetParameter param;
  ReadNetParamsFromTextFileOrDie(param_file, ¶m);
  // Set phase, stages and level
  param.mutable_state()->set_phase(phase);
  if (stages != NULL) {
    for (int i = 0; i < stages->size(); i++) {
	  //在NetState中添加stages, NetState会与NetStateRules(来自于prototxt的include/exclude)比较来确定某个layer是否保留
      param.mutable_state()->add_stage((*stages)[i]);
    }
  }
  //在NetState中添加level, NetState会与NetStateRules(来自于prototxt的include/exclude)比较来确定某个layer是否保留
  param.mutable_state()->set_level(level);
  Init(param);
}


Net<Dtype>::Init 对net中的各个layer、每个layer的输入输出blob、layer中的参数blob进行初始化 

template <typename Dtype>
void Net<Dtype>::Init(const NetParameter& in_param) {
  //检测是否有根net
  CHECK(Caffe::root_solver() || root_net_)
      << "root_net_ needs to be set for all non-root solvers";
  // Set phase from the state.
  phase_ = in_param.state().phase();
  // Filter layers based on their include/exclude rules and
  // the current NetState.
  NetParameter filtered_param;
  //使用stages/level规则对NetParameter进行过滤, 过滤后放入filtered_param
  FilterNet(in_param, &filtered_param); 
  LOG_IF(INFO, Caffe::root_solver())
      << "Initializing net from parameters: " << std::endl
      << filtered_param.DebugString();
  // Create a copy of filtered_param with splits added where necessary.
  NetParameter param;
  //对过滤后的filtered_param拷一个副本
  InsertSplits(filtered_param, ¶m);
  // Basically, build all the layers and set up their connections.
  name_ = param.name();
  map<string, int> blob_name_to_idx;
  set<string> available_blobs;
  memory_used_ = 0;
  // For each layer, set up its input and output
  //各个层输入的blob。bottom_vecs_是二维vecter, 
  //第一维是各个层,第二维是某层中的各个bottom_blob
  bottom_vecs_.resize(param.layer_size());
  //各个层输出blob
  top_vecs_.resize(param.layer_size());
  //各个层输入blob的id
  bottom_id_vecs_.resize(param.layer_size());
  //各个层内参数blob的id
  param_id_vecs_.resize(param.layer_size());
  //各个层输出blob的id
  top_id_vecs_.resize(param.layer_size());
  //各个层输入blob是否要反向传播计算
  bottom_need_backward_.resize(param.layer_size());
  for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {
    // For non-root solvers, whether this layer is shared from root_net_.
    //当前层是否要从root_solver中共享得到(如果当前是根net,值为0)
    bool share_from_root = !Caffe::root_solver()
        && root_net_->layers_[layer_id]->ShareInParallel();
    // Inherit phase from net if unset.
    if (!param.layer(layer_id).has_phase()) {
      param.mutable_layer(layer_id)->set_phase(phase_);
    }
    // Setup layer.
    const LayerParameter& layer_param = param.layer(layer_id);
    if (layer_param.propagate_down_size() > 0) {
      CHECK_EQ(layer_param.propagate_down_size(),
          layer_param.bottom_size())
          << "propagate_down param must be specified "
          << "either 0 or bottom_size times ";
    }
	
	
    //
    //创建层, 压入layers_: 可以从root_solver共享获得, 或者新建层
    //
    if (share_from_root) {
      LOG(INFO) << "Sharing layer " << layer_param.name() << " from root net";
      //root_net_->layers_中包含了所有的layer,
      layers_.push_back(root_net_->layers_[layer_id]); 
      layers_[layer_id]->SetShared(true);
    } else { 
      //对于root_solver()中的net: 里面所有layer都要新create出来
      //对于非root_solver()中的net, 只有非共享的layer才用新create
      layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));
    }
    layer_names_.push_back(layer_param.name());
    LOG_IF(INFO, Caffe::root_solver())
        << "Creating Layer " << layer_param.name();
    bool need_backward = false;

	
	
    
    /
    //1.初始化bottom blob: 将bottom_vecs_的地址与blobs_[blob_id]地址关联起来,
    //将bottom_id_vecs_与blob_id_关联起来;
    //2.对于数据输入层来说只有top,没有bottom,所以会跳过下面的for循环
    
    for (int bottom_id = 0; bottom_id < layer_param.bottom_size();
         ++bottom_id) {
      //1.net中bottom/top是交替初始化的,前一层的top是后一层的bottom,前一层top的
      //available_blobs/blob_name_to_idx参数就是后一层的bottom参数
      //2.AppendBottom将bottom_vecs_与blobs_[id]关联起来, 将bottom_id_vecs_与
      //blob_id_关联起来
      const int blob_id = AppendBottom(param, layer_id, bottom_id,
                                       &available_blobs, &blob_name_to_idx);
      // If a blob needs backward, this layer should provide it.
      //blob_need_backward_[blob_id]的值是由前一层top_blob传递过来的,同时与当
      //前层bottom_need_backward_[layer_id][bottom_id]或运算出来的结果;
      //need_backward是当前层是否要做反向传播计算的最终判断: need_backward由
      //所有blob_need_backward_和param_need_backward_组合得到
      need_backward |= blob_need_backward_[blob_id]; 
    }
    int num_top = layer_param.top_size();
	
	
	
	
    
    //初始化top blob: 将top_vecs_的地址与blobs_[blob_id]地址关联起来,
    //将top_id_vecs_与blob_id_关联起来; AppendTop还创建了新blob
    
    for (int top_id = 0; top_id < num_top; ++top_id) {
      //通过AppendTop和AppendBottom, bottom_vecs_和top_vecs_连接在了一起
      //在AppendTop中会往available_blobs添加某层的输出blob,在AppendBottom中会
      //从available_blobs中删除前一层的输出blob,所有layers遍历完后剩下的就
      //是整个net的输出blob
      AppendTop(param, layer_id, top_id, &available_blobs, &blob_name_to_idx);
      // Collect Input layer tops as Net inputs.
      if (layer_param.type() == "Input") {
	//对于整个net的输入层,每通过AppendTop新建一个top blob, blobs.size()
	//就增加1,blobs_size()是从0开始增加的,就能代表整个net输入blob的id
        const int blob_id = blobs_.size() - 1;
        net_input_blob_indices_.push_back(blob_id);
        net_input_blobs_.push_back(blobs_[blob_id].get());
      }
    }
    // If the layer specifies that AutoTopBlobs() -> true and the LayerParameter
    // specified fewer than the required number (as specified by
    // ExactNumTopBlobs() or MinTopBlobs()), allocate them here.
    Layer<Dtype>* layer = layers_[layer_id].get();
	
	
	
	
    
    //补上top blob, 使该层的top blob个数达到要求
    
    if (layer->AutoTop
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值