• PyTorch :YOLOv5实战


    相关资料:

    一、环境配置

    1、Python环境

    官网链接:Start Locally | PyTorch

    conda create -n pytorch python==3.7.3
    
    • 1
    pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
    
    • 1

    下的慢/卡死??

    ==>

    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
    
    • 1
    conda install pytorch torchvision
    
    • 1

    2、下载项目

    这里我使用的是5.0版本的代码

    GitHub - ultralytics/yolov5 at v5.0

    在这里插入图片描述

    安装相关依赖:

    pip install -r requirements.txt
    
    • 1

    二、如何利用YOLOv5进行预测

    环境配置好后,我们就可以体验一下YOLOv5了

    $ python detect.py --source 0  # webcam
                                file.jpg  # image 
                                file.mp4  # video
                                path/  # directory
                                path/*.jpg  # glob
                                'https://youtu.be/NUsoVlDFqZg'  # YouTube video
                                'rtsp://example.com/media.mp4'  # RTSP, RTMP, HTTP stream
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    parser = argparse.ArgumentParser()
        parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)')
        parser.add_argument('--source', type=str, default='data/images', help='source')  # file/folder, 0 for webcam
        parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
        parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
        parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
        parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
        parser.add_argument('--view-img', action='store_true', help='display results')
        parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
        parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
        parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
        parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
        parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
        parser.add_argument('--augment', action='store_true', help='augmented inference')
        parser.add_argument('--update', action='store_true', help='update all models')
        parser.add_argument('--project', default='runs/detect', help='save results to project/name')
        parser.add_argument('--name', default='exp', help='save results to project/name')
        parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
        opt = parser.parse_args()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2、体验一下

    python detect.py --source image/1.jpg
    
    • 1

    问题:

    预测后又结果图片,但是并没有框出识别结果

    解决方法:

    我们进入detect.py,在第53行加入

    cudnn.benchmark = True
    
    • 1

    在这里插入图片描述

    效果展示:
    在这里插入图片描述

    报错记录及解决

    AttributeError: Can't get attribute 'SPPF' on models.common' from  '....\\common.py'>
    
    • 1

    有的同学找不到SPPF这个类,那我现在直接粘贴在这里,你们只需要复制到你们的common.py里面即可,记得把import warnings放在上面去:

    models/common.py

    import warnings
    class SPPF(nn.Module):
        # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
        def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
            super().__init__()
            c_ = c1 // 2  # hidden channels
            self.cv1 = Conv(c1, c_, 1, 1)
            self.cv2 = Conv(c_ * 4, c2, 1, 1)
            self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
     
        def forward(self, x):
            x = self.cv1(x)
            with warnings.catch_warnings():
                warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
                y1 = self.m(x)
                y2 = self.m(y1)
                return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    然后:

    AttributeError: 'Upsample' object has no attribute 'recompute_scale_factor'
    
    • 1

    然后我们找到事发现场:

    File "E:\Anaconda3\envs\pytorch\lib\site-packages\torch\nn\modules\upsampling.py", line 154, in forward
        recompute_scale_factor=self.recompute_scale_factor)
    
    • 1
    • 2

    Anaconda3\envs\pytorch\Lib\site-packages\torch\nn\modules

    做出以下修改

        def forward(self, input: Tensor) -> Tensor:
            # return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners,
            #                      recompute_scale_factor=self.recompute_scale_factor)
    
            return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    之后。。。。

    RuntimeError: The size of tensor a (80) must match the size of tensor b (56) at non-singleton dimension 3
    
    • 1

    解决方法:

    下载:
    https://github.com/ultralytics/yolov5/releases/download/v5.0/yolov5s.pt
    替换默认下载的yolov5s.pt,因为默认下载的是V6.1的

    在这里插入图片描述

    替换后,在运行 detect.py就OK了

    然后成功!

    三、自定义数据集训练YOLOv5,并预测

    1、数据准备

    首先我们需要把VOC格式数据集,转换为YOLO格式数据集

    我们统一一下目录结构
    在这里插入图片描述

    运行以下脚本

    voc_to_yolo.py

    需要更改以下 line 9 的 classes,这里我的数据集有俩标签 [“spoil”, “target”]

    import xml.etree.ElementTree as ET
    import pickle
    import os
    from os import listdir, getcwd
    from os.path import join
    import random
    from shutil import copyfile
    
    classes = ["spoil", "target"]
    
    TRAIN_RATIO = 80
    
    
    def clear_hidden_files(path):
        dir_list = os.listdir(path)
        for i in dir_list:
            abspath = os.path.join(os.path.abspath(path), i)
            if os.path.isfile(abspath):
                if i.startswith("._"):
                    os.remove(abspath)
            else:
                clear_hidden_files(abspath)
    
    
    def convert(size, box):
        dw = 1. / size[0]
        dh = 1. / size[1]
        x = (box[0] + box[1]) / 2.0
        y = (box[2] + box[3]) / 2.0
        w = box[1] - box[0]
        h = box[3] - box[2]
        x = x * dw
        w = w * dw
        y = y * dh
        h = h * dh
        return (x, y, w, h)
    
    
    def convert_annotation(image_id):
        in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' % image_id, encoding='utf-8')
        out_file = open('VOCdevkit/VOC2007/YOLOLabels/%s.txt' % image_id, 'w', encoding='utf-8')
        tree = ET.parse(in_file)
        root = tree.getroot()
        size = root.find('size')
        w = int(size.find('width').text)
        h = int(size.find('height').text)
    
        for obj in root.iter('object'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            if cls not in classes or int(difficult) == 1:
                continue
            cls_id = classes.index(cls)
            xmlbox = obj.find('bndbox')
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
                 float(xmlbox.find('ymax').text))
            bb = convert((w, h), b)
            out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
        in_file.close()
        out_file.close()
    
    
    wd = os.getcwd()
    wd = os.getcwd()
    data_base_dir = os.path.join(wd, "VOCdevkit/")
    if not os.path.isdir(data_base_dir):
        os.mkdir(data_base_dir)
    work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
    if not os.path.isdir(work_sapce_dir):
        os.mkdir(work_sapce_dir)
    annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
    if not os.path.isdir(annotation_dir):
        os.mkdir(annotation_dir)
    clear_hidden_files(annotation_dir)
    image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
    if not os.path.isdir(image_dir):
        os.mkdir(image_dir)
    clear_hidden_files(image_dir)
    yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
    if not os.path.isdir(yolo_labels_dir):
        os.mkdir(yolo_labels_dir)
    clear_hidden_files(yolo_labels_dir)
    yolov5_images_dir = os.path.join(data_base_dir, "images/")
    if not os.path.isdir(yolov5_images_dir):
        os.mkdir(yolov5_images_dir)
    clear_hidden_files(yolov5_images_dir)
    yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
    if not os.path.isdir(yolov5_labels_dir):
        os.mkdir(yolov5_labels_dir)
    clear_hidden_files(yolov5_labels_dir)
    yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
    if not os.path.isdir(yolov5_images_train_dir):
        os.mkdir(yolov5_images_train_dir)
    clear_hidden_files(yolov5_images_train_dir)
    yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
    if not os.path.isdir(yolov5_images_test_dir):
        os.mkdir(yolov5_images_test_dir)
    clear_hidden_files(yolov5_images_test_dir)
    yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
    if not os.path.isdir(yolov5_labels_train_dir):
        os.mkdir(yolov5_labels_train_dir)
    clear_hidden_files(yolov5_labels_train_dir)
    yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
    if not os.path.isdir(yolov5_labels_test_dir):
        os.mkdir(yolov5_labels_test_dir)
    clear_hidden_files(yolov5_labels_test_dir)
    
    train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
    test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
    train_file.close()
    test_file.close()
    train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
    test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
    list_imgs = os.listdir(image_dir)  # list image files
    prob = random.randint(1, 100)
    print("Probability: %d" % prob)
    for i in range(0, len(list_imgs)):
        path = os.path.join(image_dir, list_imgs[i])
        if os.path.isfile(path):
            image_path = image_dir + list_imgs[i]
            voc_path = list_imgs[i]
            (nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
            (voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
            annotation_name = nameWithoutExtention + '.xml'
            annotation_path = os.path.join(annotation_dir, annotation_name)
            label_name = nameWithoutExtention + '.txt'
            label_path = os.path.join(yolo_labels_dir, label_name)
        prob = random.randint(1, 100)
        print("Probability: %d" % prob)
        if (prob < TRAIN_RATIO):  # train dataset
            if os.path.exists(annotation_path):
                train_file.write(image_path + '\n')
                convert_annotation(nameWithoutExtention)  # convert label
                copyfile(image_path, yolov5_images_train_dir + voc_path)
                copyfile(label_path, yolov5_labels_train_dir + label_name)
        else:  # test dataset
            if os.path.exists(annotation_path):
                test_file.write(image_path + '\n')
                convert_annotation(nameWithoutExtention)  # convert label
                copyfile(image_path, yolov5_images_test_dir + voc_path)
                copyfile(label_path, yolov5_labels_test_dir + label_name)
    train_file.close()
    test_file.close()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

    2、开始训练

    正常训练,终端输出:

    Image sizes 640 train, 640 test
    Using 0 dataloader workers
    Logging results to runs\train\exp2
    Starting training for 50 epochs...
    0/49     2.88G    0.1165   0.03494   0.03206    0.1835        32       640:  76%|███████▋  | 68/89 [01:24<00:22,  1.07s/it]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    50 epochs completed in 1.430 hours.
    
    Optimizer stripped from runs\train\exp2\weights\last.pt, 14.4MB
    Optimizer stripped from runs\train\exp2\weights\best.pt, 14.4MB
    
    进程已结束,退出代码为 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    报错记录:

    BrokenPipeError: [Errno 32] Broken pipe
    
    • 1
    • 原因:
      在训练过程中,设置的num_workers过大

    • 解决方法:

      utils\datasets.py

      将 line 81 下的 num_workers 改为 0

      num_workers=0
      
      • 1

    3、预测

    修改一下detect.py

     parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp2/weights/best.pt', help='model.pt path(s)')
    
    • 1

    开始预测

    python detect.py --source image/2.jpg
    
    • 1

    在这里插入图片描述

  • 相关阅读:
    这种动态规划你见过吗——状态机动态规划之股票问题(上)
    Tapdata 获得阿里云首批产品生态集成认证,携手阿里云共建新合作
    申请外观设计专利多少钱?
    Python中numpy出现has no attribute '_no_nep50_warning'错误的一个解决方案
    使用libwebsockets搭建一个简单的websocket服务器
    情人节程序员用HTML网页表白【制作属于我们的爱情相册网页】 HTML5七夕情人节表白网页源码 HTML+CSS+JavaScript
    ThreeJS-3D教学三:平移缩放+物体沿轨迹运动
    为什么HashMap的长度要是2的N次方?
    2022年卡塔尔世界杯黑科技盘点
    SpringBoot入门案例
  • 原文地址:https://blog.csdn.net/qq_55535816/article/details/126233398