学习yolov1(初级)

首先给一个模型优化网址 《深度学习之模型优化—理论实践篇》
在看这篇文章的时候《目标检测那点儿事——快到飞起的YOLO-V1》,作者写到:

YOLO-V1的训练也包括面向分类的预训练与面向目标检测的参数微调两个环节。在预训练阶段,YOLO-V1使用的训练数据集也是1000类IMAGENET数据集,使用网络结构上文介绍的目标检测网络有所不同:只采用了前20个卷积层,这些卷积层之后为一个平均池化层和一个全连接层,最终的全连接层输出维度为1000维。
在参数微调阶段,训练数据集也是PASCAL、VOC目标检测数据集(包括20个目标类别),通过将预训练分类网络最后的1000路全连接层替换为4个卷积层和2个全连接层

我们来看一幅图:
在这里插入图片描述
上面这幅图是yolov2的网络结构,但是核心思想没有变:(下面的话读三遍,重点)
YOLO-V1的训练也包括面向分类的预训练与面向目标检测的参数微调两个环节。
在预训练阶段,YOLO-V1使用的训练数据集也是1000类IMAGENET数据集,使用网络结构上文介绍的目标检测网络有所不同:只采用了前20个卷积层,这些卷积层之后为一个平均池化层和一个全连接层,最终的全连接层输出维度为1000维。
在参数微调阶段,训练数据集也是PASCAL、VOC目标检测数据集(包括20个目标类别),通过将预训练分类网络最后的1000路全连接层替换为4个卷积层和2个全连接层

在这个例子中《动手学习深度学习pytorch版——从零开始实现YOLOv1》我们可以看到在实际应用中是怎么将训练好的主干网络加载后,对后面的全连接进行微调。

在“2.2 网络结构实现”中作者这样说:

这一部分需要说明一下,由于原论文是采用自己设计的20层卷积层先在ImageNet上训练了一周,完成特征提取部分的训练。我们作为学习者而非发明者来说,花一周时间训练实在是太长了。因此,在这里我打算对原论文的结构做一点改变。
YOLOv1的前20层是用于特征提取的,也就是随便替换为一个分类网络(除去最后的全连接层)其实都行。因此,我打算使用ResNet34的网络作为特征提取部分。这样做的好处是,pytorch的torchvision中提供了ResNet34的预训练模型,训练集也是ImageNet,等于说有现成训练好的模型可以直接使用,从而免去了特征提取部分的训练时间。然后,除去ResNet34的最后两层,再连接上YOLOv1的最后4个卷积层和两个全连接层,作为我们训练的网络结构。
原文链接:https://blog.csdn.net/weixin_41424926/article/details/105383064

下面网络构建的过程当中,看##########的部分,作者加载了已经训练过分类的resnet34来作为主干网络,并去除了不要的几层,然后在后边加上yolov1的全连接层

import torchvision.models as tvmodel
import torch.nn as nn
import torch

class YOLOv1_resnet(nn.Module):
    def __init__(self):
        super(YOLOv1_resnet,self).__init__()
        #########################################################################################
        resnet = tvmodel.resnet34(pretrained=True)  # 调用torchvision里的resnet34预训练模型
        resnet_out_channel = resnet.fc.in_features  # 记录resnet全连接层之前的网络输出通道数,方便连入后续卷积网络中
        self.resnet = nn.Sequential(*list(resnet.children())[:-2])  # 去除resnet的最后两层
        #########################################################################################
        # 以下是YOLOv1的最后四个卷积层
        self.Conv_layers = nn.Sequential(
            nn.Conv2d(resnet_out_channel,1024,3,padding=1),
            nn.BatchNorm2d(1024),  # 为了加快训练,这里增加了BN层,原论文里YOLOv1是没有的
            nn.LeakyReLU(),
            nn.Conv2d(1024,1024,3,stride=2,padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
        )
        # 以下是YOLOv1的最后2个全连接层
        self.Conn_layers = nn.Sequential(
            nn.Linear(7*7*1024,4096),
            nn.LeakyReLU(),
            nn.Linear(4096,7*7*30),
            nn.Sigmoid()  # 增加sigmoid函数是为了将输出全部映射到(0,1)之间,因为如果出现负数或太大的数,后续计算loss会很麻烦
        )

    def forward(self, input):
        input = self.resnet(input)
        input = self.Conv_layers(input)
        input = input.view(input.size()[0],-1)
        input = self.Conn_layers(input)
        return input.reshape(-1, (5*NUM_BBOX+len(CLASSES)), 7, 7)  # 记住最后要reshape一下输出数据

这是训练部分:

if __name__ == '__main__':
    epoch = 50
    batchsize = 5
    lr = 0.01

    train_data = VOC2012()
    train_dataloader = DataLoader(VOC2012(is_train=True),batch_size=batchsize,shuffle=True)

    model = YOLOv1_resnet().cuda()
    ##########################################################################################
    # model.children()里是按模块(Sequential)提取的子模块,而不是具体到每个层,具体可以参见pytorch帮助文档
    # 冻结resnet34特征提取层,特征提取层不参与参数更新
    for layer in model.children():
        layer.requires_grad = False
        break
    ##########################################################################################
    criterion = Loss_yolov1()
    optimizer = torch.optim.SGD(model.parameters(),lr=lr,momentum=0.9,weight_decay=0.0005)

    is_vis = False  # 是否进行可视化,如果没有visdom可以将其设置为false
    if is_vis:
        vis = visdom.Visdom()
        viswin1 = vis.line(np.array([0.]),np.array([0.]),opts=dict(title="Loss/Step",xlabel="100*step",ylabel="Loss"))

    for e in range(epoch):
        model.train()
        yl = torch.Tensor([0]).cuda()
        for i,(inputs,labels) in enumerate(train_dataloader):
            inputs = inputs.cuda()
            labels = labels.float().cuda()
            pred = model(inputs)
            loss = criterion(pred, labels)
            optimizer.zero_grad()
            #损失函数反向传播
            loss.backward()
            #优化器进行权重优化
            optimizer.step()

            print("Epoch %d/%d| Step %d/%d| Loss: %.2f"%(e,epoch,i,len(train_data)//batchsize,loss))
            yl = yl + loss
            if is_vis and (i+1)%100==0:
                vis.line(np.array([yl.cpu().item()/(i+1)]),np.array([i+e*len(train_data)//batchsize]),win=viswin1,update='append')
        if (e+1)%10==0:
            torch.save(model,"./models_pkl/YOLOv1_epoch"+str(e+1)+".pkl")
            # compute_val_map(model)

网络预测(Inference)

网络预测的主代码和训练其实很像,麻烦的地方在于,网络预测得到pred数据后,如何将其转换为最终的bbox结果。因为pred会得到98个bbox信息,而其中大部分是没用的,但是由于是inference任务,所以没标签给你参照,所以只能用别的算法来去除无效的bbox。最常见的做法就是使用class-specific
confidence
scores的阈值和NMS(非极大值抑制)算法来去除没用的bbox。这种方法有两个超参数,一个是设置class-specific
confidence scores的阈值,另一个是NMS算法中的IOU阈值。

原文链接:https://blog.csdn.net/weixin_41424926/article/details/105383064

如何训练一个分类器呢?
下面是几个例子:
Train a Classifier on CIFAR-10
三维卷积神经网络预测MNIST数字详解
手把手教你用PyTorch从零搭建图像分类模型

你可能感兴趣的:(资料收集,深度学习)