SSD的Resnet实现步骤

时间:2024-03-31 15:23:24
以resnet作为前置网络的ssd目标提取检测

1.目标
       本文的目标是将resnet结构作为前置网络,在imagenet数据集上进行预训练,随后将ssd目标提取检测网络(一部分)接在resnet前置网络之后,形成一个完整的ssd网络。
        ssd网络下载和配置参考点击打开链接

2.resnet前置网络pretrain

2.1 利用imagenet数据生成lmdb,采用create_imagenet.sh生成,内容如下:
[plain] view plain copy
  1. #!/usr/bin/env sh  
  2. # Create the imagenet lmdb inputs  
  3. # N.B. set the path to the imagenet train + val data dirs  
  4. set -e  
  5.   
  6. EXAMPLE=models/resnet  
  7. DATA=/home/jzhang/data/VOCdevkit/VOC2007  
  8. TOOLS=build/tools  
  9.   
  10. TRAIN_DATA_ROOT=/home/jzhang/data/VOCdevkit/VOC2007/JPEGImages/  
  11.   
  12.   
  13. # Set RESIZE=true to resize the images to 256x256. Leave as false if images have  
  14. # already been resized using another tool.  
  15. RESIZE=true  
  16. if $RESIZE; then  
  17.   RESIZE_HEIGHT=224  
  18.   RESIZE_WIDTH=224  
  19. else  
  20.   RESIZE_HEIGHT=0  
  21.   RESIZE_WIDTH=0  
  22. fi  
  23.   
  24. if [ ! -d "$TRAIN_DATA_ROOT" ]; then  
  25.   echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"  
  26.   echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \  
  27.        "where the ImageNet training data is stored."  
  28.   exit 1  
  29. fi  
  30.   
  31.   
  32.   
  33. echo "Creating train lmdb..."  
  34.   
  35. GLOG_logtostderr=1 $TOOLS/convert_imageset \  
  36.     --resize_height=$RESIZE_HEIGHT \  
  37.     --resize_width=$RESIZE_WIDTH \  
  38.     --shuffle \  
  39.     $TRAIN_DATA_ROOT \  
  40.     $DATA/train.txt \  
  41.     $EXAMPLE/resnet_train_lmdb  
  42.   
  43.   
  44.   
  45. echo "Done."  
生成的过程采用TRAIN_DATA_ROOT下的图片,具体的图片目录在train.txt中:
train.txt的内容大致如下:
[plain] view plain copy
  1. 000001.jpg 0  
  2. 000002.jpg 1  
  3. 000003.jpg 2  
  4. 000004.jpg 3  
  5. 000005.jpg 4  
  6. 000006.jpg 5  
  7. 000007.jpg 6  
  8. 000008.jpg 7  
  9. 000009.jpg 8  
  10. 000010.jpg 9  
前面的为TRAIN_DATA_ROOT下的图片文件名,后面的数字代表其标签label。

运行create_imagenet.sh后就会在EXAMPLE目录下生成lmdb文件夹,其中包含data.mdb和lock.mdb。这些都是caffe需要使用的数据格式。

2.2 编写solver和prototxt
      先写各层网络结构的定义res_pretrain.prototxt:
[plain] view plain copy
  1. name: "ResNet-50"  
  2.   
  3. layer {  
  4.   name: "imagenet"  
  5.   type: "Data"  
  6.   top: "data"  
  7.   top: "label"  
  8.   include {  
  9.     phase: TRAIN  
  10.   }  
  11.     
  12.   data_param {  
  13.     source: "models/resnet/resnet_train_lmdb"         //刚才产生的train的lmdb  
  14.     batch_size: 8  
  15.     backend: LMDB  
  16.   }  
  17. }  
  18. layer {  
  19.   name: "imagenet"  
  20.   type: "Data"  
  21.   top: "data"  
  22.   top: "label"  
  23.   include {  
  24.     phase: TEST  
  25.   }  
  26.     
  27.   data_param {  
  28.     source: "models/resnet/resnet_test_lmdb"          //同理可以产生的test的lmdb  
  29.     batch_size: 1  
  30.     backend: LMDB  
  31.   }  
  32. }  
  33.   
  34.   
  35. /////////////////////////////////////////////////////////////////  
  36. ////                 resnet结构                              ////  
  37. /////////////////////////////////////////////////////////////////  
  38.   
  39. layer {  
  40.     bottom: "data"  
  41.     top: "conv1"  
  42.     name: "conv1"  
  43.     type: "Convolution"  
  44.     convolution_param {  
  45.         num_output: 64  
  46.         kernel_size: 7  
  47.         pad: 3  
  48.         stride: 2  
  49.     }  
  50. }  
  51.   
  52. layer {  
  53.     bottom: "conv1"  
  54.     top: "conv1"  
  55.     name: "bn_conv1"  
  56.     type: "BatchNorm"  
  57.     batch_norm_param {  
  58.         use_global_stats: true  
  59.     }  
  60. }  
  61.   
  62. layer {  
  63.     bottom: "conv1"  
  64.     top: "conv1"  
  65.     name: "scale_conv1"  
  66.     type: "Scale"  
  67.     scale_param {  
  68.         bias_term: true  
  69.     }  
  70. }  
  71.   
  72. layer {  
  73.     bottom: "conv1"  
  74.     top: "conv1"  
  75.     name: "conv1_relu"  
  76.     type: "ReLU"  
  77. }  
  78.   
  79. layer {  
  80.     bottom: "conv1"  
  81.     top: "pool1"  
  82.     name: "pool1"  
  83.     type: "Pooling"  
  84.     pooling_param {  
  85.         kernel_size: 3  
  86.         stride: 2  
  87.         pool: MAX  
  88.     }  
  89. }  
  90.   
  91. layer {  
  92.     bottom: "pool1"  
  93.     top: "res2a_branch1"  
  94.     name: "res2a_branch1"  
  95.     type: "Convolution"  
  96.     convolution_param {  
  97.         num_output: 256  
  98.         kernel_size: 1  
  99.         pad: 0  
  100.         stride: 1  
  101.         bias_term: false  
  102.     }  
  103. }  
  104.   
  105. layer {  
  106.     bottom: "res2a_branch1"  
  107.     top: "res2a_branch1"  
  108.     name: "bn2a_branch1"  
  109.     type: "BatchNorm"  
  110.     batch_norm_param {  
  111.         use_global_stats: true  
  112.     }  
  113. }  
  114.   
  115. //...............................  
  116.   
  117. layer {  
  118.     bottom: "res5c_branch2a"  
  119.     top: "res5c_branch2a"  
  120.     name: "bn5c_branch2a"  
  121.     type: "BatchNorm"  
  122.     batch_norm_param {  
  123.         use_global_stats: true  
  124.     }  
  125. }  
  126.   
  127. layer {  
  128.     bottom: "res5c_branch2a"  
  129.     top: "res5c_branch2a"  
  130.     name: "scale5c_branch2a"  
  131.     type: "Scale"  
  132.     scale_param {  
  133.         bias_term: true  
  134.     }  
  135. }  
  136.   
  137. layer {  
  138.     bottom: "res5c_branch2a"  
  139.     top: "res5c_branch2a"  
  140.     name: "res5c_branch2a_relu"  
  141.     type: "ReLU"  
  142. }  
  143.   
  144. layer {  
  145.     bottom: "res5c_branch2a"  
  146.     top: "res5c_branch2b"  
  147.     name: "res5c_branch2b"  
  148.     type: "Convolution"  
  149.     convolution_param {  
  150.         num_output: 512  
  151.         kernel_size: 3  
  152.         pad: 1  
  153.         stride: 1  
  154.         bias_term: false  
  155.     }  
  156. }  
  157.   
  158. layer {  
  159.     bottom: "res5c_branch2b"  
  160.     top: "res5c_branch2b"  
  161.     name: "bn5c_branch2b"  
  162.     type: "BatchNorm"  
  163.     batch_norm_param {  
  164.         use_global_stats: true  
  165.     }  
  166. }  
  167.   
  168. layer {  
  169.     bottom: "res5c_branch2b"  
  170.     top: "res5c_branch2b"  
  171.     name: "scale5c_branch2b"  
  172.     type: "Scale"  
  173.     scale_param {  
  174.         bias_term: true  
  175.     }  
  176. }  
  177.   
  178. layer {  
  179.     bottom: "res5c_branch2b"  
  180.     top: "res5c_branch2b"  
  181.     name: "res5c_branch2b_relu"  
  182.     type: "ReLU"  
  183. }  
  184.   
  185. layer {  
  186.     bottom: "res5c_branch2b"  
  187.     top: "res5c_branch2c"  
  188.     name: "res5c_branch2c"  
  189.     type: "Convolution"  
  190.     convolution_param {  
  191.         num_output: 2048  
  192.         kernel_size: 1  
  193.         pad: 0  
  194.         stride: 1  
  195.         bias_term: false  
  196.     }  
  197. }  
  198.   
  199. layer {  
  200.     bottom: "res5c_branch2c"  
  201.     top: "res5c_branch2c"  
  202.     name: "bn5c_branch2c"  
  203.     type: "BatchNorm"  
  204.     batch_norm_param {  
  205.         use_global_stats: true  
  206.     }  
  207. }  
  208.   
  209. layer {  
  210.     bottom: "res5c_branch2c"  
  211.     top: "res5c_branch2c"  
  212.     name: "scale5c_branch2c"  
  213.     type: "Scale"  
  214.     scale_param {  
  215.         bias_term: true  
  216.     }  
  217. }  
  218.   
  219. layer {  
  220.     bottom: "res5b"  
  221.     bottom: "res5c_branch2c"  
  222.     top: "res5c"  
  223.     name: "res5c"  
  224.     type: "Eltwise"  
  225. }  
  226.   
  227. layer {  
  228.     bottom: "res5c"  
  229.     top: "res5c"  
  230.     name: "res5c_relu"  
  231.     type: "ReLU"  
  232. }  
  233.   
  234. layer {  
  235.     bottom: "res5c"  
  236.     top: "pool5"  
  237.     name: "pool5"  
  238.     type: "Pooling"  
  239.     pooling_param {  
  240.         kernel_size: 7  
  241.         stride: 1  
  242.         pool: AVE  
  243.     }  
  244. }  
  245.   
  246. layer {  
  247.     bottom: "pool5"  
  248.     top: "fc1000"  
  249.     name: "fc1000"  
  250.     type: "InnerProduct"  
  251.     inner_product_param {  
  252.         num_output: 1000  
  253.     }  
  254. }  
  255.   
  256.   
  257. //loss function  
  258.   
  259.   
  260.   
  261. layer {  
  262.   name: "accuracy"  
  263.   type: "Accuracy"  
  264.   bottom: "fc1000"  
  265.   bottom: "label"  
  266.   top: "accuracy"  
  267.   include {  
  268.     phase: TEST  
  269.   }  
  270. }  
  271. layer {  
  272.   name: "loss"  
  273.   type: "SoftmaxWithLoss"  
  274.   bottom: "fc1000"  
  275.   bottom: "label"  
  276.   top: "loss"  
  277. }  

写好了网络层的prototxt之后,写solver,res_pretrain_solver.prototxt内容如下:
[plain] view plain copy
  1. net: "models/resnet/res_pretrain.prototxt"             //上一步中写的网络层次结构  
  2. test_iter: 10  
  3. test_interval: 10  
  4. base_lr: 0.01                                          //基础学习率 learning-rate  
  5. lr_policy: "step"                                      //学习策略  
  6. gamma: 0.1  
  7. stepsize: 100000  
  8. display: 20  
  9. max_iter: 450000                                       //迭代次数  
  10. momentum: 0.9                                          //学习率衰减系数  
  11. weight_decay: 0.0005                                   //权重衰减系数,防止过拟合  
  12. snapshot: 1000                                         //每1000次迭代保存一次参数中间结果  
  13. snapshot_prefix: "models/resnet/resnet_train"  
  14. solver_mode: CPU  

2.3 进行pretrain训练
     在caffe目录下运行
[plain] view plain copy
  1. ./build/tools/caffe train --solver=models/resnet/res_pretrain_solver.prototxt  

     solver=之后写的是上面的prototxt地址。

     至此,在imagenet上的预训练到此为止。训练之后会生成一个caffemodel,这就是之后需要接到ssd之前网络的参数。

3.接入ssd网络

     ssd网络finetuning的流程与之前pretrain基本一致。
3.1产生lmdb
     ssd使用的lmdb与之前略有不同。
     其train.txt文件下不再是图片对应类型,因为有boundingbox的存在, 所以一个图片对应一个xml文件,如下:
[plain] view plain copy
  1. VOC2007/JPEGImages/000001.jpg VOC2007/Annotations/000001.xml  
  2. VOC2007/JPEGImages/000002.jpg VOC2007/Annotations/000002.xml  
  3. VOC2007/JPEGImages/000003.jpg VOC2007/Annotations/000003.xml  
  4. VOC2007/JPEGImages/000004.jpg VOC2007/Annotations/000004.xml  
  5. VOC2007/JPEGImages/000006.jpg VOC2007/Annotations/000006.xml  
  6. VOC2007/JPEGImages/000008.jpg VOC2007/Annotations/000008.xml  
  7. VOC2007/JPEGImages/000010.jpg VOC2007/Annotations/000010.xml  
  8. VOC2007/JPEGImages/000011.jpg VOC2007/Annotations/000011.xml  
  9. VOC2007/JPEGImages/000013.jpg VOC2007/Annotations/000013.xml  
  10. VOC2007/JPEGImages/000014.jpg VOC2007/Annotations/000014.xml  
      其create_data.sh脚本内容大致如下:
[plain] view plain copy
  1. cd $root_dir  
  2.   
  3. redo=1  
  4. data_root_dir="$HOME/data/VOCdevkit"  
  5. dataset_name="VOC0712"  
  6. mapfile="$root_dir/data/$dataset_name/labelmap_voc.prototxt"  
  7. anno_type="detection"  
  8. db="lmdb"  
  9. min_dim=0  
  10. max_dim=0  
  11. width=0  
  12. height=0  
  13.   
  14. extra_cmd="--encode-type=jpg --encoded"  
  15. if [ $redo ]  
  16. then  
  17.   extra_cmd="$extra_cmd --redo"  
  18. fi  
  19. for subset in test trainval  
  20. do  
  21.   python $root_dir/scripts/create_annoset.py --anno-type=$anno_type --label-map-file=$mapfile --min-dim=$min_dim --max-dim=$max_dim   
  22. --resize-width=$width --resize-height=$height --check-label $extra_cmd $data_root_dir $root_dir/data/$dataset_name/$subset.txt   
  23. $data_root_dir/$dataset_name/$db/$dataset_name"_"$subset"_"$db examples/$dataset_name  
  24. done  
至此可以产生新的lmdb,假定为ssd_train_lmdb用于整体网络的数据输入。

3.2 编写solver和prototxt
首先定义ssd网络层次结构ssd_finetuning.prototxt:
[cpp] view plain copy
  1. //ssd中输入层的定义非常复杂,但其中只有一些需要改动,其余的照搬就行  
  2.   
  3. layer {  
  4.   name: "data"  
  5.   type: "AnnotatedData"  
  6.   top: "data"  
  7.   top: "label"  
  8.   include {  
  9.     phase: TRAIN  
  10.   }  
  11.   transform_param {  
  12.     mirror: true  
  13.     mean_value: 104  
  14.     mean_value: 117  
  15.     mean_value: 123  
  16.     resize_param {  
  17.       prob: 1  
  18.       resize_mode: WARP  
  19.       height: 300  
  20.       width: 300  
  21.       interp_mode: LINEAR  
  22.       interp_mode: AREA  
  23.       interp_mode: NEAREST  
  24.       interp_mode: CUBIC  
  25.       interp_mode: LANCZOS4  
  26.     }  
  27.     emit_constraint {  
  28.       emit_type: CENTER  
  29.     }  
  30.   }  
  31.   data_param {  
  32.     source: "models/resnet/<span style="font-size:14px;">ssd_train_lmdb</span>"               //刚才生成的新的lmdb  
  33.     batch_size: 32  
  34.     backend: LMDB  
  35.   }  
  36.   annotated_data_param {  
  37.     batch_sampler {  
  38.       max_sample: 1  
  39.       max_trials: 1  
  40.     }  
  41.     batch_sampler {  
  42.       sampler {  
  43.         min_scale: 0.3  
  44.         max_scale: 1.0  
  45.         min_aspect_ratio: 0.5  
  46.         max_aspect_ratio: 2.0  
  47.       }  
  48.       sample_constraint {  
  49.         min_jaccard_overlap: 0.1  
  50.       }  
  51.       max_sample: 1  
  52.       max_trials: 50  
  53.     }  
  54.     batch_sampler {  
  55.       sampler {  
  56.         min_scale: 0.3  
  57.         max_scale: 1.0  
  58.         min_aspect_ratio: 0.5  
  59.         max_aspect_ratio: 2.0  
  60.       }  
  61.       sample_constraint {  
  62.         min_jaccard_overlap: 0.3  
  63.       }  
  64.       max_sample: 1  
  65.       max_trials: 50  
  66.     }  
  67.     batch_sampler {  
  68.       sampler {  
  69.         min_scale: 0.3  
  70.         max_scale: 1.0  
  71.         min_aspect_ratio: 0.5  
  72.         max_aspect_ratio: 2.0  
  73.       }  
  74.       sample_constraint {  
  75.         min_jaccard_overlap: 0.5  
  76.       }  
  77.       max_sample: 1  
  78.       max_trials: 50  
  79.     }  
  80.     batch_sampler {  
  81.       sampler {  
  82.         min_scale: 0.3  
  83.         max_scale: 1.0  
  84.         min_aspect_ratio: 0.5  
  85.         max_aspect_ratio: 2.0  
  86.       }  
  87.       sample_constraint {  
  88.         min_jaccard_overlap: 0.7  
  89.       }  
  90.       max_sample: 1  
  91.       max_trials: 50  
  92.     }  
  93.     batch_sampler {  
  94.       sampler {  
  95.         min_scale: 0.3  
  96.         max_scale: 1.0  
  97.         min_aspect_ratio: 0.5  
  98.         max_aspect_ratio: 2.0  
  99.       }  
  100.       sample_constraint {  
  101.         min_jaccard_overlap: 0.9  
  102.       }  
  103.       max_sample: 1  
  104.       max_trials: 50  
  105.     }  
  106.     batch_sampler {  
  107.       sampler {  
  108.         min_scale: 0.3  
  109.         max_scale: 1.0  
  110.         min_aspect_ratio: 0.5  
  111.         max_aspect_ratio: 2.0  
  112.       }  
  113.       sample_constraint {  
  114.         max_jaccard_overlap: 1.0  
  115.       }  
  116.       max_sample: 1  
  117.       max_trials: 50  
  118.     }  
  119.     label_map_file: "data/VOC0712/labelmap_voc.prototxt"  
  120.   }  
  121. }  
  122.   
  123. //resnet结构  
  124.   
  125. layer {  
  126. bottom: "data"  
  127. top: "conv1"  
  128. name: "conv1"  
  129. type: "Convolution"  
  130. convolution_param {  
  131. num_output: 64  
  132. kernel_size: 7  
  133. pad: 3  
  134. stride: 2  
  135. }  
  136. }  
  137.   
  138.   
  139. layer {  
  140. bottom: "conv1"  
  141. top: "conv1"  
  142. name: "bn_conv1"  
  143. type: "BatchNorm"  
  144. batch_norm_param {  
  145. use_global_stats: true  
  146. }  
  147. }  
  148. layer {  
  149.     bottom: "data"  
  150.     top: "conv1"  
  151.     name: "conv1"  
  152.     type: "Convolution"  
  153.     convolution_param {  
  154.         num_output: 64  
  155.         kernel_size: 7  
  156.         pad: 3  
  157.         stride: 2  
  158.     }  
  159. }  
  160.   
  161. //省略很多resnet层  
  162.   
  163. layer {  
  164.   bottom: "res5c"  
  165.   top: "res5c"  
  166.   name: "res5c_relu"  
  167.   type: "ReLU"  
  168. }  
  169.   
  170.   
  171. layer {  
  172.   bottom: "res5c"  
  173.   top: "pool5"  
  174.   name: "pool5"  
  175.   type: "Pooling"  
  176.   pooling_param {  
  177.     kernel_size: 7  
  178.     stride: 1  
  179.     pool: AVE  
  180.     }  
  181. }  
[cpp] view plain copy
  1. //至此resnet主体结构完成,随后接上ssd的结构  
  2.   
  3. //用pool5作为bottom分别产生mbox_loc/mbox_conf/mbox_priorbox  
  4.   
  5. layer {  
  6.   name: "pool5_mbox_loc"  
  7.   type: "Convolution"  
  8.   bottom: "pool5"                               //选取pool5作为bottom,产生mbox_loc  
  9.   top: "pool5_mbox_loc"  
  10.   param {  
  11.     lr_mult: 1  
  12.     decay_mult: 1  
  13.   }  
  14.   param {  
  15.     lr_mult: 2  
  16.     decay_mult: 0  
  17.   }  
  18.   convolution_param {  
  19.     num_output: 24  
  20.     pad: 1  
  21.     kernel_size: 3  
  22.     stride: 1  
  23.     weight_filler {  
  24.       type: "xavier"  
  25.     }  
  26.     bias_filler {  
  27.       type: "constant"  
  28.       value: 0  
  29.     }  
  30.   }  
  31. }  
  32. layer {  
  33.   name: "pool5_mbox_loc_perm"                     //将上一层产生的mbox_loc重新排序  
  34.   type: "Permute"  
  35.   bottom: "pool5_mbox_loc"  
  36.   top: "pool5_mbox_loc_perm"  
  37.   permute_param {  
  38.     order: 0  
  39.     order: 2  
  40.     order: 3  
  41.     order: 1  
  42.   }  
  43. }  
  44. layer {  
  45.   name: "pool5_mbox_loc_flat"                    //将上一层展平(例如7*7的展平成1*49,方便之后的拼接)  
  46.   type: "Flatten"  
  47.   bottom: "pool5_mbox_loc_perm"  
  48.   top: "pool5_mbox_loc_flat"  
  49.   flatten_param {  
  50.     axis: 1  
  51.   }  
  52. }  
  53. layer {  
  54.   name: "pool5_mbox_conf"  
  55.   type: "Convolution"  
  56.   bottom: "pool5"                               //选取pool5作为bottom,产生mbox_conf(之后的排序展平同理)  
  57.   top: "pool5_mbox_conf"  
  58.  param {  
  59.     lr_mult: 1  
  60.     decay_mult: 1  
  61.   }  
  62.   param {  
  63.     lr_mult: 2  
  64.     decay_mult: 0  
  65.   }  
  66.   convolution_param {  
  67.     num_output: 126  
  68.     pad: 1  
  69.     kernel_size: 3  
  70.     stride: 1  
  71.     weight_filler {  
  72.       type: "xavier"  
  73.     }  
  74.     bias_filler {  
  75.       type: "constant"  
  76.       value: 0  
  77.     }  
  78.   }  
  79. }  
  80. layer {  
  81.   name: "pool5_mbox_conf_perm"  
  82.   type: "Permute"  
  83.   bottom: "pool5_mbox_conf"  
  84.   top: "pool5_mbox_conf_perm"  
  85.   permute_param {  
  86.     order: 0  
  87.     order: 2  
  88.     order: 3  
  89.     order: 1  
  90.   }  
  91. }  
  92. layer {  
  93.   name: "pool5_mbox_conf_flat"  
  94.   type: "Flatten"  
  95.   bottom: "pool5_mbox_conf_perm"  
  96.   top: "pool5_mbox_conf_flat"  
  97.   flatten_param {  
  98.     axis: 1  
  99.   }  
  100. }  
  101. layer {  
  102.   name: "pool5_mbox_priorbox"  
  103.   type: "PriorBox"  
  104.   bottom: "pool5"                                //选取pool5作为bottom,产生mbox_priorbox(之后排序展平)  
  105.   bottom: "data"  
  106.   top: "pool5_mbox_priorbox"  
  107.   prior_box_param {  
  108.     min_size: 276.0  
  109.     max_size: 330.0  
  110.     aspect_ratio: 2  
  111.     aspect_ratio: 3  
  112.     flip: true  
  113.     clip: true  
  114.     variance: 0.1  
  115.     variance: 0.1  
  116.     variance: 0.2  
  117.     variance: 0.2  
  118.   }  
  119. }  
  120.   
  121. //同理用res5c作为bottom分别产生mbox_loc/mbox_conf/mbox_priorbox  
  122.   
  123. layer {  
  124.   name: "res5c_mbox_loc"  
  125.   type: "Convolution"  
  126.   bottom: "res5c"  
  127.   top: "res5c_mbox_loc"                                           
  128.   param {  
  129.     lr_mult: 1  
  130.     decay_mult: 1  
  131.   }  
  132.   param {  
  133.     lr_mult: 2  
  134.     decay_mult: 0  
  135.   }  
  136.   convolution_param {  
  137.     num_output: 24  
  138.     pad: 1  
  139.     kernel_size: 3  
  140.     stride: 1  
  141.     weight_filler {  
  142.       type: "xavier"  
  143.     }  
  144.     bias_filler {  
  145.       type: "constant"  
  146.       value: 0  
  147.     }  
  148.   }  
  149. }  
  150. layer {  
  151.   name: "res5c_mbox_loc_perm"  
  152.   type: "Permute"  
  153.   bottom: "res5c_mbox_loc"  
  154.   top: "res5c_mbox_loc_perm"  
  155.   permute_param {  
  156.     order: 0  
  157.     order: 2  
  158.     order: 3  
  159.     order: 1  
  160.   }  
  161. }  
  162. layer {  
  163.   name: "res5c_mbox_loc_flat"  
  164.   type: "Flatten"  
  165.   bottom: "res5c_mbox_loc_perm"  
  166.   top: "res5c_mbox_loc_flat"  
  167.   flatten_param {  
  168.     axis: 1  
  169.   }  
  170. }  
  171. layer {  
  172.   name: "res5c_mbox_conf"  
  173.   type: "Convolution"  
  174.   bottom: "res5c"  
  175.   top: "res5c_mbox_conf"  
  176.   param {  
  177.     lr_mult: 1  
  178.     decay_mult: 1  
  179.   }  
  180.   param {  
  181.     lr_mult: 2  
  182.     decay_mult: 0  
  183.   }  
  184.   convolution_param {  
  185.     num_output: 126  
  186.     pad: 1  
  187.     kernel_size: 3  
  188.     stride: 1  
  189.     weight_filler {  
  190.       type: "xavier"  
  191.     }  
  192.     bias_filler {  
  193.       type: "constant"  
  194.       value: 0  
  195.     }  
  196.   }  
  197. }  
  198. layer {  
  199.   name: "res5c_mbox_conf_perm"  
  200.   type: "Permute"  
  201.   bottom: "res5c_mbox_conf"  
  202.   top: "res5c_mbox_conf_perm"  
  203.   permute_param {  
  204.     order: 0  
  205.     order: 2  
  206.     order: 3  
  207.     order: 1  
  208.   }  
  209. }  
  210. layer {  
  211.   name: "res5c_mbox_conf_flat"  
  212.   type: "Flatten"  
  213.   bottom: "res5c_mbox_conf_perm"  
  214.   top: "res5c_mbox_conf_flat"  
  215.   flatten_param {  
  216.     axis: 1  
  217.   }  
  218. }  
  219. layer {  
  220.   name: "res5c_mbox_priorbox"  
  221.   type: "PriorBox"  
  222.   bottom: "res5c"  
  223.   bottom: "data"  
  224.   top: "res5c_mbox_priorbox"  
  225.   prior_box_param {  
  226.     min_size: 276.0  
  227.     max_size: 330.0  
  228.     aspect_ratio: 2  
  229.     aspect_ratio: 3  
  230.     flip: true  
  231.     clip: true  
  232.     variance: 0.1  
  233.     variance: 0.1  
  234.     variance: 0.2  
  235.     variance: 0.2  
  236.   }  
  237. }  
  238.   
  239.   
  240. //Concat层将刚才的res5c和pool5产生的mbox_loc/mbox_conf/mbox_priorbox拼接起来形成一个层  
  241.   
  242. layer {  
  243.   name: "mbox_loc"  
  244.   type: "Concat"  
  245.   bottom: "res5c_mbox_loc_flat"  
  246.   bottom: "pool5_mbox_loc_flat"  
  247.   top: "mbox_loc"  
  248.   concat_param {  
  249.     axis: 1  
  250.   }  
  251. }  
  252. layer {  
  253.   name: "mbox_conf"  
  254.   type: "Concat"  
  255.   bottom: "res5c_mbox_conf_flat"  
  256.   bottom: "pool5_mbox_conf_flat"  
  257.   top: "mbox_conf"  
  258.   concat_param {  
  259.     axis: 1  
  260.   }  
  261. }  
  262. layer {  
  263.   name: "mbox_priorbox"  
  264.   type: "Concat"  
  265.   bottom: "res5c_mbox_priorbox"  
  266.   bottom: "pool5_mbox_priorbox"  
  267.   top: "mbox_priorbox"  
  268.   concat_param {  
  269.     axis: 2  
  270.   }  
  271. }  
  272.   
  273. <span style="color:#ff0000;">//mbox_loc,mbox_conf,mbox_priorbox一起做的loss-function</span>  
  274.   
  275. layer {  
  276.   name: "mbox_loss"  
  277.   type: "MultiBoxLoss"  
  278.   bottom: "mbox_loc"  
  279.   bottom: "mbox_conf"  
  280.   bottom: "mbox_priorbox"  
  281.   bottom: "label"  
  282.   top: "mbox_loss"  
  283.   include {  
  284.     phase: TRAIN  
  285.   }  
  286.   propagate_down: true  
  287.   propagate_down: true  
  288.   propagate_down: false  
  289.   propagate_down: false  
  290.   loss_param {  
  291.     normalization: VALID  
  292.   }  
  293.   multibox_loss_param {  
  294.     loc_loss_type: SMOOTH_L1  
  295.     conf_loss_type: SOFTMAX  
  296.     loc_weight: 1.0  
  297.     num_classes: 21  
  298.     share_location: true  
  299.     match_type: PER_PREDICTION  
  300.     overlap_threshold: 0.5  
  301.     use_prior_for_matching: true  
  302.     background_label_id: 0  
  303.     use_difficult_gt: true  
  304.     do_neg_mining: true  
  305.     neg_pos_ratio: 3.0  
  306.     neg_overlap: 0.5  
  307.     code_type: CENTER_SIZE  
  308.   }  
  309. }  







SSD的Resnet实现步骤
ssd中,mbox_loc层产生x,y,w,h四个值,mbox_conf对于每一个分类都有一个值,如果有20个分类,那就会产生20个值。
对于刚才的prototxt中,res5c层的尺寸为7*7,每一个像素会产生6个boundingbox,pool5层的尺寸为1*1,每一个像素会产生6个boundingbox。总共是7*7*6+1*1*6个候选的boundingbox。
如果需要增加候选的数量,那么就和pool5一样,在resnet中任意选取中间层randomlayer,在这些层之后加入randomlayer_mbox_loc/randomlayer_mbox_conf/randomlayer_mbox_priorbox,最终将这些层都展平并拼接在一起
至此,ssd的整体网络结构prototxt已经编写完成。
对于solver,与之前没有什么区别,ssd_finetuning_solver:
[plain] view plain copy
  1. net: "models/resnet/ssd_finetuning.prototxt"  
  2. base_lr: 0.01  
  3. lr_policy: "step"  
  4. gamma: 0.1  
  5. stepsize: 100000  
  6. display: 20  
  7. max_iter: 450000  
  8. momentum: 0.9  
  9. weight_decay: 0.0005  
  10. snapshot: 10000  
  11. snapshot_prefix: "models/resnet/resnet_train"  
  12. solver_mode: CPU  

3.3 训练网络
    在caffe目录下运行:
[plain] view plain copy
  1. ./build/tools/caffe train --solver=models/resnet/ssd_finetuning_solver.prototxt -weights models/resnet/res_pretrain.caffemodel  
    
    solver=之后加solver地址, weights参数后加预训练pretrain中res_pretrain.caffemodel的参数。

至此,就将pretrain好的resnet网络接入了ssd前面。