Pytorch入门实战 P09-YOLOv5里面的Backbone模块搭建网络

目录

1、YOLOv5的模型图。

2、BackBone简单介绍。

3、YOLOv5的Backbone文件。

4、YOLOv5Backbone的code部分

5、完整的code部分

6、结果展示

(1)Adam优化器

(2)SGD优化器


  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊 | 接辅导、项目定制

这周的这篇博客,主要是使用YOLOv5里面的Backbone模块,搭建网络。

我们先来看下YOLOv5的Backbone部分。

1、YOLOv5的模型图。

(图片来源于网络)

上图中,最左侧的事YOLOv5里面的BackBone,上篇博文,主要讲的是YOLOv5里面的BackBone里面的C3模块。

这篇文章,我们主要看YOLOv5里面的BackBone部分,即:YOLOv5的骨干网络。

2、BackBone简单介绍。

YOLOv5 模型主要由 Backbone、Neck 和Head 三部分组成,网络模型(如上图所示)。

①Backbone 主要负责对输入图像进行特征提取
②Neck 负责对特征图进行多尺度特征融合,并把这些特征传递给预测层。
③Head 进行最终的回归预测

YOLOv5的骨干网络(Backbone)是其整体架构中至关重要的部分,主要负责从输入图像中提取丰富的特征信息。以下是关于YOLOv5骨干网络的详细说明:

骨干网络采用自下而上的路径从原始图像中提取特征。输入图像经过一系列的卷积、批量归一化和激活函数处理后,得到不同尺度的特征图。这些特征图不仅包含了丰富的细节信息,还具备了一定的语义信息,为后续的目标检测任务提供了有力的支持。

YOLOv5的骨干网络采用了BottleNeckCSP结构,这是一种特殊设计的残差网络结构

(1)该结构由Focus结构、三组CBL+CSP1_x 和 CBL+SPP串行搭建而成。(如下图)

(2)其中,(如下图)。CBL(Convolutional Block)由卷积(Conv)、批量归一化(BN)和激活函数(Leaky ReLU)组成。(也可叫CBS,因为S的话取得是Silu激活函数,L的话,直接取激活函数Leaky,这俩都是可以的,)


(3)(如下图)CSP1_x则借鉴了CSPNet网络结构,由CBL/CBS模块、Res unit模块以及卷积层Concat组成,其中x表示有x个CSP1模块。

(4)随着网络层数的加深,特征图的分辨率逐渐降低。浅层特征图感受野比较小,尺寸比较大,包含更多的细节和位置信息;而深层特征图尺寸比较小,感受野比较大,反映了图像的全局和抽象特征,包含更丰富的语义信息。

3、YOLOv5的Backbone文件。

4、YOLOv5Backbone的code部分

class YOLOv5_backbone(nn.Module):
    def __init__(self):
        super(YOLOv5_backbone, self).__init__()

        self.Conv_1 = Conv(3, 64, 3, 2, 2)
        self.Conv_2 = Conv(64, 128, 3, 2)
        self.C3_3 = C3(128, 128)
        self.Conv_4 = Conv(128, 256, 3, 2)
        self.C3_5 = C3(256, 256)
        self.Conv_6 = Conv(256, 512, 3, 2)
        self.C3_7 = C3(512, 512)
        self.Conv_8 = Conv(512, 1024, 3, 2)
        self.C3_9 = C3(1024, 1024)
        self.SPPF = SPPF(1024, 1024, 5)

        # 全连接网络层,用于分类
        self.classifier = nn.Sequential(
            nn.Linear(in_features=65536, out_features=100),
            nn.ReLU(),
            nn.Linear(in_features=100, out_features=4)
        )

    def forward(self, x):
        x = self.Conv_1(x)
        x = self.Conv_2(x)
        x = self.C3_3(x)
        x = self.Conv_4(x)
        x = self.C3_5(x)
        x = self.Conv_6(x)
        x = self.C3_7(x)
        x = self.Conv_8(x)
        x = self.C3_9(x)
        x = self.SPPF(x)

        x = torch.flatten(x, start_dim=1)
        x = self.classifier(x)

        return 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, c2, k=1, s=1, p=None, g=1, act=True):
        super().__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)))
class Bottleneck(nn.Module):
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):
        super().__init__()
        c_ = int(c2 * e)
        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))
class C3(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__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)))

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))
class SPPF(nn.Module):
    # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
    def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_ * 4, c2, 1, 1)
        self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)

    def forward(self, x):
        x = self.cv1(x)
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
            y1 = self.m(x)
            y2 = self.m(y1)
            return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))

 

5、完整的code部分

import copy
import pathlib
import warnings

import matplotlib.pyplot as plt
import torch
from torch import nn
from torchvision import datasets
from torchvision.transforms import transforms
import matplotlib as mpl
mpl.use('Agg')  # 在服务器上运行的时候,打开注释

'''

    实现YOLOv5的 Backbone模块
'''
# 设置准备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)

# 导入数据
data_dir = './weather_photos'
data_dir = pathlib.Path(data_dir)

data_paths = list(data_dir.glob('*'))
classNames = [str(path).split('/')[1] for path in data_paths]
print(classNames)

# 图像预处理
train_transforms = transforms.Compose([
    transforms.Resize([224, 224]),
    transforms.ToTensor(),
    transforms.Normalize(
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225]
    )
])

test_transforms = transforms.Compose([
    transforms.Resize([224, 224]),
    transforms.ToTensor(),
    transforms.Normalize(
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225]
    )
])
total_data = datasets.ImageFolder('./weather_photos', transform=train_transforms)

# 划分数据集
train_size = int(0.8*len(total_data))
test_size = len(total_data) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size,test_size])
print(train_size, test_size)  # 900 225

# 加载数据集
batch_size = 4
train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
for X, y in test_dl:
    print('Shape of X[N, C, H, W]', X.shape)  # torch.Size([4, 3, 224, 224])
    print('Shape of y', y.shape, y.dtype)  # torch.Size([4]) torch.int64
    break

# 搭建网络模型 (包含Backbone模块的模型)
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, c2, k=1, s=1, p=None, g=1, act=True):
        super().__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)))


class Bottleneck(nn.Module):
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):
        super().__init__()
        c_ = int(c2 * e)
        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))


class C3(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__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)))

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


class SPPF(nn.Module):
    # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
    def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_ * 4, c2, 1, 1)
        self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)

    def forward(self, x):
        x = self.cv1(x)
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
            y1 = self.m(x)
            y2 = self.m(y1)
            return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))


class YOLOv5_backbone(nn.Module):
    def __init__(self):
        super(YOLOv5_backbone, self).__init__()

        self.Conv_1 = Conv(3, 64, 3, 2, 2)
        self.Conv_2 = Conv(64, 128, 3, 2)
        self.C3_3 = C3(128, 128)
        self.Conv_4 = Conv(128, 256, 3, 2)
        self.C3_5 = C3(256, 256)
        self.Conv_6 = Conv(256, 512, 3, 2)
        self.C3_7 = C3(512, 512)
        self.Conv_8 = Conv(512, 1024, 3, 2)
        self.C3_9 = C3(1024, 1024)
        self.SPPF = SPPF(1024, 1024, 5)

        # 全连接网络层,用于分类
        self.classifier = nn.Sequential(
            nn.Linear(in_features=65536, out_features=100),
            nn.ReLU(),
            nn.Linear(in_features=100, out_features=4)
        )

    def forward(self, x):
        x = self.Conv_1(x)
        x = self.Conv_2(x)
        x = self.C3_3(x)
        x = self.Conv_4(x)
        x = self.C3_5(x)
        x = self.Conv_6(x)
        x = self.C3_7(x)
        x = self.Conv_8(x)
        x = self.C3_9(x)
        x = self.SPPF(x)

        x = torch.flatten(x, start_dim=1)
        x = self.classifier(x)

        return x


model = YOLOv5_backbone().to(device)
print(model)


# 编写训练函数
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 训练集大小
    num_batches = len(dataloader)  # 批次数目,size/batch_size 向上取整
    train_loss, train_acc = 0, 0

    for X, y in dataloader:
        X, y = X.to(device), y.to(device)

        # 计算预测误差
        pred = model(X)
        loss = loss_fn(pred, y)

        # 反向传播
        optimizer.zero_grad()  # grad属性归零
        loss.backward()    # 反向传播
        optimizer.step()    # 每一步自动更新

        # 记录acc与loss
        train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()

    train_acc /= size
    train_loss /= num_batches
    return train_acc, train_loss


# 编写测试函数
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    test_loss, test_acc = 0, 0

    # 当不进行训练时,停止梯度更新,节省计算内存消耗
    with torch.no_grad():
        for imgs, target in dataloader:
            imgs, target = imgs.to(device), target.to(device)

            # 计算loss
            target_pred = model(imgs)
            loss = loss_fn(target_pred, target)

            test_loss += loss.item()
            test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()
    test_acc /= size
    test_loss /= num_batches

    return test_acc, test_loss



# 正式训练
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
loss_fn = nn.CrossEntropyLoss()   # 创建损失函数
epochs = 60
train_loss = []
train_acc = []
test_loss = []
test_acc = []
best_acc = 0  # 设置一个最佳准确率,作为最佳模型的判别指标

for epoch in range(epochs):
    model.train()
    epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)

    model.eval()
    epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)

    # 保存最佳模型到best_model
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        best_model = copy.deepcopy(model)

    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)

    # 获得当前学习率
    lr = optimizer.state_dict()['param_groups'][0]['lr']

    template = 'Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f} ,===,Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}'
    print(template.format(epoch + 1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss, lr))

# 保存最佳模型到文件中
PATH = './best_model.pth'
torch.save(best_model.state_dict(), PATH)
print('Done!!')


# 结果可视化
warnings.filterwarnings('ignore')
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100  # 分辨率
epochs_range = range(epochs)

plt.figure(figsize=(12, 3))

plt.subplot(1,2,1)
plt.plot(epochs_range, train_acc, label="Train Accuracy")
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Acc')

plt.subplot(1,2,2)
plt.plot(epochs_range, train_loss, label="Train Loss")
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')

plt.savefig("/data/jupyter/deep_demo/p09_v5_backbone/resultImg.jpg")  # 保存图片在服务器的位置
plt.show()



# 模型评估
best_model.load_state_dict(torch.load(PATH, map_location=device))
epoch_test_acc, epoch_test_loss = test(test_dl, best_model, loss_fn)

print(f'epoch_test_acc:{epoch_test_acc}, epoch_test_loss:{epoch_test_loss}')

6、结果展示

(1)Adam优化器

(2)SGD优化器

7、总结

 使用不同优化器,对于模型的精确度也是不一样的。

看YOLOv5源码的时候,可以先看.yaml文件,看下Backbone部分→Head部分。

看下总体的模型提,再去细看里面的代码。

收获还是很多的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/598432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux系统下产生Segmentation fault 与 Segmentation fault (core dumped)!!!

最近在学习的过程中,遇到了Segment fault(段错误)的问题,经过一番查找资料,学到了一些相关知识,这里做一个梳理,以防以后在遇到类似的问题,并且希望能够帮助到大家一丝丝&#xff01…

华为AI全栈生态布局:中国科技巨头加速创新

华为AI芯片生态全栈深度分析 2024 一、引言 1.1 华为AI芯片发展背景: 华为,通信和消费电子巨头,以其技术创新和远见著称。2013年,华为率先布局人工智能(AI),并专注于全栈AI解决方案的开发。华…

骨传导耳机哪个品牌值得入手?精选五款高性能骨传导耳机,闭眼入都不踩雷!

随着健康生活的日益普及,运动健身逐渐成为人们生活中的重要组成部分。在这一背景下,骨传导耳机作为一种新型蓝牙耳机,凭借其不堵塞耳道、防水性能强等特性,受到了广大运动爱好者的喜爱。然而,骨传导耳机的热销也吸引了…

一次性邮箱API发送邮件的方法?如何配置?

一次性邮箱API发送邮件有哪些注意事项?怎么安全发信? 随着网络安全问题的日益凸显,如何安全、高效地发送邮件成为了一个亟待解决的问题。一次性邮箱API的出现,为我们提供了一种新的解决方案。那么,如何使用一次性邮箱…

白酒:白酒香型的国际化推广与市场接受度分析

云仓酒庄的豪迈白酒一直有在白酒香型的国际化推广。随着中国白酒市场的不断扩大和国际化的趋势,了解白酒香型的国际接受度和推广策略对于酒厂和整个行业都具有重要意义。 首先,国际化推广需要深入了解国际市场的需求和消费者偏好。不同国家和地区的消费者…

长难句打卡5.7

In December 2010 America’s Federal Trade Commission (FTC) proposed adding a “do not track” (DNT) option to Internet browsers, so that users could tell advertisers that they did not want to be followed. 2010年12月,美国美国联邦贸易委员会(FTC)提…

020、Python+fastapi,第一个Python项目走向第20步:ubuntu 24.04 docker 安装mysql8集群+redis集群(一)

系列文章 pythonvue3fastapiai 学习_浪淘沙jkp的博客-CSDN博客https://blog.csdn.net/jiangkp/category_12623996.html 前言 docker安装起来比较方便,不影响系统整体,和前面虚拟环境有异曲同工之妙,今天把老笔记本T400拿出来装了个ubuntu24…

Spring AOP(3)

目录 Spring AOP原理 代理模式 代理模式中的主要角色 静态代理 动态代理 总结:面试题 什么是AOP? Spring AOP实现的方式有哪些? Spring AOP实现原理 Spring使用的是哪种代理方式? JDK和CGLIB动态代理的区别? Spring AOP原理 代理模式 代理模式, 也叫委托模式. …

CUDA C编程:第一个程序 向量相加

我的电脑没有装CUDA,所以使用租了带GPU的云服务器,然后使用vscode SSH远程连接云服务器。云GPU使用的是智星云,0.8元/h。 智星云 可以使用nvcc --version查看系统中安装的CUDA版本。 然后写第一个CUDA程序,两个向量相加结果给到…

绝地求生:季后赛名额确定!NH战队总积分榜排名第一!

2024年5月5日,PCL春季赛常规赛第五阶段第三天比赛结束,今天打完春季赛常规赛结束,16个战队进入季后赛的名额已确定。NH战队总积分506分,总积分榜排名第一!!NH战队也是唯一一支总积分超过500分的队伍。今天最…

语音识别之其他谱图

⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3077字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号&#xf…

护眼灯有没有护眼的效果?一键查看这五大护眼效果极佳的护眼台灯

在数字时代,护眼灯已成为保护视力的重要工具。但消费者常问:护眼灯有没有护眼的效果?挑选到技术过关的护眼台灯是能够很好地起到护眼效果的。本文将并重点介绍五款具有卓越护眼功能的台灯。这些精选灯具不仅在照明效果上表现出色,…

leetcode-缺失的第一个正整数-96

题目要求 思路 1.这里的题目要求刚好符合map和unordered_map 2.创建一个对应map把元素添加进去,用map.find(res)进行查找,如果存在返回指向该元素的迭代器,否则返回map::end()。 代码实现 class Solution { public:int minNumberDisappeare…

智慧公厕打造智慧城市新标杆

公共厕所作为城市基础设施的重要组成部分,直接关系到市民的生活品质和城市形象。传统的公厕管理方式存在着许多问题,如环境脏乱、清洁不及时等,给市民带来了诸多不便和不满。而智慧公厕作为一种全新的管理模式,通过物联网、大数据…

Temporary Email邮箱API发送邮件怎么配置?

Temporary Email邮箱API发送邮件的方法?如何使用? 临时邮箱因其便捷性和隐私保护的优势,越来越受到用户的青睐。而在许多场景下,我们可能需要使用临时邮箱API来发送邮件。那么,如何配置Temporary Email邮箱API发送邮件…

Docker 操作redis

命令: docker删除容器命令:docker rm 容器名称 (默认只能删除停止运行的容器) 运行redis服务端并指定窗口: docker run --name mr -p 6379:6379 -d redis redis-server --appendonly yes 运行成功之后运行docker ps 可以查看运行中的所有容器以及状态 docke rexec -it mr b…

“A”分心得:我的云计算HCIE学习之路

大家好,我是誉天云计算HCIE周末班梁同学,在誉天老师和同学们的帮助下,我终于在4月24日顺利通过了云计算3.0 HCIE的认证考试,而且获得了A,这是让我特别惊喜的,功夫不负有心人。 我日常的工作是网络运维&…

nestjs 全栈进阶--自定义装饰器

视频教程 20_nest中自定义装饰器_哔哩哔哩_bilibili nest new custom-decorator -p pnpm pnpm start:dev 在Nestjs 中我们使用了大量装饰器 decorator ,所以Nestjs 也允许我们去自定义装饰器。 1. 自定义方法装饰器 nest g decorator aaa --flat 它生产的代码…

基于web的物流管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式 🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 &…

操作系统实战(二)(linux+C语言)

实验内容 通过Linux 系统中管道通信机制,加深对于进程通信概念的理解,观察和体验并发进程间的通信和协作的效果 ,练习利用无名管道进行进程通信的编程和调试技术。 管道pipe是进程间通信最基本的一种机制,两个进程可以通过管道一个在管道一…
最新文章