caffe源碼解析:insertSplits對 top輸出到多個 Layer的情況進行分割

作用:對 top輸出到多個 Layer的情況進行分割,建立完整的網絡結構

重要的參數說明舉例:

  • layer_idx_to_layer_name[i]
    記錄各層的名稱,如 [0x00000000] "input"
  • blob_name_to_last_top_idx[“conv1”]=(1,0)
    這個例子相當於說”conv1” 這層是第1層的第0個top,
  • bottom_idx_to_source_top_idx[bottom_idx=(2,0)] = (1,0); 
    相當於說:第2層,第0個bottom,對應着第1層,第0個top
    即: [(0x00000001, 0x00000000)] (0x00000000, 0x00000000)
  • top_idx_to_bottom_count[(1,0)]=2
    表示第1個layer的第0個top有2個top(blob?),要分叉,程序會對此建立新的分叉層

 

理解:整個函數分爲兩個部分

1. 遍歷整個網絡,記錄每一個Layer的top的使用情況,記錄結構放在 top_idx_to_bottom_count中。

2. 遍歷整個網絡,對 top_idx_to_bottom_count > 1 的情況進行處理: 分兩步走

第一步. 首先是對有多個top層的Layer進行分割,主要的做法是在該層的後面新建一個Layer ,這個新的Layer的會按照 top_idx_to_bottom_count 的個數和約定的分割名稱(SplitBlobName)去新建top,參考void ConfigureSplitLayer…

第二步,是對使用同一個top的後續層的bottom的blob進行改名(使用與上一步相同的命名規則)。

下面是源碼

void InsertSplits(const NetParameter& param, NetParameter* param_split) {
  // Initialize by copying from the input NetParameter.
  param_split->CopyFrom(param);
  param_split->clear_layer();
  map<string, pair<int, int> > blob_name_to_last_top_idx;
  map<pair<int, int>, pair<int, int> > bottom_idx_to_source_top_idx;
  map<pair<int, int>, int> top_idx_to_bottom_count;
  map<pair<int, int>, float> top_idx_to_loss_weight;
  map<pair<int, int>, int> top_idx_to_bottom_split_idx;
  map<int, string> layer_idx_to_layer_name; // 每層網絡的名稱
  for (int i = 0; i < param.layer_size(); ++i) {
    const LayerParameter& layer_param = param.layer(i);
    layer_idx_to_layer_name[i] = layer_param.name();
    for (int j = 0; j < layer_param.bottom_size(); ++j) {
      const string& blob_name = layer_param.bottom(j);
      if (blob_name_to_last_top_idx.find(blob_name) ==
          blob_name_to_last_top_idx.end()) {
        LOG(FATAL) << "Unknown bottom blob '" << blob_name << "' (layer '"
                   << layer_param.name() << "', bottom index " << j << ")";
      }
      const pair<int, int>& bottom_idx = make_pair(i, j);
      const pair<int, int>& top_idx = blob_name_to_last_top_idx[blob_name];
      bottom_idx_to_source_top_idx[bottom_idx] = top_idx;
      ++top_idx_to_bottom_count[top_idx];
    }
    for (int j = 0; j < layer_param.top_size(); ++j) {
      const string& blob_name = layer_param.top(j);
      blob_name_to_last_top_idx[blob_name] = make_pair(i, j);
    }
    // A use of a top blob as a loss should be handled similarly to the use of
    // a top blob as a bottom blob to another layer.
    const int last_loss =
        std::min(layer_param.loss_weight_size(), layer_param.top_size());
    for (int j = 0; j < last_loss; ++j) {
      const string& blob_name = layer_param.top(j);
      const pair<int, int>& top_idx = blob_name_to_last_top_idx[blob_name];
      top_idx_to_loss_weight[top_idx] = layer_param.loss_weight(j);
      if (top_idx_to_loss_weight[top_idx]) {
        ++top_idx_to_bottom_count[top_idx];
      }
    }
  }
  for (int i = 0; i < param.layer_size(); ++i) {
    LayerParameter* layer_param = param_split->add_layer();
    layer_param->CopyFrom(param.layer(i));
    // Replace any shared bottom blobs with split layer outputs.
    for (int j = 0; j < layer_param->bottom_size(); ++j) {
      const pair<int, int>& top_idx =
          bottom_idx_to_source_top_idx[make_pair(i, j)];
      //表示第i層的第j個bottom, 是第top_idx0層的第top_idx1個top, 
      //   有split_count個bottom
      const int split_count = top_idx_to_bottom_count[top_idx];
      if (split_count > 1) {
        const string& layer_name = layer_idx_to_layer_name[top_idx.first];
        const string& blob_name = layer_param→bottom(j);
        // 只是改個名稱,這個名稱由 SplitBlobName創建
        layer_param->set_bottom(j, SplitBlobName(layer_name,
            blob_name, top_idx.second, top_idx_to_bottom_split_idx[top_idx]++));
      }
    }
    // Create split layer for any top blobs used by other layer as bottom
    // blobs more than once.
    for (int j = 0; j < layer_param->top_size(); ++j) {
      const pair<int, int>& top_idx = make_pair(i, j);
      //表示第i層的第j個top有split_count個blob
      const int split_count = top_idx_to_bottom_count[top_idx];
      if (split_count > 1) {
         // 如果要分叉(對應多個top)
        const string& layer_name = layer_idx_to_layer_name[i]; //第i層的名稱
        const string& blob_name = layer_param->top(j);  // 第j個top的blob名稱
        LayerParameter* split_layer_param = param_split->add_layer(); // 新建一層
        const float loss_weight = top_idx_to_loss_weight[top_idx];
        // 第i層的第j個top有的loss_weight
        ConfigureSplitLayer(layer_name, blob_name, j, split_count,
            loss_weight, split_layer_param);
        if (loss_weight) {
          layer_param->clear_loss_weight();
          top_idx_to_bottom_split_idx[top_idx]++;
        }
      }
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章