全球人工智能技术创新大赛【热身赛一】--笔记三--YOLOv5的使用步骤

以全球人工智能技术创新大赛【热身赛一】从头到尾使用YOLOv5

到GitHub上下载源码

到GitHub上下载代码:https://github.com/ultralytics/yolov5
在这里插入图片描述
解压下载后的文件,然后继续在GitHub上下载预训练权重,放到weights文件夹下
下载网址:https://github.com/ultralytics/yolov5/releases
根据自己的需要下载权重
我下载的是s、m、l、x这四个(small、middle、large、max)
在这里插入图片描述
存放到weights文件夹下:
在这里插入图片描述
在这里插入图片描述
我用迅雷下载,速度还是挺快的,建议不要直接使用游览器下载(速度磨人)
在这里插入图片描述

配置所需环境

打开requirements.txt文件可以看到里面有YOLOv5所需环境的版本
在这里插入图片描述
用Linux的终端或者Windows的cmd跳转到YOLOv5所在的目录,然后激活自己的虚拟环境(我直接使用的是base环境),然后执行pip install -r requirements.txt等待安装完成即可。
如果第一次使用pytorch,同时你的电脑配置有显卡,那可以使用cuda,相应的教程那就得百度看看其他资料了,这里就不展开了。

放置这次比赛的数据,并生成YOLOv5所需格式

首先将数据集放到data文件夹下,以全球人工智能技术创新大赛【热身赛一】为例,这个数据我自己稍微整理了一下,主要是将存放标签的json文件和图片文件放到一起(方便整理)。
在这里插入图片描述
然后使用datawhale提供的的baseline的划分数据集的代码:convertTrainLabel.py(根据不同的比赛,不同的数据格式,划分代码需要做相应的修改)
先将这个py文件复制到我们新下载的YOLOv5的文件夹下,然后新建一个文件夹:convertor
然后打开convertTrainLabel.py,修改json_path和image_path为自己存放数据的地址
最后运行。
在这里插入图片描述
运行结束后,convertor下的fold0会出现两个文件夹labels和images,将他们移动到data文件下(我是利用文件的移动,减少对代码的修改,当然也可以选择不移动文件,而是修改代码中的地址)
最终我们处理好数据集会是这样子(这个就是YOLOv5所需要的数据格式,遇到其他不同格式的目标检测比赛,相应的修改成这个格式就能使用了)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在data文件夹下建立一个后缀为yaml的文件

我这里是命名为fabric.yaml,文件内容如下:

#训练集和验证集的路径
train: ./data/images/train/
val: ./data/images/val/

#类别数目
nc: 15

#类别名
names: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12','13', '14', '15']

里面包括的是训练集和验证集图片的路径、类别的数目、这些类别的名称。这个根据题目进行修改,我们这次的布匹检测共有15类所以nc=15

修改train.py文件

找到train.py文件的444行处,一下这部分就是我们的参数设置:
在这里插入图片描述
第一个修改模型,我们选择的是哪个模型呢?(s、m、l、x)
修改这个’–cfg’中的default部分,此刻是使用x模型,如果要使用最小模型就改为yolov5s.yaml

parser.add_argument('--cfg', type=str, default='./models/yolov5x.yaml', help='model.yaml path')

第二个修改预训练权重,使用我们选择的模型相应的预训练模型
修改这个’–weights’中的default部分

parser.add_argument('--weights', type=str, default='./weights/yolov5x.pt', help='initial weights path')

第三个修改data路径
修改这个’–data’中的default部分,该成我们刚刚弄好的yaml文件,根据自己命名去修改

parser.add_argument('--data', type=str, default='./data/fabric.yaml', help='data.yaml path')

第四个修改迭代次数epoch
修改这个’–epochs’中的default部分,想迭代多少次就改为多少

parser.add_argument('--epochs', type=int, default=100)

第五个修改batch_size
修改这个’–batch-size’中的default部分,这个参数的设置需要设置成你机器的GPU个数的倍数,假如你机器GPU个数为3,那这个参数就应该设置为3的倍数。值得注意的是这个参数越大,所需要的显存越大,消耗的资源越大。

parser.add_argument('--batch-size', type=int, default=30, help='total batch size for all GPUs')

第六个可修改GPU编号
修改这个’–device’中的default部分,不一定需要修改,假如只有一个GPU或者无GPU可以使用默认值:‘’。

//这里展示使用的是编号为2的GPU
parser.add_argument('--device', default='2', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')

第七个可修改训练图像的大小
修改这个’–img-size’中的default部分,但是我不太建议一开始修改这个(我是没有修改过的),虽然图像大一些,特征可能多一些,但是相应消耗电脑的资源也变大了。

parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')

修改完以上的内容就可以运行代码开始训练啦!

训练结果

运行结束后,在runs–train目录下有我们执行的结果:
每次训练代码会生成一个exp文件夹,里面有我们的模型(best.pt最好的模型),各种运行报告
值得注意的是,代码不是无限的创建exp文件夹,它最多只会生成到exp10这个文件夹,然后继续训练会不断的覆盖exp10,所以需要养成习惯,每次训练完需要修改这个exp文件夹的名称,可以修改成这次训练的参数设置,这样方便区分、记忆和查看。
在这里插入图片描述

修改detect.py 生成提交结果

detect.py在下载下来的YOLOv5中也是有的,但是呢,上面没有生成json文件的代码,而datawhale提供的baseline中的detect.py是有生成json的。
有两个解决办法:
①修改我们YOLOv5中的detect.py。对比两份detect.py的不同,你会发现就3处有关于json的读写,将这些代码复制过去。
②修改baseline中的detect.py,让其匹配YOLOv5中utils中的工具代码。其实就是修改了读取模块的方式和添加一个类:

import argparse
import glob
import torch.backends.cudnn as cudnn
import json
import cv2
import os
import torch
from utils import google_utils
from utils.general import check_img_size, check_requirements, non_max_suppression, apply_classifier, scale_coords, \
    xyxy2xywh, strip_optimizer, set_logging, increment_path
from utils.datasets import LoadStreams, letterbox
from utils.torch_utils import select_device, load_classifier, time_synchronized
import shutil
import numpy as np
from numpy import random
import time
from pathlib import Path
from models.experimental import attempt_load
from utils.plots import plot_one_box

img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng']
vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv']
class LoadImagesTest:  # for inference
    def __init__(self, path, img_size=640):
        path = str(Path(path))  # os-agnostic
        if os.path.isdir(path):
            files = sorted(glob.glob(os.path.join(path, '*')))
        #charge get all files name
        images = [x for x in files]
        videos = [x for x in files if os.path.splitext(x)[-1].lower() in vid_formats]
        nI, nV = len(images), len(videos)

        self.img_size = img_size
        self.files = images + videos
        self.nF = nI + nV  # number of files
        self.video_flag = [False] * nI + [True] * nV
        self.mode = 'images'
        if any(videos):
            self.new_video(videos[0])  # new video
        else:
            self.cap = None
        assert self.nF > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \
                            (path, img_formats, vid_formats)

    def __iter__(self):
        self.count = 0
        return self

    def __next__(self):
        if self.count == self.nF:
            raise StopIteration
        path = self.files[self.count]

        if self.video_flag[self.count]:
            # Read video
            self.mode = 'video'
            ret_val, img0 = self.cap.read()
            if not ret_val:
                self.count += 1
                self.cap.release()
                if self.count == self.nF:  # last video
                    raise StopIteration
                else:
                    path = self.files[self.count]
                    self.new_video(path)
                    ret_val, img0 = self.cap.read()

            self.frame += 1
            print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nF, self.frame, self.nframes, path), end='')

        else:
            # Read image
            self.count += 1
            path = os.path.join(path, os.path.split(path)[-1]+'.jpg')
            img0 = cv2.imread(path)  # BGR
            assert img0 is not None, 'Image Not Found ' + path
            print('image %g/%g %s: ' % (self.count, self.nF, path), end='')

        # Padded resize
        img = letterbox(img0, new_shape=self.img_size)[0]

        # Convert
        img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416
        img = np.ascontiguousarray(img)

        # cv2.imwrite(path + '.letterbox.jpg', 255 * img.transpose((1, 2, 0))[:, :, ::-1])  # save letterbox image
        return path, img, img0, self.cap

    def new_video(self, path):
        self.frame = 0
        self.cap = cv2.VideoCapture(path)
        self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))

    def __len__(self):
        return self.nF  # number of files

踩坑

我经过数据增强后,进行训练,由于数据量很大,需要训练30分钟一代,然后当我训练到40代的时候,gpu突然丢失了,导致训练断掉了。我发现后立刻使用断点,就是生成的exp–weights文件里的last.pt模型再次进行训练。
然后我重新计算时间,发现剩下的时间只够我训练43个epoch了,所以我将epochs参数生成了43,然后再次执行train.py。我看到它在训练,以为万事大吉了,就溜去干其他事了…
结果代码识别出我是断点,然后从第40个epoch开始训练,最后在第43个epoch停了下来…
就是说我应该将epochs设成83才对!!

我发现的时候已经是第二天早上了…

然后我搜了一下,好像是因为有一个参数:resume,这个是做恢复训练用的。

作为教训,给大伙们提个醒,如果代码断掉,使用断点去训练,一定要看着代码训练几轮,看看是否正常!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值