Pytorchに基づくYoLoV5バックボーンの再現(パート1)

創造を続け、成長を加速させましょう!「ナゲッツデイリーニュープラン・6月アップデートチャレンジ」に参加した初日です。クリックしてイベントの詳細をご覧ください。

序文

簡単にまとめてみましょう。最近レビューもレビューしています。今学期の学習成果を見て、まとめて強化していきましょう。一連のメモはまだ整理中です。自分でレビューする時間はもちろん、深層学習の内容は、主にその週のYOLOについてであり、来週は私自身のクラスのものです。

このブログ投稿も約2日間作成されました。V1〜V3の論文を注意深く見ました。開発の観点から、V1からV3への変更は非常に大きいため、V4とV5は読んでいません。 V5はもっとありますそれはニューラルネットワークの構造に最適化されています。そして今日の私たちの仕事は、YOLOV5のバックボーンをどのように再現するかです。

どんなに良い理論でも実践する必要があり、理解と反省を深めることができます。次に、YOLOを使ってもっとクールなことをする必要があるので、このレベルは克服できないレベルです。

このブログ投稿は、探索用のYOLOV5.5バージョンに基づいています〜スペースの問題を考慮して、複製のために2つのブログ投稿に分割されます。

ネットワーク構造

始める前に、yolov5全体のネットワーク構造を見てみましょう。画像の説明を追加してくださいこれは完全なニューラルネットワーク構造であり、 netron.app /を介して生成できますが、この図を直接使用することはありません。実際には多くの繰り返しがあります。、この図を使用して

リファレンスデザイン

実際の写真はわかりにくいので、知乎の兄である江大白の写真を参考にしましょう。ここに画像の説明を挿入

次に、各モジュールの説明を開始します。(現在のバージョンは実際には入力batch_size x 3 x 640 x 640の画像であることに注意してください)実際の画像はこの参照図面と同じではありません。実際、特定の画像は上記の画像に基づいています。だいたい長いですが、何であれ、投稿します。

フォーカスモジュール

始める前に何かに気づいたここに画像の説明を挿入

このことはこのようなことをします、ここに画像の説明を挿入コード

class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super(Focus, self).__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act)      # 这里输入通道变成了4倍

    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))

复制代码

原始的3 x 640 × 640 的图像输入Focus结构,采用切片操作,先变成12 x 320 × 320的特征图 这里代码里面是将一张图片切成4份,每一份有原来的3个通道,所以 这里是c1*4。并且你应该注意到了这个第一个CONV的W的大小是64 x 32 x3 x3 这个也很好解释,一张图片本来是 .3 x 640 x 640 卷积核大小 3 x 3 按道理如果输出一个通道的话 那么 就是 3 x 3 x 3 此时输出32个通道就是 32 x 3 x 3 x 3 但是你有4份就是12个所以就是 32 x 12 x 3 x 3。 具体的推导可以看这张图 ここに画像の説明を挿入

接下来就是我们的其他模块

Conv 卷积模块

这个在YOLOV5里面为了放置各种训练问题,它做了不少优化,首先是一开始的训练的时候有数据增强的处理,然后就是在卷积的时候,有归一化的处理,防止参数差距很大带来的干扰。


class Conv(nn.Module):
    def __init__(self,c1,c2,k=1,s=1,p=None,g=1,act=True):
        super(Conv,self).__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

    def forward(self, x):
        
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        return self.act(self.conv(x))



复制代码

ここに画像の説明を挿入 这里注意的是这个Sigmoid 是这个玩意和RULE其实很像,但是人家<0 有负值 ここに画像の説明を挿入 这里的话多一嘴,其实这个卷积核和我们线性权重是类似的,只不过人家做到是矩阵微分,没那么神秘。

然后这里对应的图中应该是CBL模块,不过在咱们这里是Conv。

残差模块

这个对应的其实就是这个模块了CSP1_x 模块

在我们当前版本是这样的

class Bottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansion
        super(Bottleneck, self).__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_, c2, 3, 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
复制代码

ここに画像の説明を挿入

C3 模块

这个模块是这个样子的,和残差有点像,但是人家不是相加,而是扩充。 ここに画像の説明を挿入 它是保留了一部分,然后进入残差,最后做一个融合。

class C3(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super(C3, self).__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)
        self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])
        # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))

复制代码

这个“砍”一半是通过卷积实现的,通过把通道砍到原来的0.5倍实现了留下一半,然后通过残差模块self.m(cv1) 实现卷积部分,然后在通过cat合并。

ここに画像の説明を挿入 ここに画像の説明を挿入

基本上我们实际的网络架构图里面有的东西就有了,当然这里面其实还有很多门道,你仔细看common文件里面就知道,这些东西的话需要结合论文来说,我这里不好说,为了这个玩意儿我至少看了5,6篇论文,还要整理。

V3バージョンで提案されている7x713x1326x26 gradセルは、ここにあるものです(もちろん、ここではそれほど小さくはありません)。ここに画像の説明を挿入 ここに画像の説明を挿入これは、JiangDabai氏の写真に似ています。

その後、繰り返し続けます。

lxsmの違い

ここに来たので、yolov5の背後にある接尾辞の意味について話しましょう。

ここに画像の説明を挿入

実際、このyolov5xx.yamlを開くと、これがわかります。

このここに画像の説明を挿入違い。

実際、これら2つのパラメーターは、ネットワークの深さと幅を表します。たとえば、width_multipleはここでは0.5です。

出力を制御する方法は?単純。

畳み込みによって出力されるチャネル数のサイズにwidth_mulitpleを掛けると、実際には深度が制御されます。たとえば、元々設定されていた128チャネルを出力しますが、0.5を掛けて出力が64になるため、幅は狭くなります。 。深さもとてもシンプルです。CSP1_Xを覚えていますか?

Zaijiang Dabai氏の写真は、繰り返される残差がいくつかあることを示しています。標準設定はCSP1_3(モジュールがあると仮定)だと思います。3x0.3は1の整数なので、私のCSP1_3は実際にはあります。残差が1つだけであるなど、深さが低下します。設定がすべて1.0であるため、最も標準的なのはyolov5l.ptです。

おすすめ

転載: juejin.im/post/7101961593797214238