caffe net代码详细注解

caffe代码详细注解


Caffe net:init()函数代码详细注解

 

Caffe 中net的初始化函数init()是整个网络创建的关键函数。在此对此函数做详细的梳理。

 

一、代码的总体介绍

           该init()函数中主要包括以下几个函数:

1.     FilterNet(in_param,&filtered_param);

此函数的作用就是模型参数文件(*.prototxt)中的不符合规则的层去掉。例如:在caffe的examples/mnist中的lenet网络中,如果只是用于网络的前向,则需要将包含train的数据层去掉。如下:

 

[cpp] view plain copy
 
  1. layer {  
  2.   
  3.   name: "mnist"  
  4.   type: "Data"  
  5.   top: "data"  
  6.   top: "label"  
  7.   include {  
  8.     phase: TRAIN  
  9.   }  
  10.   transform_param {  
  11.     scale: 0.00390625  
  12.   }  
  13.   data_param {  
  14.     source: "examples/mnist/mnist_train_lmdb"  
  15.     batch_size: 64  
  16.     backend: LMDB  
  17.   }  
  18. }//在test计算中,此层就会调用函数FilterNet()被过滤掉  

 


2、InsertSplits(filtered_param,&param);

此函数作用是,对于底层一个输出blob对应多个上层的情况,则要在加入分裂层,形成新的网络。这么做的主要原因是多个层反传给该blob的梯度需要累加。

例如:LeNet网络中的数据层的top label blob对应两个输入层,分别是accuracy层和loss层,那么需要在数据层在插入一层。如下图:

数据层之上插入了一个新的层,label_mnist_1_split层,为该层的创建两个top blob分别为,Label_mnist_1_split_0和Label_mnist_1_split_1。

3、layers_.push_back();

该行代码是把当前层的参数转换为shared_ptr<Layer<Dtype>>,创建一个具体的层,并压入到layers_中

4、AppendBottom();

此函数为该层创建bottom blob,由于网络是堆叠而成,即:当前层的输出 bottom是前一层的输出top blob,因此此函数并没没有真正的创建blob,只是在将前一层的指针压入到了bottom_vecs_中。

5、AppendTop();

此函数为该层创建top blob,该函数真正的new的一个blob的对象。并将topblob 的指针压入到top_vecs_中

 6、layers_[layer_id]->SetUp();

  前面创建了具体的层,并为层创建了输入bottom blob 和输出top blob。改行代码这是启动该层,setup()函数的功能是为创建的blob分配数据内存空间,如有必要还需要调整该层的输入bottom blob 和输出top blob的shape。

 7、AppendParam();

 对于某些有参数的层,例如:卷基层、全连接层有weight和bias。该函数主要是修改和参数有关的变量,实际的层参数的blob在上面提到的setup()函数中已经创建。如:将层参数blob的指针压入到params_。

  

二、下面是对函数Net:init()的代码的详细注解。

 

[cpp] view plain copy
 
    1. template <typename Dtype>  
    2. void Net<Dtype>::Init(const NetParameter& in_param) {  
    3.   CHECK(Caffe::root_solver() || root_net_)  
    4.       << "root_net_ needs to be set for all non-root solvers";  
    5.   // Set phase from the state.  
    6.   phase_ = in_param.state().phase();  
    7.   // Filter layers based on their include/exclude rules and  
    8.   // the current NetState.  
    9.   NetParameter filtered_param;  
    10.     
    11.   /*将in_param中的某些不符合规则的层去掉*/  
    12.   FilterNet(in_param, &filtered_param);  
    13.   LOG_IF(INFO, Caffe::root_solver())  
    14.       << "Initializing net from parameters: " << std::endl  
    15.       << filtered_param.DebugString();  
    16.   // Create a copy of filtered_param with splits added where necessary.  
    17.   NetParameter param;  
    18.   /* 
    19.   *调用InsertSplits()函数,对于底层的一个输出blob对应多个上层的情况, 
    20.   *则要在加入分裂层,形成新的网络。 
    21.   **/   
    22.   InsertSplits(filtered_param, ¶m);  
    23. /* 
    24.  *以上部分只是根据 *.prototxt文件,确定网络name 和 blob的name的连接情况, 
    25.  *下面部分是层以及层间的blob的创建,函数ApendTop()中间blob的实例化 
    26.  *函数layer->SetUp()分配中间层blob的内存空间 
    27.  *appendparam() 
    28.  */  
    29.   // Basically, build all the layers and set up their connections.  
    30.   name_ = param.name();  
    31.   map<string, int> blob_name_to_idx;  
    32.   set<string> available_blobs;  
    33.   memory_used_ = 0;    
    34.   // For each layer, set up its input and output   
    35.   bottom_vecs_.resize(param.layer_size());//存每一层的输入(bottom)blob指针   
    36.   top_vecs_.resize(param.layer_size());//存每一层输出(top)的blob指针  
    37.   bottom_id_vecs_.resize(param.layer_size());//存每一层输入(bottom)blob的id  
    38.   param_id_vecs_.resize(param.layer_size());//存每一层参数blob的id  
    39.   top_id_vecs_.resize(param.layer_size());//存每一层输出(top)的blob的id  
    40.   bottom_need_backward_.resize(param.layer_size());//该blob是需要返回的bool值  
    41.   
    42.   //(很大的一个for循环)对每一层处理  
    43.   for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {  
    44.     // For non-root solvers, whether this layer is shared from root_net_.  
    45.     bool share_from_root = !Caffe::root_solver()  
    46.         && root_net_->layers_[layer_id]->ShareInParallel();// ???  
    47.     // Inherit phase from net if unset.  
    48.     //如果当前层没有设置phase,则将当前层phase设置为网络net 的phase  
    49.     if (!param.layer(layer_id).has_phase()) {  
    50.       param.mutable_layer(layer_id)->set_phase(phase_);  
    51.     }  
    52.     // Setup layer.  
    53.     // param.layers(i)返回的是关于第当前层的参数:  
    54.     const LayerParameter& layer_param = param.layer(layer_id);   
    55.     if (layer_param.propagate_down_size() > 0) {  
    56.       CHECK_EQ(layer_param.propagate_down_size(),  
    57.           layer_param.bottom_size())  
    58.           << "propagate_down param must be specified "  
    59.           << "either 0 or bottom_size times ";  
    60.     }  
    61.     if (share_from_root) {  
    62.       LOG(INFO) << "Sharing layer " << layer_param.name() << " from root net";  
    63.       layers_.push_back(root_net_->layers_[layer_id]);  
    64.       layers_[layer_id]->SetShared(true);  
    65.     } else {  
    66.         /* 
    67.         *把当前层的参数转换为shared_ptr<Layer<Dtype>>, 
    68.         *创建一个具体的层,并压入到layers_中  
    69.         */  
    70.       layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));  
    71.     }  
    72.     //把当前层的名字压入到layer_names_:vector<string> layer_names_  
    73.     layer_names_.push_back(layer_param.name());  
    74.     LOG_IF(INFO, Caffe::root_solver())  
    75.         << "Creating Layer " << layer_param.name();  
    76.     bool need_backward = false;  
    77.   
    78.     // Figure out this layer's input and output   
    79.     //下面开始产生当前层:分别处理bottom的blob和top的blob两个步骤   
    80.     //输入bottom blob  
    81.     for (int bottom_id = 0; bottom_id < layer_param.bottom_size();  
    82.          ++bottom_id) {  
    83.       const int blob_id = AppendBottom(param, layer_id, bottom_id,  
    84.                                        &available_blobs, &blob_name_to_idx);  
    85.       // If a blob needs backward, this layer should provide it.  
    86.       /* 
    87.         *blob_need_backward_,整个网络中,所有非参数blob,是否需要backward。 
    88.         *注意,这里所说的所有非参数blob其实指的是AppendTop函数中遍历的所有top blob, 
    89.         *并不是每一层的top+bottom,因为这一层的top就是下一层的bottom,网络是一层一层堆起来的。   
    90.         */  
    91.       need_backward |= blob_need_backward_[blob_id];  
    92.     }  
    93.     //输出top blob  
    94.     int num_top = layer_param.top_size();  
    95.     for (int top_id = 0; top_id < num_top; ++top_id) {  
    96.       AppendTop(param, layer_id, top_id, &available_blobs, &blob_name_to_idx);  
    97.       // Collect Input layer tops as Net inputs.  
    98.       if (layer_param.type() == "Input") {  
    99.         const int blob_id = blobs_.size() - 1;  
    100.         net_input_blob_indices_.push_back(blob_id);  
    101.         net_input_blobs_.push_back(blobs_[blob_id].get());  
    102.       }  
    103.     }  
    104.     // If the layer specifies that AutoTopBlobs() -> true and the LayerParameter  
    105.     // specified fewer than the required number (as specified by  
    106.     // ExactNumTopBlobs() or MinTopBlobs()), allocate them here.  
    107.     Layer<Dtype>* layer = layers_[layer_id].get();  
    108.     if (layer->AutoTopBlobs()) {  
    109.       const int needed_num_top =  
    110.           std::max(layer->MinTopBlobs(), layer->ExactNumTopBlobs());  
    111.       for (; num_top < needed_num_top; ++num_top) {  
    112.         // Add "anonymous" top blobs -- do not modify available_blobs or  
    113.         // blob_name_to_idx as we don't want these blobs to be usable as input  
    114.         // to other layers.  
    115.         AppendTop(param, layer_id, num_top, NULL, NULL);  
    116.       }  
    117.     }  
    118.     // After this layer is connected, set it up.  
    119.     if (share_from_root) {  
    120.       // Set up size of top blobs using root_net_  
    121.       const vector<Blob<Dtype>*>& base_top = root_net_->top_vecs_[layer_id];  
    122.       const vector<Blob<Dtype>*>& this_top = this->top_vecs_[layer_id];  
    123.       for (int top_id = 0; top_id < base_top.size(); ++top_id) {  
    124.         this_top[top_id]->ReshapeLike(*base_top[top_id]);  
    125.         LOG(INFO) << "Created top blob " << top_id << " (shape: "  
    126.             << this_top[top_id]->shape_string() <<  ") for shared layer "  
    127.             << layer_param.name();  
    128.       }  
    129.     } else {  
    130.      // 在 SetUp()中为 appendTop()中创建的Blob分配内存空间  
    131.       layers_[layer_id]->SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]);  
    132.     }  
    133.     LOG_IF(INFO, Caffe::root_solver())  
    134.         << "Setting up " << layer_names_[layer_id];  
    135.       
    136.     //每次循环,都会更新向量blob_loss_weights      
    137.     for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) {  
    138.         //blob_loss_weights_,每次遍历一个layer的时候,都会resize blob_loss_weights_,   
    139.         //然后调用模板类layer的loss函数返回loss_weight     
    140.       if (blob_loss_weights_.size() <= top_id_vecs_[layer_id][top_id]) {  
    141.         blob_loss_weights_.resize(top_id_vecs_[layer_id][top_id] + 1, Dtype(0));  
    142.       }  
    143.       //top_id_vecs_中存储的最基本元素是blob_id -> 每一个新的blob都会赋予其一个blob_id,  
    144.       //但是这个blob_id可能是会有重复的   
    145.       blob_loss_weights_[top_id_vecs_[layer_id][top_id]] = layer->loss(top_id);  
    146.       //loss函数返回loss_weight —> 在模板类的SetUp方法中会调用SetLossWeights来设置其私有数据成员loss_,  
    147.       //里面存储的其实是loss_weight      
    148.       LOG_IF(INFO, Caffe::root_solver())  
    149.           << "Top shape: " << top_vecs_[layer_id][top_id]->shape_string();  
    150.         
    151.       if (layer->loss(top_id)) {  
    152.         LOG_IF(INFO, Caffe::root_solver())  
    153.             << "    with loss weight " << layer->loss(top_id);  
    154.       }  
    155.       //计算所需内存   
    156.       memory_used_ += top_vecs_[layer_id][top_id]->count();  
    157.     }  
    158.     LOG_IF(INFO, Caffe::root_solver())  
    159.         << "Memory required for data: " << memory_used_ * sizeof(Dtype);  
    160.   
    161.     /* 
    162.     *以下部分是对 每层的param blob 的处理,主要是AppendParam()函数, 
    163.     *将param blob 以及blob的ID添加到 params_,param_id_vecs_ 等 
    164.     */  
    165.     const int param_size = layer_param.param_size();  
    166.     // 层内blob_的数量,即该层有几个权重参数,每个blob内有一个参数,例如;cov层和IP层都有两个参数  
    167.     const int num_param_blobs = layers_[layer_id]->blobs().size();  
    168.     //param_size是Layermeter类型对象layer_param中ParamSpec param成员的个数,   
    169.     //num_param_blobs是一个Layer中learnable parameter blob的个数,param_size <= num_param_blobs   
    170.     CHECK_LE(param_size, num_param_blobs)  
    171.         << "Too many params specified for layer " << layer_param.name();  
    172.     ParamSpec default_param_spec;  
    173.     for (int param_id = 0; param_id < num_param_blobs; ++param_id) {  
    174.       const ParamSpec* param_spec = (param_id < param_size) ? &layer_param.param(param_id) : &default_param_spec;  
    175.       const bool param_need_backward = param_spec->lr_mult() != 0;  
    176.       //由param_need_backward来决定need_backward是否为真,  
    177.       //并且,只要有一次遍历使得need_backward为真,则这个for循环结束后,need_backward也为真    
    178.       need_backward |= param_need_backward;  
    179.       layers_[layer_id]->set_param_propagate_down(param_id,  
    180.                                                   param_need_backward);  
    181.     }  
    182.     /* 
    183.     *添加parameter blob,如果当前layer没有parameter blob(num_param_blobs==0), 
    184.     *比如ReLU,那么就不进入循环,不添加parameter blob     
    185.     *AppendParam只是执行为当前layer添加parameter blob的相关工作, 
    186.     *并不会修改与backward的相关属性  
    187.     */  
    188.     for (int param_id = 0; param_id < num_param_blobs; ++param_id) {  
    189.       AppendParam(param, layer_id, param_id);  
    190.     }  
    191.     // Finally, set the backward flag  
    192.     layer_need_backward_.push_back(need_backward);  
    193.     /* 
    194.     *在上述的AppendTop函数中,在遍历当前层的每一个top blob的时候 
    195.     *都会将一个false(默认值)压入向量blob_need_backward_。 
    196.     *在下面的代码中,如果这个layer need backward,则会更新blob_need_backward_   
    197.     */  
    198.     if (need_backward) {  
    199.       for (int top_id = 0; top_id < top_id_vecs_[layer_id].size(); ++top_id) {  
    200.         blob_need_backward_[top_id_vecs_[layer_id][top_id]] = true;  
    201.       }  
    202.     }  
    203.   }  
    204. /*至此上面部分各个层被创建并启动,下面部分是按后向顺序修正backward设置  */  
    205.     
    206.   // Go through the net backwards to determine which blobs contribute to the  
    207.   // loss.  We can skip backward computation for blobs that don't contribute  
    208.   // to the loss.  
    209.   // Also checks if all bottom blobs don't need backward computation (possible  
    210.   // because the skip_propagate_down param) and so we can skip bacward  
    211.   // computation for the entire layer  
    212.   /* 
    213.   *需要注意的是,上述代码中关于backward设置的部分,是按照前向的顺序设置的, 
    214.   *而下面的代码是按后向顺序修正前向设置的结果。     
    215.   * 一个layer是否需要backward computation,主要依据两个方面: 
    216.   * (1)该layer的top blob 是否参与loss的计算; 
    217.   * (2)该layer的bottom blob 是否需要backward computation, 
    218.   *    比如Data层一般就不需要backward computation  
    219.   */  
    220.   set<string> blobs_under_loss;  
    221.   set<string> blobs_skip_backp;  
    222.   //反向,从后向前  
    223.   for (int layer_id = layers_.size() - 1; layer_id >= 0; --layer_id) {  
    224.     bool layer_contributes_loss = false;  
    225.     bool layer_skip_propagate_down = true;  
    226.     /* 
    227.     *为true,则表示当前layer的bottom blob不需要backward computation 
    228.     *即该层不需要backward computation。     
    229.     *这个局部变量所表示的意义与caffe.proto里 
    230.     *message Layerparameter的propagate_down的定义恰好相反。 
    231.     */  
    232.     for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) {  
    233.          //blob_names_整个网络中,所有非参数blob的name   
    234.       const string& blob_name = blob_names_[top_id_vecs_[layer_id][top_id]];  
    235.       if (layers_[layer_id]->loss(top_id) ||  
    236.           (blobs_under_loss.find(blob_name) != blobs_under_loss.end())) {  
    237.         layer_contributes_loss = true;  
    238.       }  
    239.       if (blobs_skip_backp.find(blob_name) == blobs_skip_backp.end()) {  
    240.         layer_skip_propagate_down = false;  
    241.       }  
    242.       if (layer_contributes_loss && !layer_skip_propagate_down)  
    243.         break;  
    244.     }  
    245.     // If this layer can skip backward computation, also all his bottom blobs  
    246.     // don't need backpropagation  
    247.     if (layer_need_backward_[layer_id] && layer_skip_propagate_down) {  
    248.       layer_need_backward_[layer_id] = false;  
    249.       for (int bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size();  
    250.                ++bottom_id) {  
    251.         //bottom_need_backward_,整个网络所有网络层的bottom blob是否需要backward    
    252.         bottom_need_backward_[layer_id][bottom_id] = false;  
    253.       }  
    254.     }  
    255.     if (!layer_contributes_loss) { layer_need_backward_[layer_id] = false; }  
    256.     if (Caffe::root_solver()) {  
    257.       if (layer_need_backward_[layer_id]) {  
    258.         LOG(INFO) << layer_names_[layer_id] << " needs backward computation.";  
    259.       } else {  
    260.         LOG(INFO) << layer_names_[layer_id]  
    261.             << " does not need backward computation.";  
    262.       }  
    263.     }  
    264.     //修正前向设置的结果    
    265.     for (int bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size();  
    266.          ++bottom_id) {  
    267.       if (layer_contributes_loss) {  
    268.         const string& blob_name =  
    269.             blob_names_[bottom_id_vecs_[layer_id][bottom_id]];  
    270.         blobs_under_loss.insert(blob_name);//为blobs_under_loss添加新元素    
    271.       } else {  
    272.         bottom_need_backward_[layer_id][bottom_id] = false;  
    273.       }  
    274.       if (!bottom_need_backward_[layer_id][bottom_id]) {  
    275.         const string& blob_name =  
    276.                    blob_names_[bottom_id_vecs_[layer_id][bottom_id]];  
    277.         blobs_skip_backp.insert(blob_name);  
    278.       }  
    279.     }  
    280.   }  
    281.   // Handle force_backward if needed.  
    282.   if (param.force_backward()) {  
    283.     for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) {  
    284.       layer_need_backward_[layer_id] = true;  
    285.       for (int bottom_id = 0;  
    286.            bottom_id < bottom_need_backward_[layer_id].size(); ++bottom_id) {  
    287.         bottom_need_backward_[layer_id][bottom_id] =  
    288.             bottom_need_backward_[layer_id][bottom_id] ||  
    289.             layers_[layer_id]->AllowForceBackward(bottom_id);  
    290.         blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] =  
    291.             blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] ||  
    292.             bottom_need_backward_[layer_id][bottom_id];  
    293.       }  
    294.       for (int param_id = 0; param_id < layers_[layer_id]->blobs().size();  
    295.            ++param_id) {  
    296.         layers_[layer_id]->set_param_propagate_down(param_id, true);  
    297.       }  
    298.     }  
    299.   }  
    300.   // In the end, all remaining blobs are considered output blobs.  
    301.   for (set<string>::iterator it = available_blobs.begin();  
    302.       it != available_blobs.end(); ++it) {  
    303.     LOG_IF(INFO, Caffe::root_solver())  
    304.         << "This network produces output " << *it;  
    305.     net_output_blobs_.push_back(blobs_[blob_name_to_idx[*it]].get());  
    306.     net_output_blob_indices_.push_back(blob_name_to_idx[*it]);  
    307.   }  
    308.   for (size_t blob_id = 0; blob_id < blob_names_.size(); ++blob_id) {  
    309.     //第一次使用向量blob_names_index_,逐一添加元素,是一个map      
    310.     blob_names_index_[blob_names_[blob_id]] = blob_id;  
    311.   }  
    312.   for (size_t layer_id = 0; layer_id < layer_names_.size(); ++layer_id) {  
    313.     //第一次使用向量layer_names_index_,逐一添加元素,是一个map      
    314.     layer_names_index_[layer_names_[layer_id]] = layer_id;  
    315.   }  
    316.   ShareWeights();  
    317.   debug_info_ = param.debug_info();  
    318.   LOG_IF(INFO, Caffe::root_solver()) << "Network initialization done.";  
    319. }  

 

posted @ 2017-09-09 16:10  菜鸡一枚  阅读(572)  评论(0编辑  收藏  举报