深度学习 08 — YOLOv5-C3模块实现

🍨 本文为[🔗365天深度学习训练营]中的学习记录博客

🍖 原作者:[K同学啊]

一、 前期准备

1. 设置GPU

如果设备上支持GPU就使用GPU,否则使用CPU

import torch
import torchvision 
import torch.nn as nn
import os,PIL,pathlib,warnings
import torchvision.transforms as transforms
from torchvision import transforms, datasets

warnings.filterwarnings("ignore")

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device 

2.导入数据 

data_dir = "/content/drive/MyDrive/Colab Notebooks/data"
data_dir = pathlib.Path(data_dir)

data_path = list(data_dir.glob('*'))
data_path
classeName = [str(path).split('/')[-1] for path in data_path]
classeName = [name for name in classeName if name != ".DS_Store"]
classeName

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("/content/drive/MyDrive/Colab Notebooks/data",transform=train_transforms)
total_data

 

 3.划分数据集

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

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

batch_size = 32

train_dl = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,num_workers=1)

test_dl = torch.utils.data.DataLoader(test_dataset,batch_size=batch_size,shuffle=True,num_workers=1)
for X,y in test_dl:
    print("Shape of X [N,C,H,W]: ",X.shape)
    print("Shape of y: ",y.shape,y.dtype)
    break

二、搭建包含C3模块的模型

1. 搭建模型 

import torch.nn.functional as F 

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)
        self.add = shortcut and c1 == c2 
    
    def forward(self,x):
        out = self.cv2(self.cv1(x))
        return x + out if self.add else out


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

        self.Conv = Conv(3,32,3,2)

        self.C3_1 = C3(32,64,3)

        self.classifier = nn.Sequential(
            nn.Linear(in_features=802816,out_features=100),
            nn.ReLU(),
            nn.Linear(in_features=100,out_features=4)
        )

    def forward(self,x):
        x = self.Conv(x)
        x = self.C3_1(x)
        x = torch.flatten(x,start_dim=1)
        x = self.classifier(x)

        return x

device = "cuda" if torch.cuda.is_available() else "cpu"

print(f'Using {device} device')

model = model_K().to(device)
model
Using cuda device
model_K(
  (Conv): Conv(
    (conv): Conv2d(3, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (act): SiLU()
  )
  (C3_1): C3(
    (cv1): Conv(
      (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (act): SiLU()
    )
    (cv2): Conv(
      (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (act): SiLU()
    )
    (cv3): Conv(
      (conv): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (act): SiLU()
    )
    (m): Sequential(
      (0): Bottleneck(
        (cv1): Conv(
          (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
        (cv2): Conv(
          (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
      )
      (1): Bottleneck(
        (cv1): Conv(
          (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
        (cv2): Conv(
          (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
      )
      (2): Bottleneck(
        (cv1): Conv(
          (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
        (cv2): Conv(
          (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
          (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          (act): SiLU()
        )
      )
    )
  )
  (classifier): Sequential(
    (0): Linear(in_features=802816, out_features=100, bias=True)
    (1): ReLU()
    (2): Linear(in_features=100, out_features=4, bias=True)
  )
)
import torchsummary as summary 

summary.summary(model,(3,224,224))

 

三、训练模型

1.编写训练模型


def train(dataloader,model,loss_fn,optimizer):

    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    train_acc,train_loss = 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()
        loss.backward()
        optimizer.step()

        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
    

2.编写测试函数

def test(dataloader,model,loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    test_acc,test_loss = 0,0

    with torch.no_grad():
        for imgs,target in dataloader:

            imgs,target = imgs.to(device), target.to(device)

            target_pred = model(imgs)
            loss = loss_fn(target_pred,target)

            test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()

            test_loss += loss.item()

    test_acc /= size
    test_loss /= num_batches

    return test_acc,test_loss
    

3.正式训练

import copy

optimizer = torch.optim.Adam(model.parameters(),lr=1e-4)

loss_fn = nn.CrossEntropyLoss()

epochs = 20 

train_acc = []
train_loss = []
test_acc = []
test_loss = []

best_loss = 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)

    if epoch_test_acc > best_loss:
        best_loss = epoch_test_acc
        best_model = copy.deepcopy(model)

    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_test_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(model.state_dict(),PATH)

print("Done")

 四、结果可视化

1.Loss 与 Accuracy图

import matplotlib.pyplot as plt 
import warnings 

warnings.filterwarnings("ignore")

epoch_range = range(epochs)

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

plt.subplot(121)

plt.plot(epoch_range,train_acc,label="Training Accuracy")
plt.plot(epoch_range,test_acc,label="Test Accuracy")
plt.legend(loc='lower right')
plt.title("Training and Validation Accuracy")

plt.subplot(122)
plt.plot(epoch_range,train_loss,label="Training Loss")
plt.plot(epoch_range,test_loss,label="Test Loss")
plt.legend(loc='upper right')
plt.show()

 2.模型评估

best_model.eval()

epoch_test_acc, epoch_test_loss = test(test_dl,best_model,loss_fn)

epoch_test_acc,epoch_test_loss

epoch_test_acc

五、个人总结

1. 了解 YOLOv5  

在本次实战中,初步了解了YOLOv5 模型的整体架构,并且使用了其中C3模块来搭建模型

理解了C3模块的工作原理 C3 类是一个自定义的神经网络模块,,并且集成了多个卷积层和瓶颈模块。C3 是由三层卷积和n个瓶颈模块组成的这些瓶颈模块可以提升特征提取能力,同时利用残差连接来避免深层网络中的梯度消失问题,并且C3 模块的设计允许网络通过多个路径学习输入数据的特征,通过并行和连续的结构来提取不同的特征,并在最后通过合并层综合这些特征,从而丰富特征表示,增强模型的学习能力。

增加C3模块与Conv模块

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

        self.Conv = Conv(3,32,3,2)

        self.C3_1 = C3(32,64,3)

        self.Conv2 = Conv(64,128,3,2)

        self.C3_2 = C3(128,256,3)

        self.classifier = nn.Sequential(
            nn.Linear(in_features=802816,out_features=100),
            nn.ReLU(),
            nn.Linear(in_features=100,out_features=4)
        )

    def forward(self,x):
        x = self.Conv(x)
        x = self.C3_1(x)
        
        x = self.Conv2(x)
        x = self.C3_2(x)

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

        return x

 

在增加两个新的模块后发现模型的准确率并没有提高反而下降了,这是有可能增加了网络的复杂性,可能导致模型在训练集上过拟合,而在测试集或验证集上的泛化能力变差。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值