Tensorflow2.0---YOLO V4-tiny网络原理及代码解析(三)- 损失函数的构建

40 篇文章 2 订阅
19 篇文章 43 订阅

Tensorflow2.0—YOLO V4-tiny网络原理及代码解析(三)- 损失函数的构建

YOLO V4中的损失函数与V3还是有比较大的区别的,具体的可以看YOLOV4与YOLOV3的区别
代码是在nets文件夹下面的loss.py文件中,在train.py中引用的是:

model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',
        			arguments={'anchors': anchors, 'num_classes': num_classes, 
        			'ignore_thresh': 0.5, 'label_smoothing': label_smoothing})(loss_input)

先来看下yolo_loss的参数:

def yolo_loss(args, #是一个列表,其中包含了预测结果和进行编码之后的真实框的结果,
					# [<tf.Tensor 'conv2d_17/BiasAdd:0' shape=(None, 13, 13, 75) dtype=float32>, 预测结果1
			        # <tf.Tensor 'conv2d_20/BiasAdd:0' shape=(None, 26, 26, 75) dtype=float32>, 预测结果2
			        # <tf.Tensor 'input_2:0' shape=(None, 13, 13, 3, 25) dtype=float32>, 真实框1
			        # <tf.Tensor 'input_3:0' shape=(None, 26, 26, 3, 25) dtype=float32>] 真实框2
			  anchors, #[[ 10.  14.]
					   # [ 23.  27.]
					   # [ 37.  58.]
					   # [ 81.  82.]
					   # [135. 169.]
					   # [344. 319.]]
			  num_classes, #['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'],共20个分类
			  ignore_thresh=.5, #阈值
			  label_smoothing=0.1, #标签平滑
			  print_loss=False, #是否打印损失
			  normalize=True): #是否做归一化

把预测的与真实的进行分割出来,
y_true是一个列表,包含两个特征层,shape分别为(m,13,13,75),(m,26,26,75)
yolo_outputs是一个列表,包含两个特征层,shape分别为(m,13,13,3,25),(m,26,26,3,25)

y_true = args[num_layers:]
yolo_outputs = args[:num_layers]

然后就开始以特征层数开始循环,这里就以(m,13,13,3,25)为例:
先获得真实框(m,13,13,3,25)的第5个位置的数据,如果在编码中该位置存在gt框,那么就设置为1,表示第(i,j)特征图中第k个锚点框包含物体,否则一切都设置为0

object_mask = y_true[l][..., 4:5]

然后,再获得真实框(m,13,13,3,25)的第6-26个位置的数据:

true_class_probs = y_true[l][..., 5:]

接着,进行标签平滑:

if label_smoothing:
    true_class_probs = _smooth_labels(true_class_probs, label_smoothing)
def _smooth_labels(y_true, label_smoothing):
    num_classes = tf.cast(K.shape(y_true)[-1], dtype=K.floatx())
    label_smoothing = K.constant(label_smoothing, dtype=K.floatx())
    return y_true * (1.0 - label_smoothing) + label_smoothing / num_classes

接着,就是yolo_head:

yolo_head(yolo_outputs[l], #yolo模型预测的结果,shape=(None,13,13,75)
          anchors[anchor_mask[l]], #预测结果所对应的anchor,这里为
						           #[[ 81.  ,82.],
						           # [135. ,169.],
						           # [344. ,319.]]
          num_classes, #voc数据集的class数量,为20
          input_shape, #(416,416)
          calc_loss=True) #是否计算损失函数,在模型预测阶段,该参数为False

下面这一段代码有点难理解,其实它的作用就是创建(13,13,1,2)的网格

grid_shape = K.shape(feats)[1:3] # height, width,为(13,13)
grid_y = K.tile(K.reshape(K.arange(0, stop=grid_shape[0]), [-1, 1, 1, 1]),
        [1, grid_shape[1], 1, 1])
grid_x = K.tile(K.reshape(K.arange(0, stop=grid_shape[1]), [1, -1, 1, 1]),
        [grid_shape[0], 1, 1, 1])
grid = K.concatenate([grid_x, grid_y])
grid = K.cast(grid, K.dtype(feats))

举个例子:
在这里插入图片描述
在这幅图片中就可以很好的看到最终其实就是生成了(13,13,1,2)的网格。

feats = K.reshape(feats, [-1, grid_shape[0], grid_shape[1], num_anchors, num_classes + 5])

将预测结果(m,13,13,75)分割成(m,13,13,3,25)。

box_xy = (K.sigmoid(feats[..., :2]) + grid) / K.cast(grid_shape[...,::-1], K.dtype(feats))
box_wh = K.exp(feats[..., 2:4]) * anchors_tensor / K.cast(input_shape[...,::-1], K.dtype(feats))
box_confidence = K.sigmoid(feats[..., 4:5])
box_class_probs = K.sigmoid(feats[..., 5:])

这四行代码的目的是:将预测值转换为真实值!
第一行:将预测结果的xy(None,13,13,3,2)先加上grid,然后除以(13,13),就得到了转化后的进行归一化的xy,shape=(None,13,13,3,2)。
第二行:将预测结果的wh(None,13,13,3,2)先乘anchor的尺寸,然后除以输入大小,最后再进行指数计算,得到转换后的wh,shape同xy。
第三行和第四行:将预测得到的confidence和class_prob进行sigmoid转化。

最后,就可以将预测结果进行decode为预测真实框的形式~

    if calc_loss == True:
        return grid, feats, box_xy, box_wh
    return box_xy, box_wh, box_confidence, box_class_probs

在计算loss的时候返回grid, feats, box_xy, box_wh
在预测的时候返回box_xy, box_wh, box_confidence, box_class_probs

pred_box = K.concatenate([pred_xy, pred_wh])

将上述box_xy, box_wh进行合并,shape=(None,13,13,3,4)


下面,还有一个loop_body函数,来看看它是干嘛的。

#-----------------------------------------------------------#
        #   对每一张图片计算ignore_mask
        #-----------------------------------------------------------#
        def loop_body(b, ignore_mask):
            #-----------------------------------------------------------#
            #   取出n个真实框:n,4
            #-----------------------------------------------------------#
            true_box = tf.boolean_mask(y_true[l][b,...,0:4], object_mask_bool[b,...,0])
            #-----------------------------------------------------------#
            #   计算预测框与真实框的iou
            #   pred_box    13,13,3,4 预测框的坐标
            #   true_box    n,4 真实框的坐标
            #   iou         13,13,3,n 预测框和真实框的iou
            #-----------------------------------------------------------#
            iou = box_iou(pred_box[b], true_box)

            #-----------------------------------------------------------#
            #   best_iou    13,13,3 每个特征点与真实框的最大重合程度
            #-----------------------------------------------------------#
            best_iou = K.max(iou, axis=-1)

            #-----------------------------------------------------------#
            #   判断预测框和真实框的最大iou小于ignore_thresh
            #   则认为该预测框没有与之对应的真实框
            #   该操作的目的是:
            #   忽略预测结果与真实框非常对应特征点,因为这些框已经比较准了
            #   不适合当作负样本,所以忽略掉。
            #-----------------------------------------------------------#
            ignore_mask = ignore_mask.write(b, K.cast(best_iou<ignore_thresh, K.dtype(true_box)))
            return b+1, ignore_mask

        #-----------------------------------------------------------#
        #   在这个地方进行一个循环、循环是对每一张图片进行的
        #-----------------------------------------------------------#
        _, ignore_mask = tf.while_loop(lambda b,*args: b<m, loop_body, [0, ignore_mask])

步骤解释:
1.先取出真实框存在物体的框的xywh
2.与预测框进行iou计算
3.找到对应每个真实框最大的iou的预测框,best_iou = (13,13,3)
4.判断预测框和真实框的最大iou小于ignore_thresh,则认为该预测框没有与之对应的真实框,这么做的目的是:忽略预测结果与真实框非常对应特征点,因为这些框已经比较准了,不适合当作负样本,所以忽略掉
5.把这些框放入ignore_mask中

		#-----------------------------------------------------------#
        #   真实框越大,比重越小,小框的比重更大。
        #-----------------------------------------------------------#
        box_loss_scale = 2 - y_true[l][...,2:3]*y_true[l][...,3:4]

        #-----------------------------------------------------------#
        #   计算Ciou loss
        #-----------------------------------------------------------#
        raw_true_box = y_true[l][...,0:4]
        ciou = box_ciou(pred_box, raw_true_box)
        ciou_loss = object_mask * box_loss_scale * (1 - ciou)

这一部分是进行预测与真实的ciou损失!但是代码实现中与论文中还是有一点区别的,在代码中还考虑到了真实框大小的因素:真实框越大,比重越小,小框的比重更大。(这里我就不写ciou的代码了,有机会单独写一个blog~),得到的ciou_loss = (None,13,13,3,1)。

最后,就是置信度损失和类别损失的计算了:

confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True)+ \
            (1-object_mask) * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True) * ignore_mask

class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[...,5:], from_logits=True)

第一行:先计算真实框存在的confidence_loss,加上不存在真实框的confidence_loss(这里要忽略那些ignore_mask里面的框)。
第二行:直接计算预测和真实的类别损失。

	num_pos += tf.maximum(K.sum(K.cast(object_mask, tf.float32)), 1)
    loss += location_loss + confidence_loss + class_loss

    loss = K.expand_dims(loss, axis=-1)

    if normalize:
        loss = loss / num_pos
    else:
        loss = loss / mf
    return loss

最后就是进行损失求和,若进行归一化,就将总损失除以正样本,要是不进行归一化,那就除以批次大小。最终得到最后的loss~

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》,课程链接 https://edu.csdn.net/course/detail/29865【为什么要学习这门课】 Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. 冗谈不够,放码过来!  代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。【课程内容与收获】 本课程将解析YOLOv4的实现原理和源码,具体内容包括:- YOLOv4目标检测原理- 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算- 代码阅读工具及方法- 深度学习计算的利器:BLAS和GEMM- GPU的CUDA编程方法及在darknet的应用- YOLOv4的程序流程- YOLOv4各层及关键技术的源码解析本课程将提供注释后的darknet的源码程序文件。【相关课程】 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括:《YOLOv4目标检测实战:训练自己的数据集》《YOLOv4-tiny目标检测实战:训练自己的数据集》《YOLOv4目标检测实战:人脸口罩佩戴检测》《YOLOv4目标检测实战:中国交通标志识别》建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。【YOLOv4网络模型架构图】 下图由白勇老师绘制  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进我的收藏吃灰吧~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值