2.3 C3网络结构原理及代码解释

一,原理

原理的图片参考了P8:在天气识别中加入YOLOv5-C3模块_yolov5中c3个数_爱挠静香的下巴的博客-CSDN博客。

C3网络构成如下图所示:

1.首先我们假设输入(input)一个tensor类型的float32的1X3X10X100的矩阵x;

2.Conv卷积网络结构:构建一个卷积网络,其输入通道为3,输出通道为3,卷积核大小为1,步长为1;再加标准化BatchNorm2d+激活函数SiLU;

3.Bottleneck残差网络结构:如下图,输入x后由两个卷积网络Conv得到一个1X3X10X100的矩阵y,这个矩阵y是对x的值经过标准化和激活函数处理过的输出值,矩阵大小和输入的x相同。最后返回值是x与y的和,即返回x+y,在这里残差网络就构建完了;

4.C3网络结构:将输入的x分别做两种处理,一是由残差网络获得一个输出值output1,二是直接由Conv卷积网络获得一个输出矩阵output2(注意,这里的conv内的输入和输出通道数会有所改变,具体变化可以看下面的代码)。最后再将两个输出值相加,即最终返回torch.cat(output1,output2)。

 

二,代码解释

C3代码的运行用到了卷积网络和残差网络,所以代码看着有点多,可以根据上面的原理思路一个一个理解。其代码解释如下:

import torch
import cv2
import numpy as np
import torch.nn as nn

#输入图片路径
image=cv2.imread(r"D:\AI\data\red_green_light\4.jpg")

images=image.reshape(1,3,1080, 1920)

input=torch.tensor(images,dtype=torch.float32)#浮点型


#silu激活函数
class SiLU(nn.Module):
    @staticmethod
    def forward(x):
        return x * torch.sigmoid(x)

def autopad(k, p=None):
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]
    return p
#卷积结构
class Conv(nn.Module):
    def __init__(self, c1=3, c2=3, 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, eps=0.001, momentum=0.03)#标准化
        self.act    = 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)))#卷积->BatchNorm2d->激活函数->output

    def fuseforward(self, x):
        return self.act(self.conv(x))#这个forward函数不存在BN操作


#残差网络
class Bottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1=3, c2=3, shortcut=True, g=1, e=0.5):
        super(Bottleneck,self).__init__()
        c_=int(c2*e)# hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)  # 输入通道数为c1,输出通道数为c_,卷积核大小为1,步长为1,默认为0填充(实际上是图片本身)
        self.cv2 = Conv(c_, c2, 3, 1, g=g)  # 输入通道数为c_,输出通道数为c2,卷积核大小为3,步长为1,默认为0填充
        self.add=shortcut and c1==c2# c1与c2需相同才可进行shortcut运算

    def forward(self,x):
        # 根据self.add的值确定是否有shortcut
        return x+self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))


class C3(nn.Module):
    def __init__(self,c1=3, c2=3, 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)
        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)])

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




#1.卷积网络
hh=Conv()
output2=hh(input)

#2.运用残差网络
ss=Bottleneck()
output=ss(input)

#3.运用C3网络
tt=C3()
out=tt(input)

print("输入值x",input)

print("卷积值:",output2)

print("残差值:",output)

print("C3值:",out)
print(out.shape)

你可能感兴趣的:(1.Yolov5解释,深度学习,人工智能,计算机视觉,YOLO,python,pytorch)