|  |  | @ -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),  # 焦点损失gamma(efficientDet默认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) | 
			
		
	
	
		
		
			
				
					|  |  | 
 |