caffe原始碼解析:insertSplits對 top輸出到多個 Layer的情況進行分割
阿新 • • 發佈:2018-12-14
作用:對 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
理解:整個函式分為兩個部分
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]++; } } } } }