欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Pytorch的学习——Yolov3的搭建

程序员文章站 2024-03-17 09:36:04
...

Yolov3的搭建

整个Yolov3一共经历三次下采样三次上采样,最后一共有三个输出,输出的维度分别为[通道数, 8, 8], [通道数, 16, 16], [通道数, 32, 32]

import torch.nn as nn


# yolo的darknet模块
class Darknet(nn.Module):
    def __init__(self, num_in, num_out, ksize, stride=1, padding=1):
        super(Darknet, self).__init__()
        self.conv1 = nn.Conv2d(num_in, num_out, ksize, stride, padding)
        self.bn1 = nn.BatchNorm2d(num_out)
        self.leakyReLU = nn.LeakyReLU(0.1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.leakyReLU(x)
        return x


# 残差模块 同resnet的残差块
class ResidualBlock(nn.Module):
    def __init__(self, num_in, num_out, num_block):
        super(ResidualBlock, self).__init__()
        self.num_block = num_block
        self.dark_conv1 = Darknet(num_in, num_out, ksize=3, stride=2, padding=1)
        self.dark_conv2 = []
        self.convblock = None
        for i in range(self.num_block):
            layers = list([])
            layers.append(Darknet(num_out, num_out//2, ksize=1, stride=1, padding=0))
            layers.append(Darknet(num_out//2, num_out, ksize=3, stride=1, padding=1))
            self.dark_conv2.append(nn.Sequential(*layers))
        self.dark_conv2 = nn.ModuleList(self.dark_conv2)

    def forward(self, x):
        x = self.dark_conv1(x)
        for convblock in self.dark_conv2:
            self.convblock = convblock
            residual = x
            x = self.convblock(x)
            x = x + residual
        return x


# darknet集成模块
class LastLayer(nn.Module):
    def __init__(self, num_in, num_out, num_out2):
        super(LastLayer, self).__init__()
        self.dark_conv1 = Darknet(num_in, num_out, ksize=1, stride=1, padding=0)
        self.dark_conv2 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.dark_conv3 = Darknet(num_out * 2, num_out, ksize=1, stride=1, padding=0)
        self.dark_conv4 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.dark_conv5 = Darknet(num_out * 2, num_out, ksize=1, stride=1, padding=0)

        self.dark_conv6 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.conv7 = nn.Conv2d(num_out * 2, num_out2, 1, stride=1, padding=0)

    def forward(self, x):
        x = self.dark_conv1(x)
        x = self.dark_conv2(x)
        x = self.dark_conv3(x)
        x = self.dark_conv4(x)
        x = self.dark_conv5(x)
        y = self.dark_conv6(x)
        y = self.conv7(y)
        return x, y

# yolov3主体
class Yolov3(nn.Module):
    def __init__(self, num_anchor, num_class):
        super(Yolov3, self).__init__()
        self.dark_conv1 = Darknet(3, 32, ksize=3, stride=1, padding=1)
        self.res1 = ResidualBlock(32, 64, 1)
        self.res2 = ResidualBlock(64, 128, 2)
        self.res3 = ResidualBlock(128, 256, 8)
        self.res4 = ResidualBlock(256, 512, 8)
        self.res5 = ResidualBlock(512, 1024, 4)

        self.last1 = LastLayer(1024, 512, num_anchor * (num_class + 5))

    def forward(self, x):
        x = self.dark_conv1(x)  
        x = self.res1(x) 
        x = self.res2(x) 
        x3 = self.res3(x) 
        x4 = self.res4(x3)  
        x5 = self.res5(x4)
        x, y1 = self.last1(x5)
        x = self.up1(x)
        x = torch.cat((x, x4), 1)
        x,y2 = self.last2(x)
        x = self.up2(x)
        x = torch.cat((x, x3), 1)
        x,y3 = self.last3(x)
        # y1的维度[通道数, 8, 8], y2的维度[通道数, 16, 16], y3的维度[通道数, 32, 32]
        return y1, y2, y3 

该模型没有全连接层需要自己加,根据输出的不同以及输出的维度自己添加

训练

在这边小编只需要维度为[通道数,8,8]的输出信息所以将上面的代码修改了一些

import torch
import torch.nn as nn


class Darknet(nn.Module):
    def __init__(self, num_in, num_out, ksize, stride=1, padding=1):
        super(Darknet, self).__init__()
        self.conv1 = nn.Conv2d(num_in, num_out, ksize, stride, padding)
        self.bn1 = nn.BatchNorm2d(num_out)
        self.leakyReLU = nn.LeakyReLU(0.1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.leakyReLU(x)
        return x


class ResidualBlock(nn.Module):
    def __init__(self, num_in, num_out, num_block):
        super(ResidualBlock, self).__init__()
        self.num_block = num_block
        self.dark_conv1 = Darknet(num_in, num_out, ksize=3, stride=2, padding=1)
        self.dark_conv2 = []
        self.convblock = None
        for i in range(self.num_block):
            layers = list([])
            layers.append(Darknet(num_out, num_out//2, ksize=1, stride=1, padding=0))
            layers.append(Darknet(num_out//2, num_out, ksize=3, stride=1, padding=1))
            self.dark_conv2.append(nn.Sequential(*layers))
        self.dark_conv2 = nn.ModuleList(self.dark_conv2)

    def forward(self, x):
        x = self.dark_conv1(x)
        for convblock in self.dark_conv2:
            self.convblock = convblock
            residual = x
            x = self.convblock(x)
            x = x + residual
        return x


class LastLayer(nn.Module):
    def __init__(self, num_in, num_out, num_out2):
        super(LastLayer, self).__init__()
        self.dark_conv1 = Darknet(num_in, num_out, ksize=1, stride=1, padding=0)
        self.dark_conv2 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.dark_conv3 = Darknet(num_out * 2, num_out, ksize=1, stride=1, padding=0)
        self.dark_conv4 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.dark_conv5 = Darknet(num_out * 2, num_out, ksize=1, stride=1, padding=0)

        self.dark_conv6 = Darknet(num_out, num_out * 2, ksize=3, stride=1, padding=1)
        self.conv7 = nn.Conv2d(num_out * 2, num_out2, 1, stride=1, padding=0)
        self.fc = nn.Linear(8 * 8 * num_out2, 2)

    def forward(self, x):
        x = self.dark_conv1(x)
        x = self.dark_conv2(x)
        x = self.dark_conv3(x)
        x = self.dark_conv4(x)
        x = self.dark_conv5(x)
        y = self.dark_conv6(x)
        y = self.conv7(y)
        y = y.view(y.size(0), -1)
        y = self.fc(y)
        return x, y


class Yolov3(nn.Module):
    def __init__(self, num_anchor, num_class):
        super(Yolov3, self).__init__()
        self.dark_conv1 = Darknet(3, 32, ksize=3, stride=1, padding=1)
        self.res1 = ResidualBlock(32, 64, 1)
        self.res2 = ResidualBlock(64, 128, 2)
        self.res3 = ResidualBlock(128, 256, 8)
        self.res4 = ResidualBlock(256, 512, 8)
        self.res5 = ResidualBlock(512, 1024, 4)

        self.last1 = LastLayer(1024, 512, num_anchor * (num_class + 5))

    def forward(self, x):
        x = self.dark_conv1(x)  
        x = self.res1(x)  
        x = self.res2(x)  
        x3 = self.res3(x)
        x4 = self.res4(x3) 
        x5 = self.res5(x4) 
        x, y1 = self.last1(x5)  
        return y1

# 检验模型
if __name__ == '__main__':
    model = Yolov3(256, 2)
    input = torch.randn(1, 3, 256, 256)
    out = model(input)
    print(out.shape)

train模块

对模型进行训练与测试

import torch
import cv2
import torch.nn as nn
import torch.utils.data
from PIL import Image
import torchvision
import torchvision.transforms as transforms
from model.YoLov3 import Yolov3


# 超参数
EPOCH = 30
BATCH_SIZE = 10
LR = 0.001

IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif', '.tiff', '.webp')


def default_loader(path):
    with open(path, 'rb') as f:
        img = Image.fromarray(cv2.imread(f.name))
        return img


def load_train_data():
    path = "../medias/fire_pictures/train"  # 路径
    train_set = torchvision.datasets.ImageFolder(path,
                                                 transform=transforms.Compose([
                                                     transforms.Resize((256, 256)),
                                                     transforms.ToTensor()]),
                                                 loader=default_loader
                                                 )

    train_loader = torch.utils.data.DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
    return train_loader


def load_test_data():
    path = "../medias/fire_pictures/test"
    test_set = torchvision.datasets.ImageFolder(path,
                                                transform=transforms.Compose([
                                                    transforms.Resize((256, 256)),
                                                    transforms.ToTensor()]),
                                                loader=default_loader
                                                )
    test_loader = torch.utils.data.DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)
    return test_loader


def train(filename, model):
    train_loader = load_train_data()
    with torch.no_grad():
        model = model.cuda()
    optimizer = torch.optim.Adam(model.parameters(), lr=LR)
    loss_func = nn.CrossEntropyLoss()
    for epoch in range(EPOCH):
        for step, (b_x, b_y) in enumerate(train_loader):
            if torch.cuda.is_available():
                with torch.no_grad():
                    b_x = b_x.cuda()
                    b_y = b_y.cuda()
            output = model(b_x)
            loss = loss_func(output, b_y)
            optimizer.zero_grad()  
            loss.backward() 
            optimizer.step() 

            if step % 50 == 0:
                print('Epoch: ', epoch)
    cnn = model .cpu()
    torch.save(cnn, '../network/' + filename)


def test(filename):
    cnn = torch.load('./network/' + filename).cuda()
    test_loader = load_test_data()
    data_iter = iter(test_loader)
    images, labels = data_iter.__next__()
    outputs = cnn(images.cuda())
    predicted = torch.softmax(outputs, 1)
    p = torch.max(predicted, 1)
    print(p[1].cpu().numpy(), labels.cpu().numpy())
    j = 0
    for i in range(len(p[1].cpu().numpy())):
        a = int(p[1].cpu().numpy()[i]) - int(labels.cpu().numpy()[i])
        if a == 0:
            j += 1
    print(j / BATCH_SIZE)


if __name__ == '__main__':
    yolo = Yolov3(256, 2)
    train("yolov3_fire_256.pkl", yolo)


相关标签: python Pytorch