4、TensorFlow2.0 实现Yolo2(Compose labels)

1.Compose labels

YOLO网络需要的形式是 [b,16,16,5,6] , 而我们的标签shape则是 [batch,max_boxes, 5],明显真实标签shape与网络预测输出shape不一致,无法做比较,损失函数就不能完成,为了完成损失函数或者说是真实标签与网络预测输出作比较,需要修改真实标签的形状。

YOLOV2损失函数包含三部分:

  1. 坐标损失: x , y , w , h x,y,w,h x,y,w,h
  2. 类别损失: class,根据自己的标签设定
  3. 置信度损失: confidence, anchors与真实框的IOU

针对损失函数,需要预先准备四个变量,分别是真实标签掩码,五维张量的真实标签,转换格式的三维张量真实标签,只包含类别的五维张量。

1.1首先我们想从5锚点中分别计算iou,选取最佳的anchors


IMGSZ = 512
GRIDSZ = 16
#我们上一篇通过K-Means计算出的pre_anchors
ANCHORS = [0.63, 0.69, 0.76, 0.93, 0.93, 1.0, 1.03, 1.09, 2.0, 2.06]


def process_true_boxes(gt_boxes,anchors):
	"""
    :param gt_boxes:[40,5] 一张真实标签的位置坐标信息
    :param anchors:YOLO的预设框anchors
    :return:
	"""
   
    # 512//16 = 32  计算网络模型从输入到输出的缩小比例
    scale = IMGSZ // GRIDSZ
    # [5,2] 将anchors转化为矩阵形式,一行代表一个anchors
    anchors = np.array(anchors).reshape((5,2))

    # mask for object
    #用来判断该方格位置的anchors有没有目标,每个方格有5个anchors
    detector_mask = np.zeros([GRIDSZ,GRIDSZ,5,1])
    # x-y-w-h-l
    #在输出方格的尺寸上[16, 16, 5]制作真实标签, 用于和预测输出值做比较,计算损失值
    matching_gt_box = np.zeros([GRIDSZ,GRIDSZ,5,5])
    # [N,5] x1-y1-x2-y2-l => x-y-w-h-l
    # 制作一个numpy变量,用于存储一张图片真实标签转换格式后的数据
    # 将左上角与右下角坐标转化为中心坐标与宽高的形式
    # [x_min, y_min, x_max, y_max] => [x_center, y_center, w, h]
    gt_boxes_grid = np.zeros(gt_boxes.shape)
    # DB: tensor => numpy
    gt_boxes = gt_boxes.numpy()
    for i,box in enumerate(gt_boxes):# [40,5]
        # box: [5],x1-y1-x2-y2
        # 512  => 16
        # 将左上角与右下角坐标转化为中心坐标与宽高的形式
        # [x_min, y_min, x_max, y_max] => [x_center, y_center, w, h]
        x = ((box[0]+box[2])/2)/scale
        y = ((box[1]+box[3])/2)/scale
        w = (box[2]-box[0])/scale
        h = (box[3]-box[1])/scale
        # [40,5] x-y-w-h-i
        # 将第 i 行的数据赋予计算得到的新数据
        gt_boxes_grid[i] = np.array([x,y,w,h,box[4]])

        if w*h > 0: # valid box
            # fine the best anchor
            # 用于筛选有效数据,当w, h为0时,表明该行没有目标,为无效的填充数据0
            
            best_anchor = 0
            best_iou = 0
            for j in range(5):
                # calcute IOU
                # 计算真实目标框有5个anchros的交并比,选出做好的一个anchors
                interct = np.minimum(w,anchors[j,0])*np.minimum(h,anchors[j,1])
               
                union = w*h + (anchors[j,1]*anchors[j,0]) - interct
                
                iou = interct/union
                #best iou 筛选最大的iou,即最好的
                if iou > best_iou:
                	#将更加优秀的anchors的索引赋值与之前定义好的变量
                    best_anchor = j
                    best_iou = iou  #记录最好的iou
            # found the best anchors
            if best_iou > 0:#用于判断是否有anchors与真实目标产生交并
            	# 向下取整,即是将中心点坐标转化为左上角坐标, 用于后续计算赋值
                x_coord = np.floor(x).astype(np.int32) 
                y_coord = np.floor(y).astype(np.int32)
                # [b,h,w,5,1]
                # 将最好的一个anchors赋值1,别的anchors默认为0
                # 图像坐标系的坐标与数组的坐标互为转置:[x,y] => [y, x]
                detector_mask[y_coord,x_coord,best_anchor] = 1
                # [b,h,w,5,x-y-w-h-l]
                 # 将最好的一个anchors赋值真实标签的信息[x_center, y_center, w, h, label],别的anchors默认为0
                """
                因为矩阵中第一维表示行,第二维表示列,比如a[4, 3],
                a有4行3列;但在图像坐标系中,横轴是x, 纵轴是y, 
                这也就是说y的值是图像的行数,x的值是图像的列数。
                所以在赋值中,需要将y写在第一维,x写在第二维,
                即 detector_mask[y_coord, x_coord, best_anchor] = 1。
                根据之前计算的IOU,可以知道与目标匹配最好的anchors的索引序号,
                然后对该anchors赋予相对应的值

                """
                matching_gt_box[y_coord,x_coord,best_anchor] = np.array([x,y,w,h,box[4]])
    # [40,5] => [16,16,5,5]
    # matching_gt_box:[16,16,5,5],用于计算损失值
    # detector_mask:[16,16,5,1],掩码,判断哪个anchors有目标
    # gt_boxes_grid:[40,5],一张图片中目标的位置信息,转化后的格式

    return matching_gt_box,detector_mask,gt_boxes_grid

1.2批量处理Compose labels

在训练过程中,训练batch_size一般不是1,有可能为2,4, 8, 16等等,所以需要将保存单张图片标签信息的变量合成为保存多张图片的变量,使用列表,然后矩阵化即可,至于矩阵化的原因,是因为矩阵容易操作,而且tensorflow中基本都是张量。具体代码如下:


def ground_truth_generator(db):
	 """
    构建一个训练数据集迭代器,每次迭代的数量由batch决定
    :param db:训练集队列,包含训练集原图片数据信息,标签位置[x_min, y_min, x_max, y_max, label]信息
    :return:
    """


    for imgs,imgs_boxes in db:
        # imgs: [b,512,512,3]b的值由之前定义的batch_size来决定
        # imgs_boxes: [b,40,5]不一定是40,要根据实际情况来判断
		
		# 创建三个批量数据列表
        # 对应上面函数的单个图片数据变量
        batch_matching_gt_boxes = []
        batch_detector_mask = []
        batch_gt_boxes_grid = []
        
        b = imgs.shape[0]#计算一个batch有多少张图片
        for i in range(b): # for each image
            matching_gt_box,detector_mask,gt_boxes_grid = process_true_boxes(imgs_boxes[i],ANCHORS)
            
            batch_matching_gt_boxes.append(matching_gt_box)
            
            batch_detector_mask.append(detector_mask)
            
            batch_gt_boxes_grid.append(gt_boxes_grid)

        #将其转化为矩阵形式并转化为tensor [b,16,16,5,1]
        detector_mask = tf.cast(np.array(batch_detector_mask),dtype=tf.float32)
        #将其转化为矩阵形式并转化为tensor,[b,16,16,5,5] x_center-y_center-w-h-l
        matching_gt_box = tf.cast(np.array(batch_matching_gt_boxes),dtype=tf.float32)
        #将其转化为矩阵形式并转化为tensor,[b,40,5] x_center-y_center-w-h-l
        gt_boxes_grid = tf.cast(np.array(batch_gt_boxes_grid),dtype=tf.float32)
		
		# [b,16,16,5]
        # 将所有的label信息单独分出来,用于后续计算分类损失值
        matching_classes = tf.cast(matching_gt_box[...,4],dtype=tf.int32)
        # 将标签进行独热码编码 [b,16,16,5,num_classes:3],
        matching_classes_oh = tf.one_hot(matching_classes,depth=3)
         # 将背景标签去除,背景为0
        # x_center-y_center-w-h-conf-l0-l1-l2 => x_center-y_center-w-h-conf-l1-l2
        # [b,16,16,5,2]
        matching_classes_oh = tf.cast(matching_classes_oh[...,1:],dtype=tf.float32)
        
        # [b,512,512,3]
        # [b,16,16,5,1]
        # [b,16,16,5,5]
        # [b,16,16,5,2]
        # [b,40,5]
        yield imgs,detector_mask,matching_gt_box,matching_classes_oh,gt_boxes_grid

1.3解释一段代码,这段代码开始我也不太明白,明白过来后,才发现及其重要,这里要感谢大神的解释:


# [b,16,16,5]
# 将所有的label信息单独分出来,用于后续计算分类损失值
matching_classes = tf.cast(matching_gt_box[...,4], dtype=tf.int32)
# 将标签进行独热码编码 [b,16,16,5,num_classes:3],
matching_classes_oh = tf.one_hot(matching_classes, depth=num_classes)
# 将背景标签去除,背景为0
# x_center-y_center-w-h-conf-l0-l1-l2 => x_center-y_center-w-h-conf-l1-l2
# [b,16,16,5,2]
matching_classes_oh = tf.cast(matching_classes_oh[...,1:], dtype=tf.float32)

如何将类别单独分出来,并另存为一个变量,就比较简单,matching_gt_box的shape为[b, 16, 16, 5, 5],最后一维代表的值为真实目标的坐标(x, y, w, h)和类别(label),所有只需要取该变量的最后一维的第5个值就可以,如上面代码所示。得到matching_classes变量后,事情并没有做完,因为网络输出shape为[b, 16, 16, 5, 7] 我的训练集只有2类,所以7表示x-y-w-h-confidece-label1-label2,不包含背景,类别数可以根据你的类别数修改。但实际类别是3类,即背景-label1-label2,虽然在网络输出中不包含背景,但自己需要知道在目标检测中,背景默认为一类,这也是为什么在xml解析这一小节中,制作标签时,默认将标签数加1,因为背景默认为0

因为网络输出不包含背景,所有我们需要将真实标签中的背景去除,去除的方法也比较简单,先将matching_classes热编码,另存为matching_classes_oh: [b, 16, 16, 5, 3],在matching_classes_oh的最后一维中的第一个值就是背景类别,只需要使用切片即可,如代码所示。最后matching_classes_oh的shape为[b, 16, 16, 5, 2],在最后一维的值形式为:[1, 0]:label1, [0, 1]:label2, [0, 0]:背景,也表示该anchors没有真实目标

1.4 可视化看一下经过处理后的数据

from matplotlib import pyplot as plt
from matplotlib import patches

def db_visualize(db):
    # imgs: [b,512,512,3]
    # imgs_boxes: [b,40,5]
    imgs,imgs_boxes = next(iter(db))
    
    img,img_boxes = imgs[0],imgs_boxes[0]
    
    f,ax1 = plt.subplots(1,figsize=(8,10))
    # display the image ,[512,512,3]
    ax1.imshow(img)
    for x1,y1,x2,y2,l in img_boxes: # [40,5]
        x1,y1,x2,y2 = float(x1),float(y1),float(x2),float(y2)
        w =x2-x1
        h = y2-y1
        if l == 1: # green for sugarweet
            color = (0,1,0)
        elif l ==2: # red for weed
            color = (0,0,1)
        else: # ignore invalid boxes
            break
        rect = patches.Rectangle((x1,y1),w,h,linewidth=2,edgecolor=color,
        facecolor='none')
        ax1.add_patch(rect)


#数据:aug_train_db  来自上一篇的(TensorFlow2 一步一步实现Yolo2.数据集预处理:图片增强)

train_gen = ground_truth_generator(aug_train_db)
img,detector_mask,matching_gt_box,matching_classes_oh,gt_boxes_grid =next(train_gen)
img,detector_mask,matching_gt_box,matching_classes_oh,gt_boxes_grid=\
    img[0],detector_mask[0],matching_gt_box[0],matching_classes_oh[0],gt_boxes_grid[0]
fig,(ax1,ax2) = plt.subplots(2,figsize=(5,10))
ax1.imshow(img)
# [b,16,16,5,1] => [16,16,1]
mask = tf.reduce_sum(detector_mask,axis=2)
ax2.matshow(mask[...,0]) # [16,16]

在这里插入图片描述

到这里,前期所有工作已经完成,下一篇开始搭建YOLO2网络。

参考学习自以下大神博客:https://blog.csdn.net/qq_37116150/article/details/105451627#4.1%20%E5%8D%95%E5%BC%A0%E5%9B%BE%E7%89%87%C2%A0

https://blog.csdn.net/python_LC_nohtyp/article/details/104842099

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: yolov3是一种目标检测算法,使用TensorFlow 2.实现。它是一种基于深度学习的算法,可以在图像检测出多个物体,并给出它们的位置和类别。TensorFlow 2.是一种流行的深度学习框架,可以帮助开发者快速构建和训练深度学习模型。使用TensorFlow 2.实现yolov3可以帮助我们更好地理解和应用深度学习算法。 ### 回答2: YOLOv3是一种流行的目标检测算法,它结合了实时性和准确性。TensorFlow 2.0是Google发布的一款深度学习框架,具有易用性和灵活性。 YOLOv3的基本原理是将输入图像分成多个网格,每个网格负责检测其的多个目标。它使用卷积神经网络(CNN)来提取图像特征,并将预测分为三个尺度。通过为每个尺度计算不同大小的锚框(anchor)和类别概率,YOLOv3可以检测不同大小和类别的目标。此外,YOLOv3还使用了一种称为"Darknet53"的主干网络来提取图像特征。 TensorFlow 2.0提供了对YOLOv3目标检测算法的支持。它提供了易于使用的API,可以方便地构建和训练YOLOv3模型。此外,TensorFlow 2.0还提供了一系列方便的工具和函数,用于数据预处理、模型调优和结果可视化等。 使用TensorFlow 2.0构建YOLOv3模型的步骤包括:准备训练数据集、定义模型架构、训练模型和评估模型。首先,需要准备一个包含目标标签和边界框的数据集。然后,定义YOLOv3模型的网络架构,并根据数据集进行模型训练。训练完成后,可以使用训练好的模型对新图像进行目标检测,并评估模型的性能。 总之,YOLOv3与TensorFlow 2.0结合使用可以提供一个强大的目标检测解决方案。它们的结合使得构建、训练和评估YOLOv3模型变得更加简单和高效。 ### 回答3: YOLOv3是一种用于目标检测的深度学习算法,它在TensorFlow 2.0框架上得到了实现和应用。 YOLOv3,全称为You Only Look Once Version 3,是YOLO系列算法的最新版本。YOLO算法通过将目标检测任务转化为一个回归问题,在一次前向传播过程直接预测图像的边界框和类别信息,从而实现了实时目标检测。YOLOv3不仅提供了更高的检测精度,还引入了一些改进策略,例如多尺度检测以及使用不同大小的边界框预测目标。 TensorFlow 2.0是谷歌开发的一款用于构建和训练机器学习模型的深度学习框架。相比于之前的版本,TensorFlow 2.0提供了更加简洁易用的API,并且与Keras紧密集成,使得模型的搭建和训练变得更加方便。此外,TensorFlow 2.0还引入了Eager Execution机制,可以实时监控模型训练过程,加速了迭代的实验和调试。 在TensorFlow 2.0框架实现YOLOv3算法可以借助于TensorFlow的强大计算能力和高效的神经网络API,方便地构建、训练和调优YOLOv3模型。同时,TensorFlow 2.0支持TensorBoard可视化工具,可以可视化模型结构和训练过程,便于理解和分析模型性能。此外,TensorFlow 2.0还提供了一系列丰富的工具和函数,例如数据增强、模型评估等,用于优化和完善YOLOv3算法的实现。 总之,YOLOv3算法的TensorFlow 2.0实现可以提供一个高效、简洁、易用的目标检测框架,帮助研究者和开发者更好地应用和推广YOLOv3算法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值