|
| 1 | +# Model Zoo - ImageNet # |
| 2 | + |
| 3 | +[ImageNet](http://www.image-net.org/) 是通用物体分类领域一个众所周知的数据库。本教程提供了一个用于ImageNet上的卷积分类网络模型。 |
| 4 | + |
| 5 | +## ResNet 介绍 |
| 6 | + |
| 7 | +论文 [Deep Residual Learning for Image Recognition](http://arxiv.org/abs/1512.03385) 中提出的ResNet网络结构在2015年ImageNet大规模视觉识别竞赛(ILSVRC 2015)的分类任务中赢得了第一名。他们提出残差学习的框架来简化网络的训练,所构建网络结构的的深度比之前使用的网络有大幅度的提高。下图展示的是基于残差的连接方式。左图构造网络模块的方式被用于34层的网络中,而右图的瓶颈连接模块用于50层,101层和152层的网络结构中。 |
| 8 | + |
| 9 | +<center></center> |
| 10 | +<center>图 1. ResNet 网络模块</center> |
| 11 | + |
| 12 | +本教程中我们给出了三个ResNet模型,这些模型都是由原作者提供的模型<https://github.com/KaimingHe/deep-residual-networks>转换过来的。我们使用PaddlePaddle在ILSVRC的验证集共50,000幅图像上测试了模型的分类错误率,其中输入图像的颜色通道顺序为**BGR**,保持宽高比缩放到短边为256,只截取中心方形的图像区域。分类错误率和模型大小由下表给出。 |
| 13 | +<center> |
| 14 | +<table border="2" cellspacing="0" cellpadding="6" rules="all" frame="border"> |
| 15 | +<colgroup> |
| 16 | +<col class="left" /> |
| 17 | +<col class="left" /> |
| 18 | +<col class="left" /> |
| 19 | +</colgroup> |
| 20 | +<thead> |
| 21 | +<tr> |
| 22 | +<th scope="col" class="left">ResNet</th> |
| 23 | +<th scope="col" class="left">Top-1</th> |
| 24 | +<th scope="col" class="left">Model Size</th> |
| 25 | +</tr> |
| 26 | +</thead> |
| 27 | + |
| 28 | +<tbody> |
| 29 | +<tr> |
| 30 | +<td class="left">ResNet-50</td> |
| 31 | +<td class="left">24.9%</td> |
| 32 | +<td class="left">99M</td> |
| 33 | +</tr> |
| 34 | +<tr> |
| 35 | +<td class="left">ResNet-101</td> |
| 36 | +<td class="left">23.7%</td> |
| 37 | +<td class="left">173M</td> |
| 38 | +</tr> |
| 39 | +<tr> |
| 40 | +<td class="left">ResNet-152</td> |
| 41 | +<td class="left">23.2%</td> |
| 42 | +<td class="left">234M</td> |
| 43 | +</tr> |
| 44 | +</tbody> |
| 45 | + |
| 46 | +</table></center> |
| 47 | +<br> |
| 48 | + |
| 49 | +## ResNet 模型 |
| 50 | + |
| 51 | +50层,101层和152层的网络配置文件可参照```demo/model_zoo/resnet/resnet.py```。你也可以通过在命令行参数中增加一个参数如```--config_args=layer_num=50```来指定网络层的数目。 |
| 52 | + |
| 53 | +### 网络可视化 |
| 54 | + |
| 55 | +你可以通过执行下面的命令来得到ResNet网络的结构可视化图。该脚本会生成一个dot文件,然后可以转换为图片。需要安装graphviz来转换dot文件为图片。 |
| 56 | + |
| 57 | +``` |
| 58 | +cd demo/model_zoo/resnet |
| 59 | +./net_diagram.sh |
| 60 | +``` |
| 61 | + |
| 62 | +### 模型下载 |
| 63 | + |
| 64 | +``` |
| 65 | +cd demo/model_zoo/resnet |
| 66 | +./get_model.sh |
| 67 | +``` |
| 68 | +你可以执行上述命令来下载所有的模型和均值文件,如果下载成功,这些文件将会被保存在```demo/model_zoo/resnet/model```路径下。 |
| 69 | + |
| 70 | +``` |
| 71 | +mean_meta_224 resnet_101 resnet_152 resnet_50 |
| 72 | +``` |
| 73 | + * resnet_50: 50层网络模型。 |
| 74 | + * resnet_101: 101层网络模型。 |
| 75 | + * resnet_152: 152层网络模型。 |
| 76 | + * mean\_meta\_224: 均值图像文件,图像大小为3 x 224 x 224,颜色通道顺序为**BGR**。你也可以使用这三个值: 103.939, 116.779, 123.68。 |
| 77 | + |
| 78 | +### 参数信息 |
| 79 | + |
| 80 | +* **卷积层权重** |
| 81 | + |
| 82 | + 由于每个卷积层后面连接的是batch normalization层,因此该层中没有偏置(bias)参数,并且只有一个权重。 |
| 83 | + 形状: `(Co, ky, kx, Ci)` |
| 84 | + * Co: 输出特征图的通道数目 |
| 85 | + * ky: 滤波器核在垂直方向上的尺寸 |
| 86 | + * kx: 滤波器核在水平方向上的尺寸 |
| 87 | + * Ci: 输入特征图的通道数目 |
| 88 | + |
| 89 | + 二维矩阵: (Co * ky * kx, Ci), 行优先次序存储。 |
| 90 | + |
| 91 | +* **全连接层权重** |
| 92 | + |
| 93 | + 二维矩阵: (输入层尺寸, 本层尺寸), 行优先次序存储。 |
| 94 | + |
| 95 | +* **[Batch Normalization](<http://arxiv.org/abs/1502.03167>) 层权重** |
| 96 | + |
| 97 | +本层有四个参数,实际上只有.w0和.wbias是需要学习的参数,另外两个分别是滑动均值和方差。在测试阶段它们将会被加载到模型中。下表展示了batch normalization层的参数。 |
| 98 | +<center> |
| 99 | +<table border="2" cellspacing="0" cellpadding="6" rules="all" frame="border"> |
| 100 | +<colgroup> |
| 101 | +<col class="left" /> |
| 102 | +<col class="left" /> |
| 103 | +<col class="left" /> |
| 104 | +</colgroup> |
| 105 | +<thead> |
| 106 | +<tr> |
| 107 | +<th scope="col" class="left">参数名</th> |
| 108 | +<th scope="col" class="left">尺寸</th> |
| 109 | +<th scope="col" class="left">含义</th> |
| 110 | +</tr> |
| 111 | +</thead> |
| 112 | + |
| 113 | +<tbody> |
| 114 | +<tr> |
| 115 | +<td class="left">_res2_1_branch1_bn.w0</td> |
| 116 | +<td class="left">256</td> |
| 117 | +<td class="left">gamma, 缩放参数</td> |
| 118 | +</tr> |
| 119 | +<tr> |
| 120 | +<td class="left">_res2_1_branch1_bn.w1</td> |
| 121 | +<td class="left">256</td> |
| 122 | +<td class="left">特征图均值</td> |
| 123 | +</tr> |
| 124 | +<tr> |
| 125 | +<td class="left">_res2_1_branch1_bn.w2</td> |
| 126 | +<td class="left">256</td> |
| 127 | +<td class="left">特征图方差</td> |
| 128 | +</tr> |
| 129 | +<tr> |
| 130 | +<td class="left">_res2_1_branch1_bn.wbias</td> |
| 131 | +<td class="left">256</td> |
| 132 | +<td class="left">beta, 偏置参数</td> |
| 133 | +</tr> |
| 134 | +</tbody> |
| 135 | + |
| 136 | +</table></center> |
| 137 | +<br> |
| 138 | + |
| 139 | +### 参数读取 |
| 140 | + |
| 141 | +使用者可以使用下面的Python脚本来读取参数值: |
| 142 | + |
| 143 | +``` |
| 144 | +import sys |
| 145 | +import numpy as np |
| 146 | +
|
| 147 | +def load(file_name): |
| 148 | + with open(file_name, 'rb') as f: |
| 149 | + f.read(16) # skip header for float type. |
| 150 | + return np.fromfile(f, dtype=np.float32) |
| 151 | +
|
| 152 | +if __name__=='__main__': |
| 153 | + weight = load(sys.argv[1]) |
| 154 | +``` |
| 155 | + |
| 156 | +或者直接使用下面的shell命令: |
| 157 | + |
| 158 | +``` |
| 159 | +od -j 16 -f _res2_1_branch1_bn.w0 |
| 160 | +``` |
| 161 | + |
| 162 | +## 特征提取 |
| 163 | + |
| 164 | +我们提供了C++和Python接口来提取特征。下面的例子使用了`demo/model_zoo/resnet/example`中的数据,详细地展示了整个特征提取的过程。 |
| 165 | + |
| 166 | +### C++接口 |
| 167 | + |
| 168 | +首先,在配置文件中的`define_py_data_sources2`里指定图像数据列表,具体请参照示例`demo/model_zoo/resnet/resnet.py`。 |
| 169 | + |
| 170 | +``` |
| 171 | + train_list = 'train.list' if not is_test else None |
| 172 | + # mean.meta is mean file of ImageNet dataset. |
| 173 | + # mean.meta size : 3 x 224 x 224. |
| 174 | + # If you use three mean value, set like: |
| 175 | + # "mean_value:103.939,116.779,123.68;" |
| 176 | + args={ |
| 177 | + 'mean_meta': "model/mean_meta_224/mean.meta", |
| 178 | + 'image_size': 224, 'crop_size': 224, |
| 179 | + 'color': True,'swap_channel:': [2, 1, 0]} |
| 180 | + define_py_data_sources2(train_list, |
| 181 | + 'example/test.list', |
| 182 | + module="example.image_list_provider", |
| 183 | + obj="processData", |
| 184 | + args=args) |
| 185 | +``` |
| 186 | + |
| 187 | +第二步,在`resnet.py`文件中指定要提取特征的网络层的名字。例如, |
| 188 | + |
| 189 | +``` |
| 190 | +Outputs("res5_3_branch2c_conv", "res5_3_branch2c_bn") |
| 191 | +``` |
| 192 | + |
| 193 | +第三步,在`extract_fea_c++.sh`文件中指定模型路径和输出的目录,然后执行下面的命令。 |
| 194 | + |
| 195 | +``` |
| 196 | +cd demo/model_zoo/resnet |
| 197 | +./extract_fea_c++.sh |
| 198 | +``` |
| 199 | + |
| 200 | +如果执行成功,特征将会存到`fea_output/rank-00000`文件中,如下所示。同时你可以使用`load_feature.py`文件中的`load_feature_c`接口来加载该文件。 |
| 201 | + |
| 202 | +``` |
| 203 | +-0.115318 -0.108358 ... -0.087884;-1.27664 ... -1.11516 -2.59123; |
| 204 | +-0.126383 -0.116248 ... -0.00534909;-1.42593 ... -1.04501 -1.40769; |
| 205 | +``` |
| 206 | + |
| 207 | +* 每行存储的是一个样本的特征。其中,第一行存的是图像`example/dog.jpg`的特征,第二行存的是图像`example/cat.jpg`的特征。 |
| 208 | +* 不同层的特征由分号`;`隔开,并且它们的顺序与`Outputs()`中指定的层顺序一致。这里,左边是`res5_3_branch2c_conv`层的特征,右边是`res5_3_branch2c_bn`层特征。 |
| 209 | + |
| 210 | +### Python接口 |
| 211 | + |
| 212 | +示例`demo/model_zoo/resnet/classify.py`中展示了如何使用Python来提取特征。下面的例子同样使用了`./example/test.list`中的数据。执行的命令如下: |
| 213 | + |
| 214 | +``` |
| 215 | +cd demo/model_zoo/resnet |
| 216 | +./extract_fea_py.sh |
| 217 | +``` |
| 218 | + |
| 219 | +extract_fea_py.sh: |
| 220 | + |
| 221 | +``` |
| 222 | +python classify.py \ |
| 223 | + --job=extract \ |
| 224 | + --conf=resnet.py\ |
| 225 | + --use_gpu=1 \ |
| 226 | + --mean=model/mean_meta_224/mean.meta \ |
| 227 | + --model=model/resnet_50 \ |
| 228 | + --data=./example/test.list \ |
| 229 | + --output_layer="res5_3_branch2c_conv,res5_3_branch2c_bn" \ |
| 230 | + --output_dir=features |
| 231 | +
|
| 232 | +``` |
| 233 | +* \--job=extract: 指定工作模式来提取特征。 |
| 234 | +* \--conf=resnet.py: 网络配置文件。 |
| 235 | +* \--use_gpu=1: 指定是否使用GPU。 |
| 236 | +* \--model=model/resnet_50: 模型路径。 |
| 237 | +* \--data=./example/test.list: 数据列表。 |
| 238 | +* \--output_layer="xxx,xxx": 指定提取特征的层。 |
| 239 | +* \--output_dir=features: 输出目录。 |
| 240 | + |
| 241 | +如果运行成功,你将会看到特征存储在`features/batch_0`文件中,该文件是由cPickle产生的。你可以使用`load_feature.py`中的`load_feature_py`接口来打开该文件,它将返回如下的字典: |
| 242 | + |
| 243 | +``` |
| 244 | +{ |
| 245 | +'cat.jpg': {'res5_3_branch2c_conv': array([[-0.12638293, -0.116248 , -0.11883899, ..., -0.00895038, 0.01994277, -0.00534909]], dtype=float32), 'res5_3_branch2c_bn': array([[-1.42593431, -1.28918779, -1.32414699, ..., -1.45933616, -1.04501402, -1.40769434]], dtype=float32)}, |
| 246 | +'dog.jpg': {'res5_3_branch2c_conv': array([[-0.11531784, -0.10835785, -0.08809858, ...,0.0055237, 0.01505112, -0.08788397]], dtype=float32), 'res5_3_branch2c_bn': array([[-1.27663755, -1.18272924, -0.90937918, ..., -1.25178063, -1.11515927, -2.59122872]], dtype=float32)} |
| 247 | +} |
| 248 | +``` |
| 249 | + |
| 250 | +仔细观察,这些特征值与上述使用C++接口提取的结果是一致的。 |
| 251 | + |
| 252 | +## 预测 |
| 253 | + |
| 254 | +`classify.py`文件也可以用于对样本进行预测。我们提供了一个示例脚本`predict.sh`,它使用50层的ResNet模型来对`example/test.list`中的数据进行预测。 |
| 255 | + |
| 256 | +``` |
| 257 | +cd demo/model_zoo/resnet |
| 258 | +./predict.sh |
| 259 | +``` |
| 260 | + |
| 261 | +predict.sh调用了`classify.py`: |
| 262 | + |
| 263 | +``` |
| 264 | +python classify.py \ |
| 265 | + --job=predict \ |
| 266 | + --conf=resnet.py\ |
| 267 | + --multi_crop \ |
| 268 | + --model=model/resnet_50 \ |
| 269 | + --use_gpu=1 \ |
| 270 | + --data=./example/test.list |
| 271 | +``` |
| 272 | +* \--job=extract: 指定工作模型进行预测。 |
| 273 | +* \--conf=resnet.py: 网络配置文件。network configure. |
| 274 | +* \--multi_crop: 使用10个裁剪图像块,预测概率取平均。 |
| 275 | +* \--use_gpu=1: 指定是否使用GPU。 |
| 276 | +* \--model=model/resnet_50: 模型路径。 |
| 277 | +* \--data=./example/test.list: 数据列表。 |
| 278 | + |
| 279 | +如果运行成功,你将会看到如下结果,其中156和285是这些图像的分类标签。 |
| 280 | + |
| 281 | +``` |
| 282 | +Label of example/dog.jpg is: 156 |
| 283 | +Label of example/cat.jpg is: 282 |
| 284 | +``` |
0 commit comments