master
qinxiaonan_branch 5 months ago
parent 49f13f4834
commit 6316da5942

@ -1,10 +1,3 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
Train a YOLOv5 model on a custom dataset
Usage:
$ python path/to/train.py --data coco128.yaml --weights yolov5s.pt --img 640
"""
import argparse import argparse
import math import math
import os import os
@ -55,12 +48,12 @@ RANK = int(os.getenv('RANK', -1))
WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1))
def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典 def train(hyp,
opt, opt,
device, device,
callbacks callbacks
): ):
# 定义训练过程中使用的变量 # 定义训练过程中使用的变量,启动深度学习模型的训练过程
save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \
Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \
opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze
@ -72,9 +65,9 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
# 超参数 # 超参数
if isinstance(hyp, str): if isinstance(hyp, str):
with open(hyp, errors='ignore') as f: with open(hyp, errors='ignore') as f:#使用with打开如果遇到编码错误就忽略并继续打开
hyp = yaml.safe_load(f) # 加载超参数字典 hyp = yaml.safe_load(f) # 加载超参数字典
LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items()))#日志,生成字符串
# 保存运行设置 # 保存运行设置
with open(save_dir / 'hyp.yaml', 'w') as f: with open(save_dir / 'hyp.yaml', 'w') as f:
@ -82,7 +75,7 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
with open(save_dir / 'opt.yaml', 'w') as f: with open(save_dir / 'opt.yaml', 'w') as f:
yaml.safe_dump(vars(opt), f, sort_keys=False) yaml.safe_dump(vars(opt), f, sort_keys=False)
# Loggers # 日志记录和初始化
if RANK in [-1, 0]: if RANK in [-1, 0]:
loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance
if loggers.wandb: if loggers.wandb:
@ -90,24 +83,24 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
if resume: if resume:
weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp
# Register actions # 注册回调函数
for k in methods(loggers): for k in methods(loggers):
callbacks.register_action(k, callback=getattr(loggers, k)) callbacks.register_action(k, callback=getattr(loggers, k))
# Config # 初始化设置
plots = not evolve # create plots plots = not evolve # 是否画图
cuda = device.type != 'cpu' cuda = device.type != 'cpu'
init_seeds(1 + RANK) init_seeds(1 + RANK) #随机种子
with torch_distributed_zero_first(LOCAL_RANK): with torch_distributed_zero_first(LOCAL_RANK):
data_dict = data_dict or check_dataset(data) # check if None data_dict = data_dict or check_dataset(data) # 检查是否存在
train_path, val_path = data_dict['train'], data_dict['val'] train_path, val_path = data_dict['train'], data_dict['val']
nc = 1 if single_cls else int(data_dict['nc']) # number of classes nc = 1 if single_cls else int(data_dict['nc']) # 类别数量
names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # 名称
assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}' # check assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}' # 检查数量与data_dict是否相匹配
is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO数据集路径
# Model # 训练模型
check_suffix(weights, '.pt') # check weights check_suffix(weights, '.pt') # 检查权重文件的后缀
pretrained = weights.endswith('.pt') pretrained = weights.endswith('.pt')
if pretrained: if pretrained:
with torch_distributed_zero_first(LOCAL_RANK): with torch_distributed_zero_first(LOCAL_RANK):
@ -122,7 +115,7 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
else: else:
model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create
# Freeze # 冻结模型层
freeze = [f'model.{x}.' for x in range(freeze)] # layers to freeze freeze = [f'model.{x}.' for x in range(freeze)] # layers to freeze
for k, v in model.named_parameters(): for k, v in model.named_parameters():
v.requires_grad = True # train all layers v.requires_grad = True # train all layers
@ -130,21 +123,21 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
LOGGER.info(f'freezing {k}') LOGGER.info(f'freezing {k}')
v.requires_grad = False v.requires_grad = False
# Image size # 图像和网格尺寸
gs = max(int(model.stride.max()), 32) # grid size (max stride) gs = max(int(model.stride.max()), 32) # 最小为32
imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # 图像尺寸是网格的整数倍
# Batch size # 批量大小
if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size if RANK == -1 and batch_size == -1: # 单GPU没有指定批量大小
batch_size = check_train_batch_size(model, imgsz) batch_size = check_train_batch_size(model, imgsz)
# Optimizer # 优化
nbs = 64 # nominal batch size nbs = 64 # 基准
accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing accumulate = max(round(nbs / batch_size), 1)
hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay hyp['weight_decay'] *= batch_size * accumulate / nbs # 调整权重系数
LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}") LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}")
g0, g1, g2 = [], [], [] # optimizer parameter groups g0, g1, g2 = [], [], [] # 初始化3个列表
for v in model.modules(): for v in model.modules():
if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias
g2.append(v.bias) g2.append(v.bias)
@ -153,25 +146,25 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay) elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay)
g1.append(v.weight) g1.append(v.weight)
if opt.adam: if opt.adam:#选择优化器
optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))
else: else:
optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True)
optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']}) # add g1 with weight_decay optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']}) # 添加g1 使用权重衰减
optimizer.add_param_group({'params': g2}) # add g2 (biases) optimizer.add_param_group({'params': g2}) # 添加g2不使用权重衰减
LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups " LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups "
f"{len(g0)} weight, {len(g1)} weight (no decay), {len(g2)} bias") f"{len(g0)} weight, {len(g1)} weight (no decay), {len(g2)} bias")
del g0, g1, g2 del g0, g1, g2 #删除
# Scheduler # 神经网络 学习调度
if opt.linear_lr: if opt.linear_lr:
lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # 计算学习率的线性衰减
else: else:
lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] lf = one_cycle(1, hyp['lrf'], epochs) # 周期变化
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
# EMA # 使用指数移动平均(EMA)来平滑模型权重
ema = ModelEMA(model) if RANK in [-1, 0] else None ema = ModelEMA(model) if RANK in [-1, 0] else None
# Resume # Resume
@ -239,7 +232,7 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
callbacks.run('on_pretrain_routine_end') callbacks.run('on_pretrain_routine_end')
# DDP mode # 处理DDP模型
if cuda and RANK != -1: if cuda and RANK != -1:
model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK)
@ -305,7 +298,7 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
if 'momentum' in x: if 'momentum' in x:
x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']])
# Multi-scale # 判断是否使用多尺度训练
if opt.multi_scale: if opt.multi_scale:
sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size
sf = sz / max(imgs.shape[2:]) # scale factor sf = sz / max(imgs.shape[2:]) # scale factor
@ -395,15 +388,9 @@ def train(hyp, # 'path/to/hyp.yaml' 或 hyp 字典
if RANK == -1 and stopper(epoch=epoch, fitness=fi): if RANK == -1 and stopper(epoch=epoch, fitness=fi):
break break
# Stop DDP TODO: known issues shttps://github.com/ultralytics/yolov5/pull/4576
# stop = stopper(epoch=epoch, fitness=fi)
# if RANK == 0:
# dist.broadcast_object_list([stop], 0) # broadcast 'stop' to all ranks
# Stop DPP
# with torch_distributed_zero_first(RANK):
# if stop:
# break # must break all DDP ranks
# end epoch ---------------------------------------------------------------------------------------------------- # end epoch ----------------------------------------------------------------------------------------------------
# end training ----------------------------------------------------------------------------------------------------- # end training -----------------------------------------------------------------------------------------------------
@ -526,48 +513,50 @@ def main(opt, callbacks=Callbacks()):
LOGGER.info('Destroying process group... ') LOGGER.info('Destroying process group... ')
dist.destroy_process_group() dist.destroy_process_group()
# Evolve hyperparameters (optional) # 演化超参数
else: else:
# Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) # 超参数演化元数据
meta = {'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) meta = {
'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) 'lr0': (1, 1e-5, 1e-1), # 初始学习率SGD=0.01, Adam=0.001
'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 'lrf': (1, 0.01, 1.0), # 最终OneCycleLR学习率lr0 * lrf
'weight_decay': (1, 0.0, 0.001), # optimizer weight decay 'momentum': (0.3, 0.6, 0.98), # SGD动量/Adam beta1
'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) 'weight_decay': (1, 0.0, 0.001), # 优化器权重衰减
'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum 'warmup_epochs': (1, 0.0, 5.0), # 预热epochs可以接受小数
'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr 'warmup_momentum': (1, 0.0, 0.95), # 预热初始动量
'box': (1, 0.02, 0.2), # box loss gain 'warmup_bias_lr': (1, 0.0, 0.2), # 预热初始偏置学习率
'cls': (1, 0.2, 4.0), # cls loss gain 'box': (1, 0.02, 0.2), # 边界框损失增益
'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight 'cls': (1, 0.2, 4.0), # 类别损失增益
'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) 'cls_pw': (1, 0.5, 2.0), # 类别BCELoss正样本权重
'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight 'obj': (1, 0.2, 4.0), # 目标损失增益(随像素缩放)
'iou_t': (0, 0.1, 0.7), # IoU training threshold 'obj_pw': (1, 0.5, 2.0), # 目标BCELoss正样本权重
'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold 'iou_t': (0, 0.1, 0.7), # IoU训练阈值
'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) 'anchor_t': (1, 2.0, 8.0), # 锚点多重阈值
'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) 'anchors': (2, 2.0, 10.0), # 每个输出网格的锚点数设为0则忽略
'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) 'fl_gamma': (0, 0.0, 2.0), # 焦点损失gammaefficientDet默认gamma=1.5
'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) 'hsv_h': (1, 0.0, 0.1), # 图像HSV-色调增强(比例)
'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) 'hsv_s': (1, 0.0, 0.9), # 图像HSV-饱和度增强(比例)
'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) 'hsv_v': (1, 0.0, 0.9), # 图像HSV-亮度增强(比例)
'translate': (1, 0.0, 0.9), # image translation (+/- fraction) 'degrees': (1, 0.0, 45.0), # 图像旋转(+/- 度)
'scale': (1, 0.0, 0.9), # image scale (+/- gain) 'translate': (1, 0.0, 0.9), # 图像平移(+/- 比例)
'shear': (1, 0.0, 10.0), # image shear (+/- deg) 'scale': (1, 0.0, 0.9), # 图像缩放(+/- 增益)
'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 'shear': (1, 0.0, 10.0), # 图像剪切(+/- 度)
'flipud': (1, 0.0, 1.0), # image flip up-down (probability) 'perspective': (0, 0.0, 0.001), # 图像透视(+/- 比例), 范围0-0.001
'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) 'flipud': (1, 0.0, 1.0), # 图像上下翻转(概率)
'mosaic': (1, 0.0, 1.0), # image mixup (probability) 'fliplr': (0, 0.0, 1.0), # 图像左右翻转(概率)
'mixup': (1, 0.0, 1.0), # image mixup (probability) 'mosaic': (1, 0.0, 1.0), # 图像混拼(概率)
'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) 'mixup': (1, 0.0, 1.0), # 图像混合(概率)
'copy_paste': (1, 0.0, 1.0) # 片段复制粘贴(概率)
}
with open(opt.hyp, errors='ignore') as f: with open(opt.hyp, errors='ignore') as f:
hyp = yaml.safe_load(f) # load hyps dict hyp = yaml.safe_load(f) # 加载超参数字典
if 'anchors' not in hyp: # anchors commented in hyp.yaml if 'anchors' not in hyp: # 设置默认值
hyp['anchors'] = 3 hyp['anchors'] = 3
opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir)
# ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices # 路径
evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv'
if opt.bucket: if opt.bucket:
os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {save_dir}') # download evolve.csv if exists os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {save_dir}') # 下载evolve.csv
for _ in range(opt.evolve): # generations to evolve for _ in range(opt.evolve): # generations to evolve
if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate
@ -615,16 +604,14 @@ def main(opt, callbacks=Callbacks()):
def run(**kwargs): def run(**kwargs):
# Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt')
opt = parse_opt(True) opt = parse_opt(True)
for k, v in kwargs.items(): for k, v in kwargs.items():
setattr(opt, k, v) setattr(opt, k, v)
main(opt) main(opt)
# python train.py --data mask_data.yaml --cfg mask_yolov5s.yaml --weights pretrained/yolov5s.pt --epoch 100 --batch-size 4 --device cpu #
# python train.py --data mask_data.yaml --cfg mask_yolov5l.yaml --weights pretrained/yolov5l.pt --epoch 100 --batch-size 4
# python train.py --data mask_data.yaml --cfg mask_yolov5m.yaml --weights pretrained/yolov5m.pt --epoch 100 --batch-size 4
if __name__ == "__main__": if __name__ == "__main__":
opt = parse_opt() opt = parse_opt()
main(opt) main(opt)

@ -1,11 +1,4 @@
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license #评估准确性
"""
Validate a trained YOLOv5 model accuracy on a custom dataset
Usage:
$ python path/to/val.py --data coco128.yaml --weights yolov5s.pt --img 640
"""
import argparse import argparse
import json import json
import os import os

@ -1,12 +1,5 @@
# -*- coding: utf-8 -*-
""" """
------------------------------------------------- 图形化界面
Project Name: yolov5-jungong
File Name: window.py.py
Author: chenming
Create Date: 2021/11/8
Description图形化界面可以检测摄像头视频和图片文件
-------------------------------------------------
""" """
# 设置tmp的目录来放中间的处理结果 # 设置tmp的目录来放中间的处理结果
import shutil import shutil

Loading…
Cancel
Save