<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          超越所有YOLO檢測(cè)模型,mmdet開源當(dāng)今最強(qiáng)最快目標(biāo)檢測(cè)模型!

          共 14326字,需瀏覽 29分鐘

           ·

          2022-09-29 10:50

          首先,這里先聲明一下由于論文和代碼沒有一并放出,所以以下內(nèi)容全是個(gè)人學(xué)習(xí)RTMDet代碼的一個(gè)結(jié)果,整個(gè)過程時(shí)間也比較緊湊,難免會(huì)有所遺漏和錯(cuò)誤,一切關(guān)于RTMDet的工作,最終以O(shè)penMMLab官方論文為主,因?yàn)榭吹介_源代碼的速度表,小編很難不愛,小模型就可以把YOLO全系列按在地上摩擦,因此也就有了下面的故事。

          0、直接上架構(gòu)圖吧!

          看著上面的圖,熟悉不?是不是滿滿的YOLO系列的味道?是的,看代碼我猜應(yīng)該是基于YOLO來進(jìn)行的增量實(shí)驗(yàn)吧,也僅僅是猜啦,畢竟暗俺也沒看到RTMDet的論文,俺也不是開發(fā)者!

          1、改進(jìn)點(diǎn)1 —— CSPNeXt

          1.1 Backbone 部分

          話不多說,直接上代碼:

          class CSPNeXtBlock(BaseModule):
              def __init__(self,
                           in_channels: int,
                           out_channels: int,
                           expansion: float = 0.5,
                           add_identity: bool = True,
                           use_depthwise: bool = False,
                           kernel_size: int = 5,
                           conv_cfg: OptConfigType = None,
                           norm_cfg: ConfigType = dict(
                               type='BN', momentum=0.03, eps=0.001)
          ,
                           act_cfg: ConfigType = dict(type='SiLU'),
                           init_cfg: OptMultiConfig = None)
           -> None:

                  super().__init__(init_cfg=init_cfg)
                  hidden_channels = int(out_channels * expansion)
                  conv = DepthwiseSeparableConvModule if use_depthwise else ConvModule
                  self.conv1 = conv(
                      in_channels,
                      hidden_channels,
                      3,
                      stride=1,
                      padding=1,
                      norm_cfg=norm_cfg,
                      act_cfg=act_cfg)
                  self.conv2 = DepthwiseSeparableConvModule(
                      hidden_channels,
                      out_channels,
                      kernel_size,
                      stride=1,
                      padding=kernel_size // 2,
                      conv_cfg=conv_cfg,
                      norm_cfg=norm_cfg,
                      act_cfg=act_cfg)
                  self.add_identity = add_identity and in_channels == out_channels

              def forward(self, x: Tensor) -> Tensor:
                  identity = x
                  out = self.conv1(x)
                  out = self.conv2(out)

                  if self.add_identity:
                      return out + identity
                  else:
                      return out

          其實(shí)通過代碼我們可以很直觀的看出模型的架構(gòu)細(xì)節(jié),這里小編也進(jìn)行了簡(jiǎn)要的繪制,具體如下圖:

          這里提到的 Depthwise Separable Convolution 是 MobileNet 的基本單元,其實(shí)這種結(jié)構(gòu)之前已經(jīng)使用在 Inception 模型中。Depthwise Separable Convolution 其實(shí)是一種可分解卷積操作,其可以分解為2個(gè)更小的操作:Depthwise Convolution 和 Pointwise Convolution,如圖所示。

          Depthwise Convolution 和標(biāo)準(zhǔn)卷積不同,對(duì)于標(biāo)準(zhǔn)卷積,其卷積核是用在所有的輸入通道上(input channels),而 Depthwise Convolution 針對(duì)每個(gè)輸入通道采用不同的卷積核,就是說一個(gè)卷積核對(duì)應(yīng)一個(gè)輸入通道,所以說 Depthwise Convolution 是 Depth 級(jí)別的操作。

          而 Pointwise Convolution 其實(shí)就是普通的 1×1 的卷積。對(duì)于 Depthwise Separable Convolution,首先是采用 Depthwise Convolution 對(duì)不同輸入通道分別進(jìn)行卷積,然后采用 Pointwise Convolution 將上面的輸出再進(jìn)行結(jié)合,這樣整體效果和一個(gè)標(biāo)準(zhǔn)卷積是差不多的,但是會(huì)大大減少計(jì)算量和模型參數(shù)量。

          熟悉DarkNet的朋友應(yīng)該都知道,如果你不知道,小編這里也給出架構(gòu)圖:

          然后依舊是直接上CSPLayer的代碼:

          class CSPLayer(BaseModule):
              def __init__(self,
                           in_channels: int,
                           out_channels: int,
                           expand_ratio: float = 0.5,
                           num_blocks: int = 1,
                           add_identity: bool = True,
                           use_depthwise: bool = False,
                           use_cspnext_block: bool = False,
                           channel_attention: bool = False,
                           conv_cfg: OptConfigType = None,
                           norm_cfg: ConfigType = dict(type='BN', momentum=0.03, eps=0.001),
                           act_cfg: ConfigType = dict(type='Swish'),
                           init_cfg: OptMultiConfig = None)
           -> None:

                  super().__init__(init_cfg=init_cfg)
                  block = CSPNeXtBlock if use_cspnext_block else DarknetBottleneck
                  mid_channels = int(out_channels * expand_ratio)
                  self.channel_attention = channel_attention
                  self.main_conv = ConvModule(
                      in_channels,
                      mid_channels,
                      1,
                      conv_cfg=conv_cfg,
                      norm_cfg=norm_cfg,
                      act_cfg=act_cfg)
                  self.short_conv = ConvModule(
                      in_channels,
                      mid_channels,
                      1,
                      conv_cfg=conv_cfg,
                      norm_cfg=norm_cfg,
                      act_cfg=act_cfg)
                  self.final_conv = ConvModule(
                      2 * mid_channels,
                      out_channels,
                      1,
                      conv_cfg=conv_cfg,
                      norm_cfg=norm_cfg,
                      act_cfg=act_cfg)

                  self.blocks = nn.Sequential(*[
                      block(
                          mid_channels,
                          mid_channels,
                          1.0,
                          add_identity,
                          use_depthwise,
                          conv_cfg=conv_cfg,
                          norm_cfg=norm_cfg,
                          act_cfg=act_cfg) for _ in range(num_blocks)
                  ])
                  if channel_attention:
                      self.attention = ChannelAttention(2 * mid_channels)

              def forward(self, x: Tensor) -> Tensor:
                  x_short = self.short_conv(x)

                  x_main = self.main_conv(x)
                  x_main = self.blocks(x_main)

                  x_final = torch.cat((x_main, x_short), dim=1)

                  if self.channel_attention:
                      x_final = self.attention(x_final)
                  return self.final_conv(x_final)

          其結(jié)構(gòu)如下所示,毫無疑問依舊是香香的CSP思想,但是這里的結(jié)構(gòu)使用了5×5的DW卷積,實(shí)現(xiàn)了更少的參數(shù)量的情況下,帶來更大的感受野。

          同時(shí)這里RTMDet的Backbone中還考慮了通道注意力的問題,其代碼如下:

          class ChannelAttention(BaseModule):
              def __init__(self, channels: int, init_cfg: OptMultiConfig = None) -> None:
                  super().__init__(init_cfg)
                  self.global_avgpool = nn.AdaptiveAvgPool2d(1)
                  self.fc = nn.Conv2d(channels, channels, 110, bias=True)
                  self.act = nn.Hardsigmoid(inplace=True)

              def forward(self, x: torch.Tensor) -> torch.Tensor:
                  out = self.global_avgpool(x)
                  out = self.fc(out)
                  out = self.act(out)
                  return x * out

          小編依舊給小伙伴們畫了示意圖:

          其實(shí)還有一個(gè)細(xì)節(jié),這里我想的也不是很明白,如果熟悉ResNet構(gòu)建的小伙伴應(yīng)該知道,凱明大神在構(gòu)建ResNet50是使用的殘差Block的數(shù)量配比就是[3,6,6,3],

          這里RTMDet使用的配比也是:

          但是小編在白嫖 TRT-ViT、NeXtViT、SWin以及ConvNeXt的時(shí)候都在或有或無地說逐層增加配比會(huì)帶來更好的結(jié)果,這里不知道為什么RTMDet選擇以前的數(shù)據(jù),期待論文中的描述和解釋!

          1.2 Neck部分

          其實(shí)也是毫不意外的PAFPN的架構(gòu),只不過這里作者選擇把YOLO系列中的CSPBlock替換為了本方法中的CSPNeXt Block,具體架構(gòu)圖如下所示:

          1.3 Head部分

          這部分也是相對(duì)比較常規(guī)的設(shè)計(jì),對(duì)于PAFPN結(jié)構(gòu)輸出的特征,先使用由堆疊的卷積所組成的分類分支以及回歸分支提取對(duì)應(yīng)的分類特征和回歸特征,然后分別送到對(duì)應(yīng)的RTM分類分支和回歸分支,得到我們最終隨需要的東西,這里有一個(gè)小小的細(xì)節(jié),便是堆疊的卷積在不同level的中是共享權(quán)重的,具體可以參見代碼,這里也不進(jìn)行過多的猜測(cè),最終還是以論文為主。

          2、匹配策略

          直接上配置參數(shù),熟悉Nanodet的小伙伴你是不是又知道了!嗯,是的是熟悉的味道,就是NanoDet-Plus的哪個(gè)策略,依舊很香,依舊很好用?。?!

          當(dāng)年的Nanodet-Plus是這樣的:

          這里所謂動(dòng)態(tài)匹配,簡(jiǎn)單來說就是直接使用模型檢測(cè)頭的輸出,與所有Ground Truth計(jì)算一個(gè)匹配得分,這個(gè)得分由分類損失和回歸損失相加得到。特征圖上N個(gè)點(diǎn)的預(yù)測(cè)值,與M個(gè)Ground Truth計(jì)算得到一個(gè)N×M的矩陣,稱為Cost Matrix,基于這個(gè)矩陣可以讓當(dāng)前預(yù)測(cè)結(jié)果動(dòng)態(tài)地尋找最優(yōu)標(biāo)簽,匹配的策略有二分圖匹配、傳輸優(yōu)化、Top-K等,在NanoDet中直接采取了Top-K的策略來匹配。

          這種策略的一個(gè)問題在于,在網(wǎng)絡(luò)訓(xùn)練的初期,預(yù)測(cè)結(jié)果是很差的,可能根本預(yù)測(cè)不出結(jié)果。所以在動(dòng)態(tài)匹配時(shí)還會(huì)加上一些位置約束,比如使用一個(gè) 5×5 的中心區(qū)域去限制匹配的自由程度,然后再依賴神經(jīng)網(wǎng)絡(luò)天生的抗噪聲能力,只需要在Ground Truth框內(nèi)隨機(jī)分配一些點(diǎn),網(wǎng)絡(luò)就能學(xué)到一些基礎(chǔ)的特征。

          3、損失函數(shù)

          這部分主要是是用來QFL和GIOU Loss,這里不進(jìn)行過多描述,以后盡可能補(bǔ)上吧,今天太累了,已經(jīng)太晚了。。。。

          4、輸入端部分

          階段一

          作者在訓(xùn)練的第一階段,主要是使用了CacheMosaic數(shù)據(jù)增強(qiáng),RandomResize,RandomCrop,RandomCrop,CacheMixup以及YOLOX關(guān)于HSV的一些增強(qiáng)手段,這里的CacheMosaic以及CacheMixup是mmdet中全新提出的新Trcik煉丹術(shù);

          階段2

          作者在訓(xùn)練階段2提出了前面提出的新技術(shù),CacheMosaic以及CacheMixup,看樣子這里應(yīng)該是學(xué)習(xí)YOLOX的訓(xùn)練技術(shù):

          4.1、CacheMosaic

          1、Mosaic流程:

          1. 選擇Mosaic中心作為4幅圖像的交點(diǎn)。
          2. 根據(jù)索引獲取左上圖,從自定義數(shù)據(jù)集中隨機(jī)抽取另外3張圖片。
          3. 如果圖像大于Mosaic Patch,子圖像將被裁剪。

          2、CacheMosaic流程:

          1. 將上次Transform的結(jié)果加到Cache中。
          2. 選擇Mosaic中心作為4幅圖像的交點(diǎn)。
          3. 根據(jù)索引獲取左上圖,從結(jié)果緩存中隨機(jī)抽取另外3張圖片。
          4. 如果圖像大于Mosaic Patch,子圖像將被裁剪。

          優(yōu)點(diǎn)我猜就是訓(xùn)練快?。?!

          4.2、CacheMixup

          1、Mixup

          1. 另一個(gè)隨機(jī)圖像被數(shù)據(jù)集挑選并嵌入到左上角的Patch中(在填充和調(diào)整大小之后)
          2. mixup變換的目標(biāo)是mixup image和origin image的加權(quán)平均。

          2、CacheMixup

          1. 將上次Transform的結(jié)果加到Cache中。
          2. 從Cache中挑選另一個(gè)隨機(jī)圖像并嵌入到左上角的Patch中(在填充和調(diào)整大小之后)
          3. mixup變換的目標(biāo)是mixup image和origin image的加權(quán)平均。

          參考

          [1].https://github.com/RangiLyu/mmdetection/tree/rtmdet_config/configs/rtmdet.

          分享

          收藏

          點(diǎn)贊

          在看

          瀏覽 137
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99精品视频免费观看 | 十八禁免费观看网站 | 免费无码又爽又高潮视频 | 亚洲 小说区 图片区 | aaaaaa在线 |