博客專欄

        EEPW首頁 > 博客 > 一覽YOLOv5中的評價(jià)方式

        一覽YOLOv5中的評價(jià)方式

        發(fā)布人:計(jì)算機(jī)視覺工坊 時(shí)間:2023-02-21 來源:工程師 發(fā)布文章
        前言
        代碼倉庫地址:https://github.com/Oneflow-Inc/one-yolov5歡迎star one-yolov5項(xiàng)目 獲取最新的動(dòng)態(tài)。

        源碼解讀:https://github.com/Oneflow-Inc/one-yolov5/blob/main/val.py 。文章里面的超鏈接可能被公眾號吃掉,可以直接到我們的文檔網(wǎng)站閱讀獲得更好的體驗(yàn):https://start.oneflow.org/oneflow-yolo-doc/source_code_interpretation/val_py.htmlUltralytics YOLOv5 官方給的介紹:

        Validate a model's accuracy on COCO val or test-dev datasets. Models are downloaded automatically from the latest YOLOv5 release. To show results by class use the --verbose flag. Note that pycocotools metrics may be ~1% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation.
        1.導(dǎo)入需要的包和基本配置
        import argparse # 解析命令行參數(shù)模塊
        import json     # 字典列表和JSON字符串之間的相互解析模塊
        import os       # 與操作系統(tǒng)進(jìn)行交互的模塊 包含文件路徑操作和解析
        import sys      # sys系統(tǒng)模塊 包含了與Python解釋器和它的環(huán)境有關(guān)的函數(shù)
        from pathlib import Path  # Path將str轉(zhuǎn)換為Path對象 使字符串路徑易于操作的模塊

        import numpy as np # NumPy(Numerical Python)是Python的一種開源的數(shù)值計(jì)算擴(kuò)展
        import oneflow as flow # OneFlow 深度學(xué)習(xí)框架
        from tqdm import tqdm # 進(jìn)度條模塊
         
        from models.common import DetectMultiBackend # 下面都是 one-yolov5 定義的模塊,在本系列的其它文章都有涉及
        from utils.callbacks import Callbacks
        from utils.dataloaders import create_dataloader
        from utils.general import (
            LOGGER,
            check_dataset,
            check_img_size,
            check_requirements,
            check_yaml,
            coco80_to_coco91_class,
            colorstr,
            increment_path,
            non_max_suppression,
            print_args,
            scale_coords,
            xywh2xyxy,
            xyxy2xywh,
        )
        from utils.metrics import ConfusionMatrix, ap_per_class, box_iou
        from utils.oneflow_utils import select_device, time_sync
        from utils.plots import output_to_target, plot_images, plot_val_study
        2.opt參數(shù)詳解

        參數(shù)解析
        datadataset.yaml path數(shù)據(jù)集配置文件地址 包含數(shù)據(jù)集的路徑、類別個(gè)數(shù)、類名、下載地址等信息
        weightsmodel weights path(s)模型的權(quán)重文件地址 weights/yolov5s
        batch-sizebatch size計(jì)算樣本的批次大小 默認(rèn)32
        imgszinference size (pixels)輸入網(wǎng)絡(luò)的圖片分辨率    默認(rèn)640
        conf-thresconfidence thresholdobject置信度閾值 默認(rèn)0.001
        iou-thresNMS IoU threshold進(jìn)行NMS時(shí)IOU的閾值 默認(rèn)0.6
        tasktrain, val, test, speed or study設(shè)置測試的類型 有train, val, test, speed or study幾種 默認(rèn)val
        devicecuda device, i.e. 0 or 0,1,2,3 or cpu測試的設(shè)備
        workersmax dataloader workers (per RANK in DDP mode)加載數(shù)據(jù)使用的 dataloader workers
        single-clstreat as single-class dataset數(shù)據(jù)集是否只用一個(gè)類別 默認(rèn)False
        augmentaugmented inference測試是否使用TTA Test Time Augment 默認(rèn)False
        verbosereport mAP by class是否打印出每個(gè)類別的mAP 默認(rèn)False
        save-hybridsave label+prediction hybrid results to *.txt保存label+prediction 雜交結(jié)果到對應(yīng).txt 默認(rèn)False
        save-confsave confidences in --save-txt labels
        save-jsonsave a COCO-JSON results file是否按照coco的json格式保存結(jié)果       默認(rèn)False
        projectsave to project/name測試保存的源文件 默認(rèn)runs/val
        namesave to project/name測試保存的文件地址名 默認(rèn)exp  保存在runs/val/exp
        exist-okexisting project/name ok, do not increment是否保存在當(dāng)前文件,不新增 默認(rèn)False
        halfuse FP16 half-precision inference是否使用半精度推理 默認(rèn)False
        dnnuse OpenCV DNN for ONNX inference是否使用 OpenCV DNN 對 ONNX 模型推理

        3.main函數(shù)
        根據(jù)解析的opt參數(shù),調(diào)用run函數(shù)
        def main(opt):
            #  檢測requirements文件中需要的包是否安裝好了
            check_requirements(requirements=ROOT / "requirements.txt", exclude=("tensorboard""thop"))
            
            if opt.task in ("train""val""test"):  # run normally
                if opt.conf_thres > 0.001:  # 更多請見 https://github.com/ultralytics/yolov5/issues/1466
                    LOGGER.info(f"WARNING: confidence threshold {opt.conf_thres} > 0.001 produces invalid results")
                run(**vars(opt))

            else:
                weights = opt.weights if isinstance(opt.weights, list) else [opt.weights]
                opt.half = True  # FP16 for fastest results
                if opt.task == "speed":  # speed benchmarks
                    # python val.py --task speed --data coco.yaml
                    #                --batch 1 --weights yolov5n/ yolov5s/ ...
                    opt.conf_thres, opt.iou_thres, opt.save_json = 0.250.45False
                    for opt.weights in weights:
                        run(**vars(opt), plots=False)

                elif opt.task == "study":  # speed vs mAP benchmarks
                    # python val.py --task study --data coco.yaml
                    #                --iou 0.7 --weights yolov5n/ yolov5s/...
                    for opt.weights in weights:
                        f = f"study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt"
                        x, y = (
                            list(range(2561536 + 128128)),
                            [],
                        )  # x axis (image sizes), y axis
                        # "study": 模型在各個(gè)尺度下的指標(biāo)并可視化,
                        # 上面list(range(256, 1536 + 128, 128)),代表 img-size 的各個(gè)尺度, 具體代碼如下:
                        for opt.imgsz in x:  # img-size
                            LOGGER.info(f"\nRunning {f} --imgsz {opt.imgsz}...")
                            r, _, t = run(**vars(opt), plots=False)
                            y.append(r + t)  # results and times
                        np.savetxt(f, y, fmt="%10.4g")  # save
                    os.system("zip -r study.zip study_*.txt")
                    # 可視化各個(gè)指標(biāo)
                    plot_val_study(x=x)  # plot
        3. run函數(shù)
        https://github.com/Oneflow-Inc/one-yolov5/blob/bf8c66e011fcf5b8885068074ffc6b56c113a20c/val.py#L112-L383
        3.1 載入?yún)?shù)
        # 不參與反向傳播
        @flow.no_grad() 
        def run(
            data, # 數(shù)據(jù)集配置文件地址 包含數(shù)據(jù)集的路徑、類別個(gè)數(shù)、類名、下載地址等信息 train.py時(shí)傳入data_dict
            weights=None,  # 模型的權(quán)重文件地址 運(yùn)行train.py=None 運(yùn)行test.py=默認(rèn)weights/yolov5s
            batch_size=32,  # 前向傳播的批次大小 運(yùn)行test.py傳入默認(rèn)32 運(yùn)行train.py則傳入batch_size // WORLD_SIZE * 2
            imgsz=640,  # 輸入網(wǎng)絡(luò)的圖片分辨率 運(yùn)行test.py傳入默認(rèn)640 運(yùn)行train.py則傳入imgsz_test
            conf_thres=0.001,  # object置信度閾值 默認(rèn)0.001
            iou_thres=0.6,  # 進(jìn)行NMS時(shí)IOU的閾值 默認(rèn)0.6
            task="val",  # 設(shè)置測試的類型 有train, val, test, speed or study幾種 默認(rèn)val
            device="",  # 執(zhí)行 val.py 所在的設(shè)備 cuda device, i.e. 0 or 0,1,2,3 or cpu
            workers=8,  # dataloader中的最大 worker 數(shù)(線程個(gè)數(shù))
            single_cls=False,  # 數(shù)據(jù)集是否只有一個(gè)類別 默認(rèn)False
            augment=False,  # 測試時(shí)增強(qiáng),詳細(xì)請看我們的教程:https://start.oneflow.org/oneflow-yolo-doc/tutorials/03_chapter/TTA.html
            verbose=False,  # 是否打印出每個(gè)類別的mAP 運(yùn)行test.py傳入默認(rèn)Fasle 運(yùn)行train.py則傳入nc < 50 and final_epoch
            save_txt=False,  # 是否以txt文件的形式保存模型預(yù)測框的坐標(biāo) 默認(rèn)True
            save_hybrid=False,  # 是否save label+prediction hybrid results to *.txt  默認(rèn)False
            save_conf=False,  # 是否保存預(yù)測每個(gè)目標(biāo)的置信度到預(yù)測txt文件中 默認(rèn)True
            save_json=False,  # 是否按照coco的json格式保存預(yù)測框,并且使用cocoapi做評估(需要同樣coco的json格式的標(biāo)簽),
                              #運(yùn)行test.py傳入默認(rèn)Fasle 運(yùn)行train.py則傳入is_coco and final_epoch(一般也是False)
            project=ROOT / "runs/val",  # 驗(yàn)證結(jié)果保存的根目錄 默認(rèn)是 runs/val
            name="exp",   # 驗(yàn)證結(jié)果保存的目錄 默認(rèn)是exp  最終: runs/val/exp
            exist_ok=False,  # 如果文件存在就increment name,不存在就新建  默認(rèn)False(默認(rèn)文件都是不存在的)
            half=True,    # 使用 FP16 的半精度推理
            dnn=False,    # 在 ONNX 推理時(shí)使用 OpenCV DNN 后段端
            model=None,   # 如果執(zhí)行val.py就為None 如果執(zhí)行train.py就會(huì)傳入( model=attempt_load(f, device).half() )
            dataloader=None,   # 數(shù)據(jù)加載器 如果執(zhí)行val.py就為None 如果執(zhí)行train.py就會(huì)傳入testloader
            save_dir=Path("")# 文件保存路徑 如果執(zhí)行val.py就為‘’ , 如果執(zhí)行train.py就會(huì)傳入save_dir(runs/train/expn)
            plots=True,  # 是否可視化 運(yùn)行val.py傳入,默認(rèn)True 
            callbacks=Callbacks()
            compute_loss=None, # 損失函數(shù) 運(yùn)行val.py傳入默認(rèn)None 運(yùn)行train.py則傳入compute_loss(train)
        )
        :

        3.2 Initialize/load model and set device(初始化/加載模型以及設(shè)置設(shè)備)
          if training:  # 通過 train.py 調(diào)用的run函數(shù)
                device, of, engine = (
                    next(model.parameters()).device,
                    True,
                    False,
                )  # get model device, OneFlow model
                half &= device.type != "cpu"  # half precision only supported on CUDA
                model.half() if half else model.float()
            else:  # 直接通過 val.py 調(diào)用 run 函數(shù)
                device = select_device(device, batch_size=batch_size)

                # Directories  生成 save_dir 文件路徑  run/val/expn
                save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)  # increment run
                (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

                # 加載模型 只在運(yùn)行 val.py 才需要自己加載model
                model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)
                
                stride, of, engine = model.stride, model.of, model.engine
                # 檢測輸入圖片的分辨率 imgsz 是否能被 stride 整除 
                imgsz = check_img_size(imgsz, s=stride)  # check image size
                half = model.fp16  # FP16 supported on limited backends with CUDA
                if engine:
                    batch_size = model.batch_size
                else:
                    device = model.device
                    if not of:
                        batch_size = 1  # export.py models default to batch-size 1
                        LOGGER.info(f"Forcing --batch-size 1 inference (1,3,{imgsz},{imgsz}) for non-OneFlow models")
                
                # Data
                data = check_dataset(data)  # check
        3.3 Configure
        # 配置
        model.eval() # 啟動(dòng)模型驗(yàn)證模式
        cuda = device.type != "cpu"
        is_coco = isinstance(data.get("val"), str) and data["val"].endswith(f"coco{os.sep}val2017.txt")  # 通過 COCO 數(shù)據(jù)集的文件夾組織結(jié)構(gòu)判斷當(dāng)前數(shù)據(jù)集是否為 COCO 數(shù)據(jù)集
        nc = 1 if single_cls else int(data["nc"])  # number of classes
        # 設(shè)置iou閾值 從0.5-0.95取10個(gè)(0.05間隔)   iou vector for mAP@0.5:0.95
        # iouv: [0.50000, 0.55000, 0.60000, 0.65000, 0.70000, 0.75000, 0.80000, 0.85000, 0.90000, 0.95000]
        iouv = flow.linspace(0.50.9510, device=device)  # iou vector for mAP@0.5:0.95
        niou = iouv.numel() # 示例 mAP@0.5:0.95 iou閾值個(gè)數(shù)=10個(gè),計(jì)算 mAP 的詳細(xì)教程可以在 https://start.oneflow.org/oneflow-yolo-doc/tutorials/05_chapter/map_analysis.html 這里查看
        3.4 Dataloader
        通過 train.py 調(diào)用 run 函數(shù)會(huì)傳入一個(gè) Dataloader,而通過 val.py 需要加載測試數(shù)據(jù)集
        # Dataloader
        # 如果不是訓(xùn)練(執(zhí)行val.py腳本調(diào)用run函數(shù))就調(diào)用create_dataloader生成dataloader
        # 如果是訓(xùn)練(執(zhí)行train.py調(diào)用run函數(shù))就不需要生成dataloader 可以直接從參數(shù)中傳過來testloader
        if not training: # 加載val數(shù)據(jù)集
            if of and not single_cls:  # check --weights are trained on --data
                ncm = model.model.nc
                assert ncm == nc, (
                    f"{weights} ({ncm} classes) trained on different --data than what you passed ({nc} " f"classes). Pass correct combination of" f" --weights and --data that are trained together."
                )
            model.warmup(imgsz=(1 if of else batch_size, 3, imgsz, imgsz))  # warmup
            pad = 0.0 if task in ("speed""benchmark"else 0.5
            rect = False if task == "benchmark" else of  # square inference for benchmarks
            task = task if task in ("train""val""test"else "val"  # path to train/val/test images
            # 創(chuàng)建dataloader 這里的rect默認(rèn)為True 矩形推理用于測試集 在不影響mAP的情況下可以大大提升推理速度
            dataloader = create_dataloader(
                data[task],
                imgsz,
                batch_size,
                stride,
                single_cls,
                pad=pad,
                rect=rect,
                workers=workers,
                prefix=colorstr(f"{task}: "),
            )[0]
        3.5 初始化
        # 初始化驗(yàn)證的圖片的數(shù)量
        seen = 0
        # 初始化混淆矩陣
        confusion_matrix = ConfusionMatrix(nc=nc)

        #  獲取數(shù)據(jù)集所有目標(biāo)類別的類名
        names = dict(enumerate(model.names if hasattr(model, "names"else model.module.names))

        # coco80_to_coco91_class :  converts 80-index (val2014) to 91-index (paper) 
        # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
        class_map = coco80_to_coco91_class() if is_coco else list(range(1000))
        # 設(shè)置進(jìn)度條模塊顯示信息
        s = ("%20s" + "%11s" * 6) % (
            "Class",
            "Images",
            "Labels",
            "P",
            "R",
            "mAP@.5",
            "mAP@.5:.95",
        )
        # 初始化時(shí)間 dt[t0(預(yù)處理的時(shí)間), t1(推理的時(shí)間), t2(后處理的時(shí)間)] 和 p, r, f1, mp, mr, map50, map指標(biāo)
        dt, p, r, f1, mp, mr, map50, map = (
            [0.00.00.0],
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
        )
        #  初始化驗(yàn)證集的損失
        loss = flow.zeros(3, device=device)
        #  初始化 json 文件中的字典, 統(tǒng)計(jì)信息, ap, ap_class 
        jdict, stats, ap, ap_class = [], [], [], []
        callbacks.run("on_val_start")
        # 初始化 tqdm 進(jìn)度條模塊
        pbar = tqdm(dataloader, desc=s, bar_format="{l_bar}{bar:10}{r_bar}{bar:-10b}")

        示例輸出

        val: data=data/coco.yaml, weights=['yolov5x'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, task=val, 
            device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False
            save_conf=False, save_json=True, project=runs/val, name=exp, exist_ok=False, half=True, dnn=False
        YOLOv5 

        *博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請聯(lián)系工作人員刪除。



        關(guān)鍵詞: AI

        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 云南省| 泸州市| 桂东县| 锡林浩特市| 蒲城县| 民县| 萝北县| 晋宁县| 吉木乃县| 辽宁省| 大冶市| 马山县| 敦煌市| 家居| 新竹市| 清原| 亚东县| 安陆市| 利津县| 石家庄市| 吉木乃县| 乐业县| 佳木斯市| 延吉市| 沧源| 胶南市| 房山区| 焦作市| 敦化市| 靖边县| 衡阳县| 西吉县| 义乌市| 沾益县| 澎湖县| 达尔| 容城县| 汶川县| 油尖旺区| 万全县| 阜城县|