void Net < Dtype >::appendTop(const NetParameter& param, const int layer_id, const int top_id, set<string>* available_blobs, map<string, int>* blob_name_to_idx){ boost::shared_ptr<LayerParameter> layer_param( layer_id >= 0 ? new LayerParameter(param.layer(layer_id)) : NULL); // use (layer_id//top_id) or (-1//top_id) to get a blob name const string& blob_name = layer_param ? (top_id<layer_param->top_size() ? layer_param->top(top_id) : "(automatic)") : param.input(top_id); // in-place case (e.g: // I0721 10:38 : 16.722070 4692 net.cpp : 84] relu1 <-conv1 // I0721 10:38 : 16.722082 4692 net.cpp : 98] relu1->conv1(in-place) // check a blob whether at the same postion in both bottom and top if (blob_name_to_idx && layer_param && top_id < layer_param->bottom_size() && blob_name == layer_param->bottom(top_id)){ LOG_IF(INFO, Dragon::get_root_solver()) << layer_param->name() << "[Layer-Produce]->" << blob_name << " [Blob-Name] (in-place)"; // add into this layer's top blob using blob_name top_vecs[layer_id].push_back(blobs[(*blob_name_to_idx)[blob_name]].get()); // log the id top_id_vecs[layer_id].push_back((*blob_name_to_idx)[blob_name]); } else if (blob_name_to_idx && (*blob_name_to_idx).count(blob_name) ){ LOG(FATAL) << "Top blob:" << blob_name << " propogate from multiple sources."; } // normal top blob stuffing else{ // debug info if (Dragon::get_root_solver()){ if (layer_param) LOG(INFO) << layer_param->name() << "[Layer-Produce] ->" << blob_name << " [Blob-Name]"; // special case and only used when viewing a Net's structure // because they need not specify data source and can not train or test // virtual data input blobs do not belong to any layers // see more in insert_splits.cpp/void InsertSplits() else LOG(INFO) << "Input " << top_id << "[Blob-Code] -> " << blob_name << "[Blob - Name]"; } // allocate a null blob at first boost::shared_ptr<Blob<Dtype>> ptr_blob(new Blob<Dtype>()); // store global blob infos const int blob_id = blobs.size(); blobs.push_back(ptr_blob); blobs_name.push_back(blob_name); blobs_need_backward.push_back(false); // encode index number for a name // which also represent this top blob is binded from a bottom // check it before can know whether a top blob has multiple sources(Forbidden) if (blob_name_to_idx) (*blob_name_to_idx)[blob_name] = blob_id; // reshape for virtual input blobs solely // becaude they do not exist into a DataLayer(provide reshape/transfrom service) if (layer_id == -1){ ptr_blob->reshape(param.input_shape(top_id)); // store solely for virtual input blobs net_input_blobs.push_back(ptr_blob.get()); net_input_blob_indices.push_back(blob_id); } else{ top_vecs[layer_id].push_back(ptr_blob.get()); top_id_vecs[layer_id].push_back(blob_id); } } // a set used for listing all exsiting top blobs if (available_blobs) available_blobs->insert(blob_name); }