(13)10张结构图,深入理解YOLOv11算法各个模块

YOLOv11继承自YOLOv8,使同等精度下参数量降低20%。

在这里插入图片描述

一、yolo v11核心代码和对应的结构

(1)动态卷积层

def autopad(k, p=None, d=1):
    """自动填充以保持输出形状相同"""
    if d > 1:
    	# 实际的卷积核大小
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  
    if p is None:
    	# 自动填充
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  
    return p
    
class DynamicConv(nn.Module):
    """动态卷积层"""
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True, num_experts=4):
        super().__init__()
        self.conv = nn.Sequential(
            DynamicConv_Single(c1, c2, kernel_size=k, stride=s, padding=autopad(k, p, d), dilation=d, groups=g, num_experts=num_experts),
            nn.BatchNorm2d(c2),
            nn.SiLU() if act else nn.Identity()
        )

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

(2)卷积层

image-20241214123406653

class Conv(nn.Module):
    """卷积层,包含卷积、批归一化和激活函数"""
    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=None, groups=1, act=True):
        super(Conv, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, autopad(kernel_size, padding), groups=groups, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.act = nn.SiLU() if act else nn.Identity()  # 使用SiLU激活函数
        
    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

(3)Bottleneck结构

image-20241214154638949

class Bottleneck(nn.Module):
    """标准瓶颈模块,包含两个卷积层"""
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):
        super(Bottleneck, self).__init__()
        c_ = int(c2 * e)  # 隐藏通道数
        self.cv1 = Conv(c1, c_, k[0], 1)  # 第一个卷积层
        self.cv2 = Conv(c_, c2, k[1], 1)  # 第二个卷积层
        self.add = shortcut and c1 == c2  # 是否使用shortcut连接

    def forward(self, x):
        """前向传播,使用shortcut连接"""
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

(4)C2f层

​ C2f层使用了2个Bottleneck模块,在小网络会使用这个模块。

image-20241214160813691

class C2f(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
        """Initializes a CSP bottleneck with 2 convolutions and n Bottleneck blocks for faster processing."""
        super().__init__()
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

    def forward_split(self, x):
        """Forward pass using split() instead of chunk()."""
        y = self.cv1(x).split((self.c, self.c), 1)
        y = [y[0], y[1]]
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

(5)C3k层

image-20241214163211679

class C3k(nn.Module):
    """C3k模块,包含多个瓶颈模块"""
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=3):
        super(C3k, self).__init__()
        c_ = int(c2 * e)  # hidden channels
        self.m = nn.Sequential(*(Bottleneck(c1, c2, shortcut, g, k=(k, k), e=e) for _ in range(n)))  # 创建n个瓶颈模块

    def forward(self, x):
        return self.m(x)  # 前向传播
        

(6)C3K2层

​ 实际就使用看2个上面讲的C3K层,在大网络会使用这个模块。

image-20241214164856010

class C3k2(C2f):
    def __init__(self, c1, c2, n=1, c3k=False, e=0.5, g=1, shortcut=True):
        super().__init__(c1, c2, n, shortcut, g, e)
        self.m = nn.ModuleList(
            C3k(self.c, self.c, 2, shortcut, g) if c3k else Bottleneck(self.c, self.c, shortcut, g) for _ in range(n)
        )

(7)C3k动态卷积

class C3k_DynamicConv(C3k):
    """C3k模块,使用动态卷积"""
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=3):
        super().__init__(c1, c2, n, shortcut, g, e, k)
        c_ = int(c2 * e)  # 隐藏通道数
        self.m = nn.Sequential(*(Bottleneck_DynamicConv(c_, c_, shortcut, g, k=(k, k), e=1.0) for _ in range(n)))
# 创建n个动态卷积瓶颈模块
class C3k2_DynamicConv(C3k2):
    """C3k2模块,使用动态卷积"""
    def __init__(self, c1, c2, n=1, c3k=False, e=0.5, g=1, shortcut=True):
        super().__init__(c1, c2, n, c3k, e, g, shortcut)
        self.m = nn.ModuleList(C3k_DynamicConv(self.c, self.c, 2, shortcut, g) if c3k else Bottleneck_DynamicConv(self.c, self.c, shortcut, g, k=(3, 3), e=1.0) for _ in range(n))

(8)FFN层

image-20241214165337258

(9)PSA层

​ 这些模块负责自注意力(self-attention)和前馈(feed-forward)操作。PSABlock 类实现了神经网络中的位置敏感注意力块。这个类封装了应用多头注意力和前馈神经网络层的功能,并可选地包含快捷连接。

image-20241214171145038

class PSABlock(nn.Module):
    def __init__(self, c, attn_ratio=0.5, num_heads=4, shortcut=True) -> None:
        super().__init__()
        self.attn = Attention(c, attn_ratio=attn_ratio, num_heads=num_heads)
        self.ffn = nn.Sequential(Conv(c, c * 2, 1), Conv(c * 2, c, 1, act=False))
        self.add = shortcut

    def forward(self, x):
        x = x + self.attn(x) if self.add else self.attn(x)
        x = x + self.ffn(x) if self.add else self.ffn(x)
        return x

(10)C2PSA层

  • C2PSA模块:这个模块实现了一个带有注意力机制的卷积块,目的是提升特征提取和处理的效果。

image-20241214172508365

  • **注意力机制的卷积块 **:

    image-20241214182853058

代码:

class C2PSA(nn.Module):
    def __init__(self, c1, c2, n=1, e=0.5):
        super().__init__()
        assert c1 == c2
        self.c = int(c1 * e)
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv(2 * self.c, c1, 1)
        self.m = nn.Sequential(*(PSABlock(self.c, attn_ratio=0.5, num_heads=self.c // 64) for _ in range(n)))
    def forward(self, x):
        a, b = self.cv1(x).split((self.c, self.c), dim=1)
        b = self.m(b)
        return self.cv2(torch.cat((a, b), 1))

二、yolo入门实战教程

​ 视频教程点击:《吐血录制,yolo11猫狗实时检测实战项目,从零开始写yolov11代码》,视频全程25分钟,或B站搜“AI莫大猫”。

image-20241212090014863

​ 从零训练自己的数据集。

三、往期回顾

(1)yolo11猫狗实时检测实战项目,从零开始写yolov11代码
(2)yolo实战:从零开始学yolo之yolov1的技术原理
(3)YOLOv1训练过程,新手入门
高清动画,3分钟揭秘神经网络技术原理
在这里插入图片描述

Transfermer的Q、K、V设计的底层逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值