• 基于YOLOv5、YOLOv8的烟雾报警检测(超实用项目)


    目录

    1.简介

    2.YOLO算法

    3.基于YOLOv5、YOLOv8的烟雾检测报警系统

    3.1gui界面主代码 

    3.2YOLOv5主代码


    视频已上传b站 

    YOLOv5、YOLOv8检测-烟雾检测报警系统_哔哩哔哩_bilibili

    本文为系列专栏,包括各种YOLO检测算法项目、追踪算法项目、双目视觉、深度结构光相机测距测速三维测量项目等

    专栏持续更新中,有需要的小伙伴可私聊,接项目定制。

    1.简介

    随着科技的不断发展,人工智能技术在各个领域得到广泛应用。其中,计算机视觉是人工智能领域中的一个重要分支,它主要研究如何使机器“看”和“理解”图像或视频。在计算机视觉领域,目标检测是一个关键问题,它涉及识别图像或视频中的特定对象,并确定它们的位置。烟雾检测作为目标检测的一个重要应用领域,对于及时发现火灾、减少人员伤亡和财产损失具有重要意义。

    1. 火灾安全:烟雾是火灾初期最常见且最早的指示物之一。快速准确地检测和报警可以帮助尽早采取适当的措施,以防止火灾蔓延和减少损失。通过基于YOLOv5的烟雾报警系统,可以实现实时、高效的烟雾检测,提供及时的火灾预警。

    2. 人员安全:烟雾中的有害气体和毒素可能对人体健康产生严重威胁。火灾发生时,人们通常可能会处于迷惘或恐慌状态,很难准确判断烟雾的存在和危害程度。一个可靠的烟雾报警系统可以提供及早的警示,帮助人们采取必要的行动,增加人员的逃生机会。

    3. 资产保护:火灾造成的财产损失往往巨大。通过及时发现和报警,可以提高火灾发生时应对的效率,减少财产损失。基于YOLOv5的烟雾报警系统可以实现对大范围区域进行监控和烟雾检测,可以在火灾发生前尽早发出警报,有助于及时采取措施保护财产。

    4. 自动化和智能化:基于YOLOv5的烟雾报警系统能够利用计算机视觉技术自动实现烟雾检测,无需人工干预,并能够实现高精度的目标检测。这种系统的自动化和智能化特性可以降低人力成本,提高检测效率和准确性。

    总之,基于YOLOv5的烟雾报警系统对于火灾安全、人员安全、资产保护以及自动化智能化等方面都具有重要的背景意义,可以提高火灾预警和处理的效率,减少火灾带来的损失。

    本项目旨在基于YOLOv5和YOLOv8这两个先进的目标检测模型,开展火灾检测的研究和应用。YOLO(You Only Look Once)是一种实时目标检测算法,它将目标检测任务转化为一个回归问题,通过单次前向传递神经网络即可得到图像中所有目标的类别和位置。YOLOv5是YOLO系列中的最新版本,它在精度和速度之间取得了很好的平衡,被广泛应用于各种实时目标检测任务。

    在本项目中,我们将探讨火灾检测领域的挑战和需求,介绍YOLOv5和YOLOv8的基本原理和算法结构,以及在实际火灾检测场景中的应用。通过本项目的研究,我们希望能够为提高火灾检测的准确性和效率,保障人们的生命财产安全,做出积极贡献。

    希望本项目能够为火灾检测领域的研究和实际应用提供有益的参考和启示,推动人工智能技术在火灾安全领域的进一步发展和应用。

    2.YOLO算法

    YOLO(You Only Look Once)是一种高效的实时目标检测算法,它将目标检测任务转化为一个回归问题,通过单次前向传递神经网络即可得到图像中所有目标的类别和位置。相较于传统的目标检测方法,YOLO具有更快的速度和较高的准确性,使其成为计算机视觉领域中的重要算法之一。

    YOLO算法的基本思想是将输入图像划分为一个固定大小的网格(grid),每个网格负责预测图像中是否包含目标以及目标的位置和类别。与传统的滑动窗口方法不同,YOLO将目标检测任务转化为一个回归问题,同时预测所有目标的位置和类别,避免了重复计算,因此速度更快。

    以下是YOLO算法的主要特点和步骤:

    划分网格: 将输入图像划分为SxS个网格,每个网格负责预测该网格内是否包含目标。

    预测框和类别: 每个网格预测B个边界框(bounding boxes)以及每个边界框的置信度(confidence)和类别概率。置信度表示边界框的准确性,类别概率表示目标属于不同类别的概率。

    计算损失函数: YOLO使用多任务损失函数,包括边界框坐标的回归损失、置信度的损失(包括目标是否存在的损失和目标位置的精度损失)、类别概率的损失。通过最小化这些损失,网络可以学习到准确的目标位置和类别信息。

    非极大值抑制(NMS): 在预测结果中,可能存在多个边界框对同一个目标的重复检测。为了去除这些重叠的边界框,使用NMS算法来选择具有最高置信度的边界框,并消除与其IoU(交并比)高于阈值的其他边界框。

    输出结果: 最终,YOLO输出图像中所有目标的位置和类别信息,以及它们的置信度分数。

    YOLO的优势在于它的速度和准确性,它能够实时处理高分辨率的图像,并且在不同尺度和大小的目标上具有很好的泛化能力。这使得YOLO广泛应用于实时目标检测、视频分析、自动驾驶等领域。

    3.基于YOLOv5、YOLOv8的烟雾检测报警系统

    部分代码展示

    3.1gui界面主代码 

    1. from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMenu, QAction
    2. from main_win.win import Ui_mainWindow
    3. from PyQt5.QtCore import Qt, QPoint, QTimer, QThread, pyqtSignal
    4. from PyQt5.QtGui import QImage, QPixmap, QPainter, QIcon
    5. import sys
    6. import os
    7. import json
    8. import numpy as np
    9. import torch
    10. import torch.backends.cudnn as cudnn
    11. import os
    12. import time
    13. import cv2
    14. from models.experimental import attempt_load
    15. from utils.datasets import LoadImages, LoadWebcam
    16. from utils.CustomMessageBox import MessageBox
    17. # LoadWebcam 的最后一个返回值改为 self.cap
    18. from utils.general import check_img_size, check_requirements, check_imshow, colorstr, non_max_suppression, \
    19. apply_classifier, scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box
    20. from utils.plots import colors, plot_one_box, plot_one_box_PIL
    21. from utils.torch_utils import select_device, load_classifier, time_sync
    22. from utils.capnums import Camera
    23. from dialog.rtsp_win import Window
    24. class DetThread(QThread):
    25. send_img = pyqtSignal(np.ndarray)
    26. send_raw = pyqtSignal(np.ndarray)
    27. send_statistic = pyqtSignal(dict)
    28. # 发送信号:正在检测/暂停/停止/检测结束/错误报告
    29. send_msg = pyqtSignal(str)
    30. send_percent = pyqtSignal(int)
    31. send_fps = pyqtSignal(str)
    32. def __init__(self):
    33. super(DetThread, self).__init__()
    34. self.weights = './yolov5s.pt' # 设置权重
    35. self.current_weight = './yolov5s.pt' # 当前权重
    36. self.source = '0' # 视频源
    37. self.conf_thres = 0.25 # 置信度
    38. self.iou_thres = 0.45 # iou
    39. self.jump_out = False # 跳出循环
    40. self.is_continue = True # 继续/暂停
    41. self.percent_length = 1000 # 进度条
    42. self.rate_check = True # 是否启用延时
    43. self.rate = 100 # 延时HZ
    44. self.save_fold = './result' # 保存文件夹
    45. @torch.no_grad()
    46. def run(self,
    47. imgsz=640, # inference size (pixels)
    48. max_det=1000, # maximum detections per image
    49. device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
    50. view_img=True, # show results
    51. save_txt=False, # save results to *.txt
    52. save_conf=False, # save confidences in --save-txt labels
    53. save_crop=False, # save cropped prediction boxes
    54. nosave=False, # do not save images/videos
    55. classes=None, # filter by class: --class 0, or --class 0 2 3
    56. agnostic_nms=False, # class-agnostic NMS
    57. augment=False, # augmented inference
    58. visualize=False, # visualize features
    59. update=False, # update all models
    60. project='runs/detect', # save results to project/name
    61. name='exp', # save results to project/name
    62. exist_ok=False, # existing project/name ok, do not increment
    63. line_thickness=3, # bounding box thickness (pixels)
    64. hide_labels=False, # hide labels
    65. hide_conf=False, # hide confidences
    66. half=False, # use FP16 half-precision inference
    67. ):
    68. # Initialize
    69. try:
    70. device = select_device(device)
    71. half &= device.type != 'cpu' # half precision only supported on CUDA
    72. # Load model
    73. model = attempt_load(self.weights, map_location=device) # load FP32 model
    74. num_params = 0
    75. for param in model.parameters():
    76. num_params += param.numel()
    77. stride = int(model.stride.max()) # model stride
    78. imgsz = check_img_size(imgsz, s=stride) # check image size
    79. names = model.module.names if hasattr(model, 'module') else model.names # get class names
    80. if half:
    81. model.half() # to FP16
    82. # Dataloader
    83. if self.source.isnumeric() or self.source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')):
    84. view_img = check_imshow()
    85. cudnn.benchmark = True # set True to speed up constant image size inference
    86. dataset = LoadWebcam(self.source, img_size=imgsz, stride=stride)
    87. # bs = len(dataset) # batch_size
    88. else:
    89. dataset = LoadImages(self.source, img_size=imgsz, stride=stride)
    90. # Run inference
    91. if device.type != 'cpu':
    92. model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once
    93. count = 0
    94. # 跳帧检测
    95. jump_count = 0
    96. start_time = time.time()
    97. dataset = iter(dataset)
    98. while True:
    99. # 手动停止
    100. if self.jump_out:
    101. self.vid_cap.release()
    102. self.send_percent.emit(0)
    103. self.send_msg.emit('停止')
    104. if hasattr(self, 'out'):
    105. self.out.release()
    106. break
    107. # 临时更换模型
    108. if self.current_weight != self.weights:
    109. # Load model
    110. model = attempt_load(self.weights, map_location=device) # load FP32 model
    111. num_params = 0
    112. for param in model.parameters():
    113. num_params += param.numel()
    114. stride = int(model.stride.max()) # model stride
    115. imgsz = check_img_size(imgsz, s=stride) # check image size
    116. names = model.module.names if hasattr(model, 'module') else model.names # get class names
    117. if half:
    118. model.half() # to FP16
    119. # Run inference
    120. if device.type != 'cpu':
    121. model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once
    122. self.current_weight = self.weights
    123. # 暂停开关
    124. if self.is_continue:
    125. path, img, im0s, self.vid_cap = next(dataset)
    126. # jump_count += 1
    127. # if jump_count % 5 != 0:
    128. # continue
    129. count += 1
    130. # 每三十帧刷新一次输出帧率
    131. if count % 30 == 0 and count >= 30:
    132. fps = int(30/(time.time()-start_time))
    133. self.send_fps.emit('fps:'+str(fps))
    134. start_time = time.time()
    135. if self.vid_cap:
    136. percent = int(count/self.vid_cap.get(cv2.CAP_PROP_FRAME_COUNT)*self.percent_length)
    137. self.send_percent.emit(percent)
    138. else:
    139. percent = self.percent_length
    140. statistic_dic = {name: 0 for name in names}
    141. img = torch.from_numpy(img).to(device)
    142. img = img.half() if half else img.float() # uint8 to fp16/32
    143. img /= 255.0 # 0 - 255 to 0.0 - 1.0
    144. if img.ndimension() == 3:
    145. img = img.unsqueeze(0)
    146. pred = model(img, augment=augment)[0]
    147. # Apply NMS
    148. pred = non_max_suppression(pred, self.conf_thres, self.iou_thres, classes, agnostic_nms, max_det=max_det)
    149. # Process detections
    150. for i, det in enumerate(pred): # detections per image
    151. im0 = im0s.copy()
    152. if len(det):
    153. # Rescale boxes from img_size to im0 size
    154. det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
    155. # Write results
    156. for *xyxy, conf, cls in reversed(det):
    157. c = int(cls) # integer class
    158. statistic_dic[names[c]] += 1
    159. label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
    160. # im0 = plot_one_box_PIL(xyxy, im0, label=label, color=colors(c, True), line_thickness=line_thickness) # 中文标签画框,但是耗时会增加
    161. plot_one_box(xyxy, im0, label=label, color=colors(c, True),
    162. line_thickness=line_thickness)
    163. # 控制视频发送频率
    164. if self.rate_check:
    165. time.sleep(1/self.rate)
    166. self.send_img.emit(im0)
    167. self.send_raw.emit(im0s if isinstance(im0s, np.ndarray) else im0s[0])
    168. self.send_statistic.emit(statistic_dic)
    169. # 如果自动录制
    170. if self.save_fold:
    171. os.makedirs(self.save_fold, exist_ok=True) # 路径不存在,自动保存
    172. # 如果输入是图片
    173. if self.vid_cap is None:
    174. save_path = os.path.join(self.save_fold,
    175. time.strftime('%Y_%m_%d_%H_%M_%S',
    176. time.localtime()) + '.jpg')
    177. cv2.imwrite(save_path, im0)
    178. else:
    179. if count == 1: # 第一帧时初始化录制
    180. # 以视频原始帧率进行录制
    181. ori_fps = int(self.vid_cap.get(cv2.CAP_PROP_FPS))
    182. if ori_fps == 0:
    183. ori_fps = 25
    184. # width = int(self.vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    185. # height = int(self.vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    186. width, height = im0.shape[1], im0.shape[0]
    187. save_path = os.path.join(self.save_fold, time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime()) + '.mp4')
    188. self.out = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), ori_fps,
    189. (width, height))
    190. self.out.write(im0)
    191. if percent == self.percent_length:
    192. print(count)
    193. self.send_percent.emit(0)
    194. self.send_msg.emit('检测结束')
    195. if hasattr(self, 'out'):
    196. self.out.release()
    197. # 正常跳出循环
    198. break
    199. except Exception as e:
    200. self.send_msg.emit('%s' % e)

    3.2YOLOv5主代码

    1. """Train a YOLOv5 model on a custom dataset
    2. Usage:
    3. $ python path/to/train.py --data coco128.yaml --weights yolov5s.pt --img 640
    4. """
    5. import argparse
    6. import logging
    7. import os
    8. import random
    9. import sys
    10. import time
    11. import warnings
    12. from copy import deepcopy
    13. from pathlib import Path
    14. from threading import Thread
    15. import math
    16. import numpy as np
    17. import torch.distributed as dist
    18. import torch.nn as nn
    19. import torch.nn.functional as F
    20. import torch.optim as optim
    21. import torch.optim.lr_scheduler as lr_scheduler
    22. import torch.utils.data
    23. import yaml
    24. from torch.cuda import amp
    25. from torch.nn.parallel import DistributedDataParallel as DDP
    26. from torch.utils.tensorboard import SummaryWriter
    27. from tqdm import tqdm
    28. FILE = Path(__file__).absolute()
    29. sys.path.append(FILE.parents[0].as_posix()) # add yolov5/ to path
    30. import val # for end-of-epoch mAP
    31. from models.experimental import attempt_load
    32. from models.yolo import Model
    33. from utils.autoanchor import check_anchors
    34. from utils.datasets import create_dataloader
    35. from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \
    36. strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \
    37. check_requirements, print_mutation, set_logging, one_cycle, colorstr
    38. from utils.google_utils import attempt_download
    39. from utils.loss import ComputeLoss
    40. from utils.plots import plot_images, plot_labels, plot_results, plot_evolution
    41. from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first, de_parallel
    42. from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume
    43. from utils.metrics import fitness
    44. LOGGER = logging.getLogger(__name__)
    45. LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html
    46. RANK = int(os.getenv('RANK', -1))
    47. WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1))
    48. def train(hyp, # path/to/hyp.yaml or hyp dictionary
    49. opt,
    50. device,
    51. ):
    52. save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, = \
    53. opt.save_dir, opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \
    54. opt.resume, opt.noval, opt.nosave, opt.workers
    55. # Directories
    56. save_dir = Path(save_dir)
    57. wdir = save_dir / 'weights'
    58. wdir.mkdir(parents=True, exist_ok=True) # make dir
    59. last = wdir / 'last.pt'
    60. best = wdir / 'best.pt'
    61. results_file = save_dir / 'results.txt'
    62. # Hyperparameters
    63. if isinstance(hyp, str):
    64. with open(hyp) as f:
    65. hyp = yaml.safe_load(f) # load hyps dict
    66. LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items()))
    67. # Save run settings
    68. with open(save_dir / 'hyp.yaml', 'w') as f:
    69. yaml.safe_dump(hyp, f, sort_keys=False)
    70. with open(save_dir / 'opt.yaml', 'w') as f:
    71. yaml.safe_dump(vars(opt), f, sort_keys=False)
    72. # Configure
    73. plots = not evolve # create plots
    74. cuda = device.type != 'cpu'
    75. init_seeds(1 + RANK)
    76. with open(data) as f:
    77. data_dict = yaml.safe_load(f) # data dict
    78. # Loggers
    79. loggers = {'wandb': None, 'tb': None} # loggers dict
    80. if RANK in [-1, 0]:
    81. # TensorBoard
    82. if not evolve:
    83. prefix = colorstr('tensorboard: ')
    84. LOGGER.info(f"{prefix}Start with 'tensorboard --logdir {opt.project}', view at http://localhost:6006/")
    85. loggers['tb'] = SummaryWriter(str(save_dir))
    86. # W&B
    87. opt.hyp = hyp # add hyperparameters
    88. run_id = torch.load(weights).get('wandb_id') if weights.endswith('.pt') and os.path.isfile(weights) else None
    89. run_id = run_id if opt.resume else None # start fresh run if transfer learning
    90. wandb_logger = WandbLogger(opt, save_dir.stem, run_id, data_dict)
    91. loggers['wandb'] = wandb_logger.wandb
    92. if loggers['wandb']:
    93. data_dict = wandb_logger.data_dict
    94. weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp # may update weights, epochs if resuming
    95. nc = 1 if single_cls else int(data_dict['nc']) # number of classes
    96. names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names
    97. assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, data) # check
    98. is_coco = data.endswith('coco.yaml') and nc == 80 # COCO dataset
    99. # Model
    100. pretrained = weights.endswith('.pt')
    101. if pretrained:
    102. with torch_distributed_zero_first(RANK):
    103. weights = attempt_download(weights) # download if not found locally
    104. ckpt = torch.load(weights, map_location=device) # load checkpoint
    105. model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create
    106. exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys
    107. state_dict = ckpt['model'].float().state_dict() # to FP32
    108. state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=exclude) # intersect
    109. model.load_state_dict(state_dict, strict=False) # load
    110. LOGGER.info('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report
    111. else:
    112. model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create
    113. with torch_distributed_zero_first(RANK):
    114. check_dataset(data_dict) # check
    115. train_path = data_dict['train']
    116. val_path = data_dict['val']
    117. # Freeze
    118. freeze = [] # parameter names to freeze (full or partial)
    119. for k, v in model.named_parameters():
    120. v.requires_grad = True # train all layers
    121. if any(x in k for x in freeze):
    122. print('freezing %s' % k)
    123. v.requires_grad = False
    124. # Optimizer
    125. nbs = 64 # nominal batch size
    126. accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing
    127. hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay
    128. LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}")
    129. pg0, pg1, pg2 = [], [], [] # optimizer parameter groups
    130. for k, v in model.named_modules():
    131. if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):
    132. pg2.append(v.bias) # biases
    133. if isinstance(v, nn.BatchNorm2d):
    134. pg0.append(v.weight) # no decay
    135. elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):
    136. pg1.append(v.weight) # apply decay
    137. if opt.adam:
    138. optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum
    139. else:
    140. optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True)
    141. optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay
    142. optimizer.add_param_group({'params': pg2}) # add pg2 (biases)
    143. LOGGER.info('Optimizer groups: %g .bias, %g conv.weight, %g other' % (len(pg2), len(pg1), len(pg0)))
    144. del pg0, pg1, pg2
    145. # Scheduler https://arxiv.org/pdf/1812.01187.pdf
    146. # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR
    147. if opt.linear_lr:
    148. lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear
    149. else:
    150. lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf']
    151. scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
    152. # plot_lr_scheduler(optimizer, scheduler, epochs)
    153. # EMA
    154. ema = ModelEMA(model) if RANK in [-1, 0] else None
    155. # Resume
    156. start_epoch, best_fitness = 0, 0.0
    157. if pretrained:
    158. # Optimizer
    159. if ckpt['optimizer'] is not None:
    160. optimizer.load_state_dict(ckpt['optimizer'])
    161. best_fitness = ckpt['best_fitness']
    162. # EMA
    163. if ema and ckpt.get('ema'):
    164. ema.ema.load_state_dict(ckpt['ema'].float().state_dict())
    165. ema.updates = ckpt['updates']
    166. # Results
    167. if ckpt.get('training_results') is not None:
    168. results_file.write_text(ckpt['training_results']) # write results.txt
    169. # Epochs
    170. start_epoch = ckpt['epoch'] + 1
    171. if resume:
    172. assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs)
    173. if epochs < start_epoch:
    174. LOGGER.info('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' %
    175. (weights, ckpt['epoch'], epochs))
    176. epochs += ckpt['epoch'] # finetune additional epochs
    177. del ckpt, state_dict
    178. # Image sizes
    179. gs = max(int(model.stride.max()), 32) # grid size (max stride)
    180. nl = model.model[-1].nl # number of detection layers (used for scaling hyp['obj'])
    181. imgsz = check_img_size(opt.imgsz, gs) # verify imgsz is gs-multiple
    182. # DP mode
    183. if cuda and RANK == -1 and torch.cuda.device_count() > 1:
    184. logging.warning('DP not recommended, instead use torch.distributed.run for best DDP Multi-GPU results.\n'
    185. 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.')
    186. model = torch.nn.DataParallel(model)
    187. # SyncBatchNorm
    188. if opt.sync_bn and cuda and RANK != -1:
    189. raise Exception('can not train with --sync-bn, known issue https://github.com/ultralytics/yolov5/issues/3998')
    190. model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device)
    191. LOGGER.info('Using SyncBatchNorm()')
    192. # Trainloader
    193. train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls,
    194. hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=RANK,
    195. workers=workers, image_weights=opt.image_weights, quad=opt.quad,
    196. prefix=colorstr('train: '))
    197. mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class
    198. nb = len(train_loader) # number of batches
    199. assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, data, nc - 1)
    200. # Process 0
    201. if RANK in [-1, 0]:
    202. val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls,
    203. hyp=hyp, cache=opt.cache_images and not noval, rect=True, rank=-1,
    204. workers=workers, pad=0.5,
    205. prefix=colorstr('val: '))[0]
    206. if not resume:
    207. labels = np.concatenate(dataset.labels, 0)
    208. # c = torch.tensor(labels[:, 0]) # classes
    209. # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency
    210. # model._initialize_biases(cf.to(device))
    211. if plots:
    212. plot_labels(labels, names, save_dir, loggers)
    213. # Anchors
    214. if not opt.noautoanchor:
    215. check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz)
    216. model.half().float() # pre-reduce anchor precision
    217. # DDP mode
    218. if cuda and RANK != -1:
    219. model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK)
    220. # Model parameters
    221. hyp['box'] *= 3. / nl # scale to layers
    222. hyp['cls'] *= nc / 80. * 3. / nl # scale to classes and layers
    223. hyp['obj'] *= (imgsz / 640) ** 2 * 3. / nl # scale to image size and layers
    224. hyp['label_smoothing'] = opt.label_smoothing
    225. model.nc = nc # attach number of classes to model
    226. model.hyp = hyp # attach hyperparameters to model
    227. model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou)
    228. model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights
    229. model.names = names
    230. # Start training
    231. t0 = time.time()
    232. nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations)
    233. # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training
    234. last_opt_step = -1
    235. maps = np.zeros(nc) # mAP per class
    236. results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls)
    237. scheduler.last_epoch = start_epoch - 1 # do not move
    238. scaler = amp.GradScaler(enabled=cuda)
    239. compute_loss = ComputeLoss(model) # init loss class
    240. LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n'
    241. f'Using {train_loader.num_workers} dataloader workers\n'
    242. f'Logging results to {save_dir}\n'
    243. f'Starting training for {epochs} epochs...')
    244. for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------
    245. model.train()
    246. # Update image weights (optional)
    247. if opt.image_weights:
    248. # Generate indices
    249. if RANK in [-1, 0]:
    250. cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights
    251. iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights
    252. dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx
    253. # Broadcast if DDP
    254. if RANK != -1:
    255. indices = (torch.tensor(dataset.indices) if RANK == 0 else torch.zeros(dataset.n)).int()
    256. dist.broadcast(indices, 0)
    257. if RANK != 0:
    258. dataset.indices = indices.cpu().numpy()
    259. # Update mosaic border
    260. # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs)
    261. # dataset.mosaic_border = [b - imgsz, -b] # height, width borders
    262. mloss = torch.zeros(4, device=device) # mean losses
    263. if RANK != -1:
    264. train_loader.sampler.set_epoch(epoch)
    265. pbar = enumerate(train_loader)
    266. LOGGER.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'labels', 'img_size'))
    267. if RANK in [-1, 0]:
    268. pbar = tqdm(pbar, total=nb) # progress bar
    269. optimizer.zero_grad()
    270. for i, (imgs, targets, paths, _) in pbar: # batch -------------------------------------------------------------
    271. ni = i + nb * epoch # number integrated batches (since train start)
    272. imgs = imgs.to(device, non_blocking=True).float() / 255.0 # uint8 to float32, 0-255 to 0.0-1.0
    273. # Warmup
    274. if ni <= nw:
    275. xi = [0, nw] # x interp
    276. # model.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou)
    277. accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round())
    278. for j, x in enumerate(optimizer.param_groups):
    279. # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0
    280. x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)])
    281. if 'momentum' in x:
    282. x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']])
    283. # Multi-scale
    284. if opt.multi_scale:
    285. sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size
    286. sf = sz / max(imgs.shape[2:]) # scale factor
    287. if sf != 1:
    288. ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple)
    289. imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False)
    290. # Forward
    291. with amp.autocast(enabled=cuda):
    292. pred = model(imgs) # forward
    293. loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size
    294. if RANK != -1:
    295. loss *= WORLD_SIZE # gradient averaged between devices in DDP mode
    296. if opt.quad:
    297. loss *= 4.
    298. # Backward
    299. scaler.scale(loss).backward()
    300. # Optimize
    301. if ni - last_opt_step >= accumulate:
    302. scaler.step(optimizer) # optimizer.step
    303. scaler.update()
    304. optimizer.zero_grad()
    305. if ema:
    306. ema.update(model)
    307. last_opt_step = ni
    308. # Print
    309. if RANK in [-1, 0]:
    310. mloss = (mloss * i + loss_items) / (i + 1) # update mean losses
    311. mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB)
    312. s = ('%10s' * 2 + '%10.4g' * 6) % (
    313. f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])
    314. pbar.set_description(s)
    315. # Plot
    316. if plots and ni < 3:
    317. f = save_dir / f'train_batch{ni}.jpg' # filename
    318. Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start()
    319. if loggers['tb'] and ni == 0: # TensorBoard
    320. with warnings.catch_warnings():
    321. warnings.simplefilter('ignore') # suppress jit trace warning
    322. loggers['tb'].add_graph(torch.jit.trace(de_parallel(model), imgs[0:1], strict=False), [])
    323. elif plots and ni == 10 and loggers['wandb']:
    324. wandb_logger.log({'Mosaics': [loggers['wandb'].Image(str(x), caption=x.name) for x in
    325. save_dir.glob('train*.jpg') if x.exists()]})
    326. # end batch ------------------------------------------------------------------------------------------------
    327. # Scheduler
    328. lr = [x['lr'] for x in optimizer.param_groups] # for loggers
    329. scheduler.step()
    330. # DDP process 0 or single-GPU
    331. if RANK in [-1, 0]:
    332. # mAP
    333. ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights'])
    334. final_epoch = epoch + 1 == epochs
    335. if not noval or final_epoch: # Calculate mAP
    336. wandb_logger.current_epoch = epoch + 1
    337. results, maps, _ = val.run(data_dict,
    338. batch_size=batch_size // WORLD_SIZE * 2,
    339. imgsz=imgsz,
    340. model=ema.ema,
    341. single_cls=single_cls,
    342. dataloader=val_loader,
    343. save_dir=save_dir,
    344. save_json=is_coco and final_epoch,
    345. verbose=nc < 50 and final_epoch,
    346. plots=plots and final_epoch,
    347. wandb_logger=wandb_logger,
    348. compute_loss=compute_loss)
    349. # Write
    350. with open(results_file, 'a') as f:
    351. f.write(s + '%10.4g' * 7 % results + '\n') # append metrics, val_loss
    352. # Log
    353. tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss
    354. 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95',
    355. 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss
    356. 'x/lr0', 'x/lr1', 'x/lr2'] # params
    357. for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags):
    358. if loggers['tb']:
    359. loggers['tb'].add_scalar(tag, x, epoch) # TensorBoard
    360. if loggers['wandb']:
    361. wandb_logger.log({tag: x}) # W&B
    362. # Update best mAP
    363. fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95]
    364. if fi > best_fitness:
    365. best_fitness = fi
    366. wandb_logger.end_epoch(best_result=best_fitness == fi)
    367. # Save model
    368. if (not nosave) or (final_epoch and not evolve): # if save
    369. ckpt = {'epoch': epoch,
    370. 'best_fitness': best_fitness,
    371. 'training_results': results_file.read_text(),
    372. 'model': deepcopy(de_parallel(model)).half(),
    373. 'ema': deepcopy(ema.ema).half(),
    374. 'updates': ema.updates,
    375. 'optimizer': optimizer.state_dict(),
    376. 'wandb_id': wandb_logger.wandb_run.id if loggers['wandb'] else None}
    377. # Save last, best and delete
    378. torch.save(ckpt, last)
    379. if best_fitness == fi:
    380. torch.save(ckpt, best)
    381. if loggers['wandb']:
    382. if ((epoch + 1) % opt.save_period == 0 and not final_epoch) and opt.save_period != -1:
    383. wandb_logger.log_model(last.parent, opt, epoch, fi, best_model=best_fitness == fi)
    384. del ckpt
    385. # end epoch ----------------------------------------------------------------------------------------------------
    386. # end training -----------------------------------------------------------------------------------------------------
    387. if RANK in [-1, 0]:
    388. LOGGER.info(f'{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.\n')
    389. if plots:
    390. plot_results(save_dir=save_dir) # save as results.png
    391. if loggers['wandb']:
    392. files = ['results.png', 'confusion_matrix.png', *[f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R')]]
    393. wandb_logger.log({"Results": [loggers['wandb'].Image(str(save_dir / f), caption=f) for f in files
    394. if (save_dir / f).exists()]})
    395. if not evolve:
    396. if is_coco: # COCO dataset
    397. for m in [last, best] if best.exists() else [last]: # speed, mAP tests
    398. results, _, _ = val.run(data_dict,
    399. batch_size=batch_size // WORLD_SIZE * 2,
    400. imgsz=imgsz,
    401. model=attempt_load(m, device).half(),
    402. single_cls=single_cls,
    403. dataloader=val_loader,
    404. save_dir=save_dir,
    405. save_json=True,
    406. plots=False)
    407. # Strip optimizers
    408. for f in last, best:
    409. if f.exists():
    410. strip_optimizer(f) # strip optimizers
    411. if loggers['wandb']: # Log the stripped model
    412. loggers['wandb'].log_artifact(str(best if best.exists() else last), type='model',
    413. name='run_' + wandb_logger.wandb_run.id + '_model',
    414. aliases=['latest', 'best', 'stripped'])
    415. wandb_logger.finish_run()
    416. torch.cuda.empty_cache()
    417. return results

  • 相关阅读:
    js调用(前/后)摄像头,截取照片,关闭摄像头
    pytest自动化框架运行全局配置文件pytest.ini
    java毕业设计病人追踪治疗信息系统mybatis+源码+调试部署+系统+数据库+lw
    openGauss安装(超详细)
    消息队列-概述-JMS和AMQP
    Docker部署前后端服务示例
    创建型模式-原型模式(五)
    关于ES集群信息的一些查看
    JavaEE——Session会话追踪的实现机制
    maven
  • 原文地址:https://blog.csdn.net/weixin_45303602/article/details/133756341