PP-YOLO詳解(1)-- backbonepython
你們好,本次教程將帶領你們開啓PP-YOLO學習。經過前面一系列學習,相信你們已經掌握了圖像分類任務的基本概念以及相關實踐,下面將帶你們實戰目標檢測任務中經典的YOLO系列算法:PP-YOLO。git
本次將對使用的backbone網絡:ResNet50-vd-dcn,進行講解。github
下載安裝命令 ## CPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle ## GPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
1 ResNet_D
Resnet_vd最先是在Bag of Tricks for Image Classification with Convolutional Neural Networks,這篇文章中提出了不少很是實用的訓練技巧,我會在後面專門出一期教程對這些技巧進行詳細講解。算法
對於ResNet網絡來講,最核心的部分即跳躍鏈接結構,其分爲兩種BasicBlock、BottleneckBlock,網絡
,ide
在這裏,咱們只關心BottleneckBlock這個結構,在論文中,對該結構作了以下改進:性能
須要注意的是每一個結構中輸入和輸出的鏈接方式,在resnet_c中,改進的地方爲模型開始的7 * 7卷積層,使用了連續的3 * 3 卷積層進行了替代。在論文中主要針對BottleneckBlock進行了改進。原始的BottleneckBlock以下所示:學習
1.1 代碼講解
代碼來源於paddle2.0rc官方API文檔源碼,傳送門,經過閱讀源碼,發現這裏直接實現了resnet_vb結構,即下采樣放在了第二個卷積(3 * 3)上,沒有放在第一個卷積(1 * 1)上。而且paddleclas中,對resnet的定義也是使用了resnet_vb結構。url
1.1.1 ResNet_B詳解
class BottleneckBlock(nn.Layer): def __init__(self, num_channels, num_filters, stride, shortcut=True, name=None, data_format="NCHW"): super(BottleneckBlock, self).__init__() self.conv0 = ConvBNLayer( num_channels=num_channels, num_filters=num_filters, filter_size=1, act="relu", name=name + "_branch2a", data_format=data_format) self.conv1 = ConvBNLayer( num_channels=num_filters, num_filters=num_filters, filter_size=3, stride=stride, act="relu", name=name + "_branch2b", data_format=data_format) self.conv2 = ConvBNLayer( num_channels=num_filters, num_filters=num_filters * 4, filter_size=1, act=None, name=name + "_branch2c", data_format=data_format) if not shortcut: self.short = ConvBNLayer( num_channels=num_channels, num_filters=num_filters * 4, filter_size=1, stride=stride, name=name + "_branch1", data_format=data_format) self.shortcut = shortcut self._num_channels_out = num_filters * 4 def forward(self, inputs): y = self.conv0(inputs) conv1 = self.conv1(y) conv2 = self.conv2(conv1) if self.shortcut: short = inputs else: short = self.short(inputs) y = paddle.add(x=short, y=conv2) y = F.relu(y) return y
在這裏,再也不對resnet中原始的BottleneckBlock進行贅述,直接使用飛槳官方給出的代碼。對於想要嘗試原始的BottleneckBlock的同窗,只需將第二個卷積中的stride換到第一個卷積中便可。spa
1.1.2 ResNet_C詳解
self.conv1_1 = ConvBNLayer( num_channels=3, num_filters=32, filter_size=3, stride=2, act='relu', name="conv1_1") self.conv1_2 = ConvBNLayer( num_channels=32, num_filters=32, filter_size=3, stride=1, act='relu', name="conv1_2") self.conv1_3 = ConvBNLayer( num_channels=32, num_filters=64, filter_size=3, stride=1, act='relu', name="conv1_3")
self.conv = ConvBNLayer( num_channels=self.input_image_channel, num_filters=64, filter_size=7, stride=2, act="relu", name="conv1", data_format=self.data_format)
1.1.3 ResNet_D詳解
class ConvBNLayer(nn.Layer): def __init__(self, num_channels, num_filters, filter_size, stride=1, groups=1, is_vd_mode=False, act=None, lr_mult=1.0, name=None): super(ConvBNLayer, self).__init__() self.is_vd_mode = is_vd_mode self._pool2d_avg = AvgPool2D( kernel_size=2, stride=2, padding=0, ceil_mode=True) self._conv = Conv2D( in_channels=num_channels, out_channels=num_filters, kernel_size=filter_size, stride=stride, padding=(filter_size - 1) // 2, groups=groups, weight_attr=ParamAttr( name=name + "_weights", learning_rate=lr_mult), bias_attr=False) if name == "conv1": bn_name = "bn_" + name else: bn_name = "bn" + name[3:] self._batch_norm = BatchNorm( num_filters, act=act, param_attr=ParamAttr(name=bn_name + '_scale'), bias_attr=ParamAttr(bn_name + '_offset'), moving_mean_name=bn_name + '_mean', moving_variance_name=bn_name + '_variance') def forward(self, inputs): if self.is_vd_mode: inputs = self._pool2d_avg(inputs) y = self._conv(inputs) y = self._batch_norm(y) return y
1.2 ResNet_D總結
在原始的ResNet中,如圖所示,Path A的第一個1 x 1卷積層使用了strde=2的步長,會致使3/4的信息丟失。所以ResNet-B將第1、二個卷積層的步長交換。實驗代表ResNet-B 有0.5%的性能提高。
由於卷積的代價會隨着卷積核的長和寬增大而接近平方增長,所以ResNet-C使用3個連續的3 x 3 卷積替換Input stem的7 x 7 卷積。實驗代表ResNet-C 有0.2%的性能提高。
ResNet-D在ResNet-B的基礎上進一步調整,在Path B的1 x 1卷積前面,加入2 x 2 stride 2的pooling層,將下采樣提早,避免了3/4的信息丟失。實驗代表ResNet-D 有0.3%的性能提高。
上述中均來自於論文中的論述。實際上這裏還存在着一個問題,爲何在Path A中將下采樣提早就會避免信息丟失。(目前我也對這部分存在疑問,找到答案後會對此進行闡述)
對於ResNet-C使用3個連續的3 x 3 卷積替換Input stem的7 x 7 卷積,我本身的理解有兩方面的好處,
(1)感覺野相同,(2)減小參數量。
ResNet-D同ResNet-B中Path A中相同處理的辦法相同,一樣將下采樣提早,避免信息丟失。
下載安裝命令 ## CPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle ## GPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
一點小小的宣傳&下期預告
下一個項目中將爲你們介紹在Paddle2.0中DCN 是如何實現的,而且對代碼詳解。歡迎你們關注哦。
我目前在上海,感興趣的領域包括模型壓縮、小目標檢測、嵌入式,歡迎交流關注。來AI Studio互粉吧等你哦
本文同步分享在 博客「小鴨學院」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。