YOLOv3 代码详解(5) —— 训练脚本解析 train.py

部署运行你感兴趣的模型镜像

前言:

yolo系列的论文阅读
论文阅读 || 深度学习之目标检测 重磅出击YOLOv3
论文阅读 || 深度学习之目标检测yolov2
论文阅读 || 深度学习之目标检测yolov1

该篇讲解的工程连接是:
tensorflow的yolov3:https://github.com/YunYang1994/tensorflow-yolov3

自己对该工程的解析博客:
YOLOv3 || 1. 使用自己的数据集训练yolov3
YOLOv3 || 2. dataset.py解析
YOLOv3 || 3. dataset.py的多进程改造
YOLOv3 || 4. yolov3.py 网络结构的搭建和loss的定义
YOLOv3 || 5. train.py
YOLOv3 || 6. anchorboxes的获取 kmeans.py
YOLOv3 || 7. yolov3的pb文件的测试

该篇博客介绍的是yolov3的训练过程

1 代码讲解

1.1 代码概述

该脚本定义了yolov3的整个训练过程。是通过定义了class YoloTrain(object):来实现的。


class YoloTrain(object):
   def __init__(self):
       """初始化训练所需的所有变量"""
   def train(self):
       """进行神经网络整个过程的训练"""
       

1.2 def __init__(self)

工程作者将训练过程中的操作,都定义在相应的域下。使代码更加有条理

  • 1.神经网络的 placehoder
  • 2.神经网络的 结构 和 loss
  • 3.神经网络的 learn_rate
  • 4.神经网络的 define_weight_decay
  • 5.神经网络的 define_first_stage_train 的优化器
    神经网络的 define_second_stage_train 的优化器
  • 6.神经网络的 loader_and_saver
  • 7.神经网络的 summary

   def __init__(self):
       self.anchor_per_scale    = cfg.YOLO.ANCHOR_PER_SCALE                  # 每个尺度下的anchor数量
       self.classes             = utils.read_class_names(cfg.YOLO.CLASSES)   # 物体分类的类别
       self.num_classes         = len(self.classes)                          # 物体分类类别的数量
       self.learn_rate_init     = cfg.TRAIN.LEARN_RATE_INIT                  # 初始学习率(最大学习率)
       self.learn_rate_end      = cfg.TRAIN.LEARN_RATE_END		             # 
       self.first_stage_epochs  = cfg.TRAIN.FISRT_STAGE_EPOCHS               #  第一阶段训练轮数
       self.second_stage_epochs = cfg.TRAIN.SECOND_STAGE_EPOCHS     # 第二阶段训练轮数
       self.warmup_periods      = cfg.TRAIN.WARMUP_EPOCHS           # 预热训练的轮数
       self.initial_weight      = cfg.TRAIN.INITIAL_WEIGHT          #  初始学习率
       self.time                = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
       self.moving_ave_decay    = cfg.YOLO.MOVING_AVE_DECAY       # 滑动平均衰减
       self.max_bbox_per_scale  = 150                             # 一张图片可存在bbox的数量的最大值
       self.train_logdir        = "./data/log/train"              #  训练日志的路径
       self.trainset            = Dataset('train')                #  实例化训练数据的读取
       self.testset             = Dataset('test')                 #  实例化预测数据的读取
       self.steps_per_period    = len(self.trainset)              #  每轮中的步数
       self.sess                = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))  # 创建会话
  • 1神经网络的placehoder】:yolov3使用的是不同尺寸的图片进行训练,所以对输入输出的placehoder并未设置shape

       with tf.name_scope('define_input'):
           self.input_data   = tf.placeholder(dtype=tf.float32, name='input_data')
           self.label_sbbox  = tf.placeholder(dtype=tf.float32, name='label_sbbox')
           self.label_mbbox  = tf.placeholder(dtype=tf.float32, name='label_mbbox')
           self.label_lbbox  = tf.placeholder(dtype=tf.float32, name='label_lbbox')
           self.true_sbboxes = tf.placeholder(dtype=tf.float32, name='sbboxes')
           self.true_mbboxes = tf.placeholder(dtype=tf.float32, name='mbboxes')
           self.true_lbboxes = tf.placeholder(dtype=tf.float32, name='lbboxes')
           self.trainable     = tf.placeholder(dtype=tf.bool, name='training')
           
  • 2神经网络的loss】:创建一个YOLOv3的对象,然后计算其loss。loss的详细操作在上一篇博客 yolov3的loss 中有解析

       with tf.name_scope("define_loss"):
           self.model = YOLOV3(self.input_data, self.trainable)
           self.net_var = tf.global_variables()
           self.giou_loss, self.conf_loss, self.prob_loss = self.model.compute_loss(
                                                   self.label_sbbox,  self.label_mbbox,  self.label_lbbox,
                                                   self.true_sbboxes, self.true_mbboxes, self.true_lbboxes)
           self.loss = self.giou_loss + self.conf_loss + self.prob_loss
           
  • 3神经网络的learn_rate】:学习率的变化分两个阶段
    – 预热阶段 warmup_periods:学习率—线性衰减的方式
    – 正常训练阶段:学习率—余弦退火,使训练过程中更好的逃离局部最优

       with tf.name_scope('learn_rate'):
           self.global_step = tf.Variable(1.0, dtype=tf.float64, trainable=False, name='global_step')
           # 训练的warmup预数的数量
           warmup_steps = tf.constant(self.warmup_periods * self.steps_per_period,
                                       dtype=tf.float64, name='warmup_steps')
           # 训练的所有步数的数量
           train_steps = tf.constant( (self.first_stage_epochs + self.second_stage_epochs)* self.steps_per_period,
                                       dtype=tf.float64, name='train_steps')
           self.learn_rate = tf.cond(
               pred=self.global_step < warmup_steps,
               true_fn=lambda: self.global_step / warmup_steps * self.learn_rate_init,
               false_fn=lambda: self.learn_rate_end + 0.5 * (self.learn_rate_init - self.learn_rate_end) *
                                   (1 + tf.cos(
                                       (self.global_step - warmup_steps) / (train_steps - warmup_steps) * np.pi))
           )
           global_step_update = tf.assign_add(self.global_step, 1.0)
           

       with tf.name_scope("define_weight_decay"):
           moving_ave = tf.train.ExponentialMovingAverage(self.moving_ave_decay).apply(tf.trainable_variables())
           
  • 5神经网络的define_first_stage_train】:训练的第一阶段
    – 基于COCO数据集训练好的模型,使用自己的数据集,来微调最后一层的神经网络。所以该阶段设置时训练参数时,只将3个输出模块的最后一层的参数传入到优化器进行训练。
    tf.control_dependencies该函数是指定某些操作的依赖关系。下面的这个例子表示:op_c/op_d的执行必须在op_a/op_b执行之后完成,以为就是说执行顺序为op_a, op_b, op_c, op_d。
    tf.no_op( ):表示什么也不操作。
with tf.control_dependencies([op_a, op_b]):
    op_c
    op_d


       with tf.name_scope("define_first_stage_train"):
           # 将神经网络最后一层的参数,设置为可训练参数
           self.first_stage_trainable_var_list = []
           for var in tf.trainable_variables():
               var_name = var.op.name
               var_name_mess = str(var_name).split('/')
               if var_name_mess[0] in ['conv_sbbox', 'conv_mbbox', 'conv_lbbox']:
                   self.first_stage_trainable_var_list.append(var)
           
           # 设置训练的优化器,并将可训练参数传入
           first_stage_optimizer = tf.train.AdamOptimizer(self.learn_rate).minimize(self.loss,
                                                     var_list=self.first_stage_trainable_var_list)
           with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
               with tf.control_dependencies([first_stage_optimizer, global_step_update]):
                   with tf.control_dependencies([moving_ave]):
                       self.train_op_with_frozen_variables = tf.no_op()
                       
  • 6神经网络的define_second_stage_train】:训练的第二阶段
    – 第二阶段就将所有可训练的参数,传入优化器中进行训练,使整个网络进行微调。
    – 其他训练方面的设置与第一阶段一致

     with tf.name_scope("define_second_stage_train"):
           second_stage_trainable_var_list = tf.trainable_variables()
           second_stage_optimizer = tf.train.AdamOptimizer(self.learn_rate).minimize(self.loss,
                                                     var_list=second_stage_trainable_var_list)

           with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
               with tf.control_dependencies([second_stage_optimizer, global_step_update]):
                   with tf.control_dependencies([moving_ave]):
                       self.train_op_with_all_variables = tf.no_op()
                       
  • 7神经网络的loader_and_saver】:

       with tf.name_scope('loader_and_saver'):
           self.loader = tf.train.Saver(self.net_var)
           self.saver  = tf.train.Saver(tf.global_variables(), max_to_keep=10)
           
  • 8神经网络的summary】:
    – 设置训练时的日志文件。

       with tf.name_scope('summary'):
           tf.summary.scalar("learn_rate",      self.learn_rate)
           tf.summary.scalar("giou_loss",  self.giou_loss)
           tf.summary.scalar("conf_loss",  self.conf_loss)
           tf.summary.scalar("prob_loss",  self.prob_loss)
           tf.summary.scalar("total_loss", self.loss)

           logdir = "./data/log/"
           if os.path.exists(logdir): shutil.rmtree(logdir)
           os.mkdir(logdir)
           self.write_op = tf.summary.merge_all()
           self.summary_writer  = tf.summary.FileWriter(logdir, graph=self.sess.graph)
            

1.3 def train(self)


   def train(self):
       self.sess.run(tf.global_variables_initializer())
       try:
           print('=> Restoring weights from: %s ... ' % self.initial_weight)
           self.loader.restore(self.sess, self.initial_weight)
       except:
           print('=> %s does not exist !!!' % self.initial_weight)
           print('= > Now it starts to train YOLOV3 from scratch ...')
           self.first_stage_epochs = 0

       for epoch in range(1, 1+self.first_stage_epochs+self.second_stage_epochs):
           if epoch <= self.first_stage_epochs:
               train_op = self.train_op_with_frozen_variables
           else:
               train_op = self.train_op_with_all_variables

           pbar = tqdm(self.trainset)
           train_epoch_loss, test_epoch_loss = [], []

           for train_data in pbar:

              _, summary, train_step_loss, global_step_val = self.sess.run(
                   [train_op, self.write_op, self.loss, self.global_step],feed_dict={
                                               self.input_data:   train_data[0],
                                               self.label_sbbox:  train_data[1],
                                               self.label_mbbox:  train_data[2],
                                               self.label_lbbox:  train_data[3],
                                               self.true_sbboxes: train_data[4],
                                               self.true_mbboxes: train_data[5],
                                               self.true_lbboxes: train_data[6],
                                               self.trainable:    True,
               })

               train_epoch_loss.append(train_step_loss)
               self.summary_writer.add_summary(summary, global_step_val)
               pbar.set_description("train loss: %.2f" %train_step_loss)

           for test_data in self.testset:
              test_step_loss = self.sess.run( self.loss, feed_dict={
                                               self.input_data:   test_data[0],
                                               self.label_sbbox:  test_data[1],
                                               self.label_mbbox:  test_data[2],
                                               self.label_lbbox:  test_data[3],
                                               self.true_sbboxes: test_data[4],
                                               self.true_mbboxes: test_data[5],
                                               self.true_lbboxes: test_data[6],
                                               self.trainable:    False,
               })

               test_epoch_loss.append(test_step_loss)

           train_epoch_loss, test_epoch_loss = np.mean(train_epoch_loss), np.mean(test_epoch_loss)
           ckpt_file = "./checkpoint/yolov3_test_loss=%.4f.ckpt" % test_epoch_loss
           log_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
           print("=> Epoch: %2d Time: %s Train loss: %.2f Test loss: %.2f Saving %s ..."
                           %(epoch, log_time, train_epoch_loss, test_epoch_loss, ckpt_file))
           # self.saver.save(self.sess, ckpt_file, global_step=epoch)

您可能感兴趣的与本文相关的镜像

Yolo-v5

Yolo-v5

Yolo

YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的Joseph Redmon 和Ali Farhadi 开发。 YOLO 于2015 年推出,因其高速和高精度而广受欢迎

<think>我们正在讨论YOLOv5训练脚本train.py的输出参数含义。根据用户需求,我们需要详细解释train.py运行时输出的各项参数的含义。根据引用[1]和引用[3],我们可以看到train.py的典型运行命令,其中包含了一些参数,如--data,--weights,--cfg等。但是用户关心的是训练过程中输出的参数的含义,也就是训练日志中出现的那些指标。在YOLOv5训练过程中,控制台会输出每个epoch的训练结果,包括一些性能指标和损失值。这些输出通常包括以下几列:1.Epoch:当前训练的轮次。2.gpu_mem:GPU内存使用情况(单位GB)。3.box_loss:边界框回归损失。4.obj_loss:目标置信度损失(表示是否存在目标的损失)。5.cls_loss:分类损失(表示目标类别的损失)。6.labels:当前batch中标注的目标数量。7.img_size:输入图像的尺寸(通常为640x640)。8.其他可能包括精确度(precision)、召回率(recall)、mAP(meanAveragePrecision)等。此外,在训练过程中,每隔一定轮次会进行验证,并输出验证集上的指标,如mAP@0.5、mAP@0.5:0.95等。现在,让我们详细解释这些参数:1.**Epoch**:表示当前的训练轮次。一个epoch表示整个训练数据集被遍历一次。2.**gpu_mem**:当前GPU内存的使用量(以GB为单位)。这个值可以帮助监控显存占用,避免超出显存容量。3.**box_loss**:边界框回归损失。YOLOv5使用CIoU(Complete-IoU)损失函数来计算预测框和真实框之间的差异。这个损失值越小,表示边界框预测越准确。4.**obj_loss**:目标置信度损失。该损失衡量模型对每个网格单元中是否存在目标的预测能力。它使用二元交叉熵损失函数。5.**cls_loss**:分类损失。该损失衡量模型对目标类别的预测能力。如果数据集中有多个类别,则使用交叉熵损失函数。6.**labels**:当前batch中所有图像中标注的目标(即真实框)的总数。7.**img_size**:输入到网络的图像尺寸。默认情况下,YOLOv5使用640x640的输入尺寸。在验证阶段,我们会看到更多的评估指标:8.**Precision(P)**:精确率,表示模型预测为正例的样本中真正为正例的比例。公式为:$Precision=\frac{TP}{TP+FP}$,其中TP为真正例,FP为假正例。9.**Recall(R)**:召回率,表示实际为正例的样本中被正确预测为正例的比例。公式为:$Recall=\frac{TP}{TP+FN}$,其中FN为假负例。10.**mAP@0.5**:表示在IoU阈值为0.5时的平均精度(meanAveragePrecision)。它是所有类别AP(AveragePrecision)的平均值。11.**mAP@0.5:0.95**:表示在IoU阈值从0.5到0.95(步长0.05)的多个阈值下的平均mAP。这个指标更加严格,因为它要求边界框在多种IoU阈值下都有良好的表现。在训练过程中,我们还会看到一些学习率(lr)的值,以及训练时间等信息。下面是一个典型的训练输出行(示例):Epochgpu_memboxobjclslabelsimg_size0/2992.76G0.085620.031720.02317128640:100%|██████████|85/85[00:35<00:00,2.41it/s]ClassImagesLabelsPRmAP@.5mAP@.5:.95:100%|██████████|21/21[00:07<00:00,2.88it/s]all1319290.7490.6140.6850.435解释:-第一行是训练过程:当前是第0轮(总共299轮),GPU内存使用2.76GB,边界框损失0.08562,目标置信度损失0.03172,分类损失0.02317,当前batch中总共有128个标注目标,图像尺寸为640。-第二行是验证过程:在验证集上,类别&#39;all&#39;(所有类别)的指标:验证图像数量131张,标签数量929个,精确率(P)为0.749,召回率(R)为0.614,mAP@0.5为0.685,mAP@0.5:0.95为0.435。注意:在验证过程中,每个类别都会计算指标,最后还会计算所有类别的平均值(这里用&#39;all&#39;表示)。另外,在训练开始前,通常还会输出模型的结构信息、参数数量、梯度优化策略等信息。以上就是YOLOv5训练脚本train.py输出参数的基本含义。这些参数对于监控训练过程、调整超参数和评估模型性能至关重要。为了帮助用户进一步理解,我们可以生成一些相关问题:§§相关问题§§1.如何根据训练输出的损失值判断模型是否在正常训练?2.mAP@0.5和mAP@0.5:0.95有什么区别?为什么需要两个指标?3.YOLOv5训练中,哪些因素会影响精确率(P)和召回率(R)?4.训练过程中,如果发现box_loss不下降,可能是什么原因?如何解决?</think>### YOLOv5 train.py 输出参数详解YOLOv5 训练过程中,`train.py` 会输出多类关键参数,主要分为**训练指标**、**性能指标**和**资源监控**三类。以下是详细解释: #### 1. **训练指标 (Training Metrics)** - **`Epoch`**: 当前训练轮次和总轮次(如 `10/300` 表示共300轮,当前第10轮) - **`gpu_mem`**: GPU显存占用(如 `3.2G`) - **`box_loss`**: 边界框回归损失,衡量预测框与真实框的匹配度,目标是最小化该值 - **`obj_loss`**: 目标置信度损失,判断网格内是否存在目标 - **`cls_loss`**: 分类损失,评估目标类别预测准确性 - **`labels`**: 当前批次(batch)中标注的目标数量 - **`img_size`**: 输入图像尺寸(默认 `640`) #### 2. **性能指标 (Validation Metrics)** 验证阶段输出的关键指标: - **`P` (Precision)**: 精确率 $Precision = \frac{TP}{TP+FP}$ 表示预测为正样本中实际为正的比例 - **`R` (Recall)**: 召回率 $Recall = \frac{TP}{TP+FN}$ 表示实际正样本中被正确预测的比例 - **`mAP@.5`**: IoU阈值=0.5时的平均精度(所有类别的AP平均值) - **`mAP@.5:.95`**: IoU阈值从0.5到0.95(步长0.05)的平均mAP,更严格的综合指标 - **`Class`**: 类别名称(`all` 表示所有类别平均值) #### 3. **资源监控 (Resource Monitoring)** - **`lr/pg`**: 当前学习率(如 `0.01`)和优化器参数组索引 - **`time`**: 单个epoch耗时(如 `0:20` 表示20秒) - **`rate`**: 处理速度(如 `2.5it/s` 表示每秒处理2.5个批次) #### 示例输出解析 ```plaintext Epoch gpu_mem box obj cls labels img_size 10/300 3.2G 0.05231 0.02145 0.00876 64 640: 100% Class Images Labels P R mAP@.5 mAP@.5:.95 all 1000 5632 0.865 0.792 0.842 0.612 ``` - **解读**:第10轮训练,显存占用3.2GB,边界框损失0.052,验证集mAP@0.5达84.2%,综合mAP@0.5:0.95为61.2%[^1][^3]。 #### 关键说明 - 损失值**持续下降**表明训练有效,若**长期不降**需调整超参数 - **mAP@.5:.95 > 50%** 通常表示模型性能良好 - **GPU显存突增**可能提示数据加载异常或批次过大 - 验证指标**每轮结束时更新**,训练指标**实时更新**[^2] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值