365天深度学习打卡 第P9周:YOLOv5的backbone实现

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

文章目录

  • 一、Backbone模块代码
    • 1.1 Conv模块
    • 1.2 C3模块
    • Bottleneck模块
    • SPPF模块
  • 二、数据集和相关参数设置
    • 2.1 数据集操作
    • 2.2 相关参数设置
    • 2.3 定义Backbone网络
  • 三、训练及结果可视化
    • 3.1 训练及测试代码
    • 3.2 训练循环代码
    • 3.3 训练结果可视化

一、Backbone模块代码

1.1 Conv模块

def autopad(k, p=None):                        # kernel  padding 根据卷积核大小k自动计算卷积核padding数(0填充)
    """
    :param k: 卷积核的 kernel_size
    :param p: 卷积的padding  一般是None
    :return:  自动计算的需要pad值(0填充)
    """
    if p is None:
        # k 是 int 整数则除以2, 若干的整数值则循环整除
        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, act=True, g=1):
        """
        :param c1: 输入的channel值
        :param c2: 输出的channel值
        :param k: 卷积的kernel_size
        :param s: 卷积的stride
        :param p: 卷积的padding  一般是None
        :param act: 激活函数类型   True就是SiLU(), False就是不使用激活函数
        :param g: 卷积的groups数  =1就是普通的卷积  >1就是深度可分离卷积
        """
        super(Conv, self).__init__()

        self.conv_1 = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=True)
        self.bn = nn.BatchNorm2d(c2)

        self.act = nn.SiLU() if act else nn.Identity()     # 若act=True, 则激活,  act=False, 不激活

    def forward(self, x):

        return self.act(self.bn(self.conv_1(x)))

1.2 C3模块

class C3(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        """
        :param c1: 整个 C3 的输入channel
        :param c2: 整个 C3 的输出channel
        :param n: 有n个Bottleneck
        :param shortcut: bool Bottleneck中是否有shortcut,默认True
        :param g: C3中的3x3卷积类型  =1普通卷积  >1深度可分离卷积
        :param e: expansion ratio
        """
        super(C3, self).__init__()
        c_ = int(c2 * e)
        self.cv_1 = Conv(c1, c_, 1, 1)
        self.cv_2 = Conv(c1, c_, 1, 1)
        # *操作符可以把一个list拆开成一个个独立的元素,然后再送入Sequential来构造m,相当于m用了n次Bottleneck的操作
        self.m = nn.Sequential(*[Bottleneck(c_, c_, e=1, shortcut=True, g=1) for _ in range(n)])
        self.cv_3 = Conv(2*c_, c2, 1, 1)

    def forward(self, x):
        return self.cv_3(torch.cat((self.m(self.cv_1(x)), self.cv_2(x)), dim=1))

Bottleneck模块

class Bottleneck(nn.Module):
    def __init__(self, c1, c2, e=0.5, shortcut=True, g=1):
        """
        :param c1: 整个Bottleneck的输入channel
        :param c2: 整个Bottleneck的输出channel
        :param e: expansion ratio  c2*e 就是第一个卷积的输出channel=第二个卷积的输入channel
        :param shortcut: bool Bottleneck中是否有shortcut,默认True
        :param g: Bottleneck中的3x3卷积类型  =1普通卷积  >1深度可分离卷积
        """
        super(Bottleneck, self).__init__()

        c_ = int(c2*e)                            # 使通道减半, c_具体多少取决于e
        self.conv_1 = Conv(c1, c_, 1, 1)
        self.conv_2 = Conv(c_, c2, 3, 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        return x + self.conv_2(self.conv_1(x)) if self.add else self.conv_2(self.conv_1(x))

SPPF模块

class SPPF(nn.Module):
    def __init__(self, c1, c2, k=5, e=0.5):
        """
        :param c1: 输入通道
        :param c2: 输出通道
        :param k:  池化的卷积核
        :param e:  用于控制中间的通道
        """
        super(SPPF, self).__init__()

        c_ = int(c2 * e)
        self.conv1 = Conv(c1, c_, 1, 1)

        self.pool_1 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
        self.pool_2 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
        self.pool_3 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)

        self.conv2 = Conv(4*c_, c2, 1, 1)

    def forward(self, x):
        x_1 = self.conv1(x)
        x_2 = self.pool_1(x_1)
        x_3 = self.pool_2(x_2)
        x_4 = self.pool_3(x_3)
        # dim=1的原因: (batch, channels, height, width)
        # 为什么在channels连接, 因为cat前图片的 height, width一致
        return self.conv2(torch.cat((x_1, x_2, x_3, x_4), dim=1))

二、数据集和相关参数设置

2.1 数据集操作

import torch
from torch import nn
import datetime
import matplotlib.pyplot as plt
import copy
from torch.utils.data import DataLoader
import torchvision
from torchvision.transforms import ToTensor, transforms


total_dir = './weather_photos/'

transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(std=[0.5, 0.5, 0.5], mean=[0.5, 0.5, 0.5])
])

total_data = torchvision.datasets.ImageFolder(total_dir, transform)
print(total_data)
print(total_data.class_to_idx)

idx_to_class = dict((v, k) for k,v in total_data.class_to_idx.items())
print(idx_to_class)

train_size = int(len(total_data) * 0.8)
test_size = int(len(total_data)) - train_size

train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])

train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=32, shuffle=True)

2.2 相关参数设置

device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = YOLOv5_backbone().to(device)
lr_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=lr_rate)
loss_fn = nn.CrossEntropyLoss()

def printlog(info):
    nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print("\n"+"=========="*8 + "%s"%nowtime)
    print(str(info)+"\n")


def adjust_learn_rate(optimizer, epoch, lr_rate):

    lr = lr_rate*(0.9**(epoch // 5))
    for p in optimizer.param_groups:
        p['lr'] = lr

2.3 定义Backbone网络

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

        self.c_1 = Conv(3, 64, 3, 2, 2)
        self.c_2 = Conv(64, 128, 3, 2)
        self.c3_3 = C3(128, 128, 1)
        self.c_4 = Conv(128, 256, 3, 2)
        self.c3_5 = C3(256, 256, 1)
        self.c_6 = Conv(256, 512, 3, 2)
        self.c3_7 = C3(512, 512, 1)
        self.c_8 = Conv(512, 1024, 3, 2)
        self.c3_9 = C3(1024, 1024, 1)
        self.sppf = SPPF(1024, 1024, 5)
        self.linear = nn.Sequential(
            nn.Linear(65536, 1000),
            nn.ReLU(),

            nn.Linear(1000, 4)
        )

    def forward(self, x):
        x = self.c_1(x)
        x = self.c_2(x)
        x = self.c3_3(x)
        x = self.c_4(x)
        x = self.c3_5(x)
        x = self.c_6(x)
        x = self.c3_7(x)
        x = self.c_8(x)
        x = self.c3_9(x)
        x = self.sppf(x)
        x = x.view(-1, 65536)
        x = self.linear(x)
        return x


三、训练及结果可视化

3.1 训练及测试代码

def train(train_dataloader, model, loss_fn, optimizer):
    size = len(train_dataloader.dataset)
    num_of_batch = len(train_dataloader)
    train_correct, train_loss = 0.0, 0.0
    for x, y in train_dataloader:
        x, y = x.to(device), y.to(device)
        pre = model(x)
        loss = loss_fn(pre, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        with torch.no_grad():
            train_correct += (pre.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()

    train_correct /= size
    train_loss /= num_of_batch
    return train_correct, train_loss


def test(test_dataloader, model, loss_fn):
    size = len(test_dataloader.dataset)
    num_of_batch = len(test_dataloader)
    test_correct, test_loss = 0.0, 0.0
    with torch.no_grad():
        for x, y in test_dataloader:
            x, y = x.to(device), y.to(device)
            pre = model(x)
            loss = loss_fn(pre, y)
            test_loss += loss.item()
            test_correct += (pre.argmax(1) == y).type(torch.float).sum().item()

    test_correct /= size
    test_loss /= num_of_batch
    return test_correct, test_loss

3.2 训练循环代码

epochs = 50
train_acc = []
train_loss = []
test_acc = []
test_loss = []
best_acc = 0.0
for epoch in range(epochs):
    printlog("Epoch {0} / {1}".format(epoch, epochs))
    model.train()
    epoch_train_acc, epoch_train_loss = train(train_dataloader, model, loss_fn, optimizer)

    adjust_learn_rate(optimizer, epoch, lr_rate)

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

    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)
    # 保存最佳模型
    # if epoch_test_acc > best_acc:
        # best_acc = epoch_test_acc
        # best_model = copy.deepcopy(model)

    template = ("train_acc:{:.5f}, train_loss:{:.5f}, test_acc:{:.5f}, test_loss:{:.5f}")
    print(template.format(epoch_train_acc, epoch_train_loss, epoch_test_acc, epoch_test_loss))
print('done')

plt.plot(range(epochs), train_loss, label='train_loss')
plt.plot(range(epochs), train_acc, label='train_acc')
plt.plot(range(epochs), test_loss, label='test_loss')
plt.plot(range(epochs), test_acc, label='test_acc')
plt.legend()
plt.show()
print('done')

# path = './best_path'
# torch.save(best_model.state_dict(), path)
# print('Done')


3.3 训练结果可视化

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python修改密码:一种安全可靠、快速高效的方式

Python 修改密码:一种安全可靠、快速高效的方式 在数字化时代,越来越多的信息被存储在计算机系统中,因此密码的保护变得尤为重要。人们需要保证他们的密码是安全可靠的,并定期更换密码。Python作为一种强大而且通用的编程语言&am…

Unity用鼠标拖拽UI,UI跟随鼠标移动

Unity用鼠标拖拽UI,UI跟随鼠标移动 效果一、原理二、源码总结💢💢版权声明 效果 先上效果 一、原理 继承几个拖拽的接口 IBeginDragHandler, IDragHandler,IEndDragHandler 计算下偏移量,转换下坐标系 限制下可拖拽的范围&…

Tensorflow2基础代码实战系列之时间序列预测任务

深度学习框架Tensorflow2系列 注:大家觉得博客好的话,别忘了点赞收藏呀,本人每周都会更新关于人工智能和大数据相关的内容,内容多为原创,Python Java Scala SQL 代码,CV NLP 推荐系统等,Spark …

实时时钟 RTC

概述 实时时钟(RTC) 模块可长时间维持精确计时,为系统提供实时时钟和日历。该模块功耗极低,最大程度延长电池寿命。 RTC的主要特点: ⚫ BCD 时间 格式 ,完整万年历 ⚫ 支持数字调校, 最高 精度可达 0. 06 ppm ⚫ 可输出…

作为996社畜,如何自学Python?一文讲清楚

作为996社畜,应该如何自学Python?今天就给大家分享一下,工作之余,应该如何学习Python? 1. 明确目标 对于零基础的学员而言,要明确你学习Python仅仅是为了满足好奇心?还是有工作需要&#xff0c…

如何使用ArcGIS制作气温空间分布图

本文使用ArcMap10.2,以湖北省为例,通过空间插值,制作湖北省1981-2010年20年平均气温空间分布图 树谷资料库资源大全 1 数据准备 可在中国气象数据网下载湖北省1981-2010共20年的各区站累年平均气温数据和各区站经纬度数据。打开为txt格式 在…

【三】设计模式~~~创建型模式~~~抽象工厂模式(Java)

【学习难度:★★★★☆,使用频率:★★★★★】 3.1. 模式动机 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中…

【计算机网络】网络基础(一)

首先声明:这是开发中用到的网络的知识点,侧重点在于编程实践,不重视概念。网络基础不在于细节,在于构建宏观的结构。后面重点在于网络套接字编程!!!!! 目录 1.背景知识 …

经典文献阅读之--ERASOR(栅格占用过滤动态障碍物)

0. 简介 之前作者在《激光雷达动态障碍物滤除-调研与展望》以及《3D帧间匹配-----剔除动态障碍物》中提到了如何通过各种方法来完成动态障碍物的滤波。而本文也将围绕着如何完成动态障碍物滤波来展开,来介绍《ERASOR: Egocentric Ratio of Pseudo Occupancy-based …

CentOS系统如何开展爬虫工作

CentOS 系统可以用于进行爬虫工作。实际上,很多大型网站和在线服务都运行在 Linux 系统下,包括 CentOS、Ubuntu、Debian 等,因此 CentOS 系统也常用于进行爬虫工作。 在CentOS系统上开展爬虫工作,可以按照以下步骤进行&#xff1a…

CESSCN安全设计与集成一级-中国通信企业协会通信网络安全服务能力评定证书

通信网络安全设计与集成服务能力评定是依据《通信网络安全防护管理办法》、《电信网与互联网第三方安全服务评定准则》YD/T2669-2013、以及《通信网络安全服务能力评定管理办法》的具体要求,对通信网络安全服务单位的技术能力、服务能力、质量保证能力、人员构成与素…

智能路由器开发之OpenWrt简介

智能路由器开发之OpenWrt简介 1. 引言 1.1 智能路由器的重要性和应用场景 智能路由器作为网络通信的核心设备,具有重要的地位和广泛的应用场景。传统的路由器主要提供基本的网络连接功能,但随着智能家居、物联网和大数据应用的快速发展,对于…

池州控股集团财务共享项目启动啦!

近日,由用友网络承建的池州市投资控股集团有限公司财务共享项目启动会成功举办,也标志着池州控股集团财务共享项目正式启动!池州控股集团总经理刘俊、用友国资事业部总经理汪发清及其他相关专家和项目组主要成员参加了此次启动会。 池州投控集…

100种思维模型之全局观思维模型-67

全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。 01、何谓全局观思维模型 一、全局观思维 什么叫全局观? 世界上的所有东西,都是被规律作用者的&#xff0c…

Linux网络基础-5

在上一篇博客中我们对网络层的典型协议--IP进行了介绍,那么本篇博客作为网络方面的最后一片博客,我们对网络中最后内容--链路层协议进行讲解。 目录 1.链路层协议 1.1MAC地址 1.1.1类型 1.1.2作用 1.2以太网协议 1.2.1协议格式 1.2.2ARP协议 1.…

现场直击 | 沈阳新技术交流会,实景三维再“出圈”

5月19日,由中国测绘学会、中国地理信息产业协会指导,辽宁省测绘地理信息学会、辽宁省土地学会地理信息专业委员会主办,武汉大势智慧科技有限公司、沈阳市勘察测绘研究院有限公司承办的“全自主、全流程、全覆盖”2023实景三维新技术交流会沈阳…

QT桌面项目(日历程序)

文章目录 前言一、QCalendarWidget介绍二、日历代码实现总结 前言 本篇文章继续为大家讲解QT桌面项目,那么这篇文章我们将实现一个日历程序。在QT中要想实现一个简单的日历程序是非常简单的,使用QT中自带的QCalendarWidget类即可实现。 一、QCalendarW…

LAMP的部署(天光渐暗,暮色里遗漏了一丝蓝,星辰便从中亮起。)

一、LAMP架构概述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词,具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP&#…

阻抗板是否高可靠,华秋有话说

随着高频高速电子产品的快速发展,信号传输过程更容易出现反射、串扰等信号完整性问题,且频率越高、传输速率越快,信号损耗越严重,如何降低信号在传输过程中的损耗、保证信号完整性是高频高速PCB发展中的巨大挑战。 在高速PCB设计…

USB主机枚举设备

https://space.bilibili.com/489340606/channel/collectiondetail?sid896957 以下图片来自于沁恒微电子蔡亮工程师的讲课,对USB开发入门很有好处。 1. USB设备的组成结构 一个设备可以有多个配置,但同一时刻只能有一个生效。一个配置可以有多个接口&a…