😎😎😎物体检测-系列教程 总目录
有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Pycharm中进行
本篇文章配套的代码资源已经上传
点我下载源码
24、epoch循环训练------更新、评估、保存
这部分是训练过程的每个epoch结束之前执行的一系列操作,主要包括学习率调整、模型评估、日志记录、模型保存等
# Schedulerscheduler.step()# DDP process 0 or single-GPUif rank in [-1, 0]:# mAPif ema is not None:ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride'])final_epoch = epoch + 1 == epochsif not opt.notest or final_epoch: # Calculate mAPresults, maps, times = test.test(opt.data,batch_size=total_batch_size,imgsz=imgsz_test,model=ema.ema.module if hasattr(ema.ema, 'module') else ema.ema,single_cls=opt.single_cls,dataloader=testloader,save_dir=log_dir)# Writewith open(results_file, 'a') as f:f.write(s + '%10.4g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls)if len(opt.name) and opt.bucket:os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name))# Tensorboardif tb_writer:tags = ['train/giou_loss', 'train/obj_loss', 'train/cls_loss','metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95','val/giou_loss', 'val/obj_loss', 'val/cls_loss']for x, tag in zip(list(mloss[:-1]) + list(results), tags):tb_writer.add_scalar(tag, x, epoch)# Update best mAPfi = fitness(np.array(results).reshape(1, -1)) # fitness_i = weighted combination of [P, R, mAP, F1]if fi > best_fitness:best_fitness = fi# Save modelsave = (not opt.nosave) or (final_epoch and not opt.evolve)if save:with open(results_file, 'r') as f: # create checkpointckpt = {'epoch': epoch,'best_fitness': best_fitness,'training_results': f.read(),'model': ema.ema.module if hasattr(ema, 'module') else ema.ema,'optimizer': None if final_epoch else optimizer.state_dict()}# Save last, best and deletetorch.save(ckpt, last)if best_fitness == fi:torch.save(ckpt, best)del ckpt
- 更新学习率调度器的状态,根据预定的策略(如学习率衰减)调整学习率,以帮助模型更好地收敛
- 如果不是分布式训练或者在分布式训练的主进程:
- 如果使用了指数移动平均(EMA)模型,将更新EMA模型的属性:
- 更新EMA模型的属性,包括模型配置(yaml)、类别数量(nc)、超参数(hyp)、损失比例(gr)、类别名称(names)和步长(stride),这是为了确保EMA模型与训练模型保持同步
- final_epoch ,判断当前epoch是否是训练的最后一个epoch,确定何时执行一些只在训练结束时需要进行的操作(如保存模型)非常关键
- 如果设置为在每个epoch结束时都进行测试(notest为False)或者当前是最后一个epoch,则执行模型测试
- 从测试脚本中调用测试函数,进行模型评估。计算模型在测试集上的性能指标,包括精度、召回率和mAP等。根据是否使用EMA以及是否在模型上使用了DataParallel或DistributedDataParallel,选择适当的模型进行评估
- 打开测试文件
- 将测试结果写入到指定的文件中,results_file是存储结果的文件路径,s是包含训练信息的字符串,results包含了测试指标的值
- 如果指定了云存储桶(bucket)和文件命名(name)
- 将结果文件上传到云存储
- 如果配置了TensorBoard日志记录器
- 定义一组标签,用于在TensorBoard中组织不同的训练和验证指标
- 遍历每个指标及其对应的标签
- 使用TensorBoard的add_scalar函数记录这些指标,在TensorBoard中进行可视化
- fi ,调用辅助函数fitness计算一个综合性能指标(称为"fitness"),它基于测试结果(例如精度、召回率、mAP等)
- 如果当前epoch的fitness分数高于迄今为止的最佳分数,则
- best_fitness ,更新最佳fitness分数
- save ,决定是否保存模型。如果不是显式地设置为不保存模型(nosave为False),或者当前是最后一个epoch并且没有进行模型进化(evolve为False),则保存模型
- 如果满足保存模型的条件:
- 读取并保存当前模型的状态,包括epoch数、最佳fitness分数、训练结果、模型本身以及优化器的状态(如果不是最后一个epoch)
- 将模型的状态保存到文件中。last变量代表最后一个checkpoint的文件名
- 如果当前模型的fitness等于最佳fitness,则
- 将其保存为最佳模型的checkpoint
- 删除临时保存的模型状态字典,释放内存
这部分展示了在训练过程中每个epoch结束之前执行的关键步骤,包括更新学习率、评估模型性能、记录和保存结果、以及条件性地保存模型的状态。这些步骤对于监控训练进度、评估模型性能和保证训练过程的可重现性非常重要
25、结束epoch循环训练的后续处理
这部分主要涉及在训练结束的清理和保存工作,包括重命名和保存训练结果、模型状态、上传权重到云存储、绘制结果图表和清理资源等
if rank in [-1, 0]:# Strip optimizersn = ('_' if len(opt.name) and not opt.name.isnumeric() else '') + opt.namefresults, flast, fbest = 'results%s.txt' % n, wdir + 'last%s.pt' % n, wdir + 'best%s.pt' % nfor f1, f2 in zip([wdir + 'last.pt', wdir + 'best.pt', 'results.txt'], [flast, fbest, fresults]):if os.path.exists(f1):os.rename(f1, f2) # renameispt = f2.endswith('.pt') # is *.ptstrip_optimizer(f2) if ispt else None # strip optimizeros.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket and ispt else None # upload# Finishif not opt.evolve:plot_results(save_dir=log_dir) # save as results.pnglogger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600))dist.destroy_process_group() if rank not in [-1, 0] else Nonetorch.cuda.empty_cache()return results
- 如果不是分布式训练或者是分布式训练的主进程:
- n,构造文件名的前缀。如果用户提供了命名(opt.name)且名称不是全数字,则在名称前加上下划线;否则直接使用名称。这有助于生成更具可读性和组织性的文件名
- fresults, flast, fbest,基于上一步得到的名称前缀n,构造结果文件、最后一个模型状态文件和最佳模型状态文件的完整路径
- 使用for循环结合zip函数遍历原始文件名和新文件名的列表,f1是原始文件名,f2是新文件名
- 如果原始文件(f1)存在
- 则将其重命名为新的文件名(f2),保持文件命名的一致性和可识别性
- ispt ,判断文件是否是.pt格式的模型文件,对于接下来是否执行某些特定操作(如剥离优化器状态)很关键
- 如果文件是.pt格式的模型文件,则执行辅助函数strip_optimizer,从模型文件中移除优化器的状态。这可以减小文件大小,便于分享或部署模型
- 如果指定了云存储桶(opt.bucket)且文件是模型文件,则使用gsutil cp命令将文件上传到云存储桶中。这便于模型的远程存储和访问
- 如果不是在执行进化训练(opt.evolve)
- 调用辅助函数plot_results,在指定的日志目录中保存训练结果的图表(通常为results.png),有助于可视化训练过程
- 记录一条日志信息,训练完成,包括完成的epochs数和总耗时(以小时计)
- 如果当前进程是分布式训练中的非主进程,则销毁进程组。这是分布式训练结束时的清理工作,有助于正确地关闭分布式训练环境
- 清空CUDA缓存。这有助于释放未使用的GPU内存,使其可用于其他应用程序
- 返回训练过程中的最终结果,包括模型性能指标等重要信息