YOLOV4中anchor与box之间的关系以及代码实现

YOLOV4中anchor与预测框之间的关系以及代码实现

有些同学已经学习目标检测有了一段时间,对于Fast系列和yolo系列的目标检测算法都如数家珍,包括每次改进升级用到了哪些tricks或者新的改进。现在也出现了很多anchor-free的算法,摒弃了anchor的使用。

但是,作者想说的是,我们是否真正的把anchor与预测框之间的关系搞得很明白,是否阅读过每一行anchor相关的代码?笔者近阶段写了一系列的博文均以代码为核心,分析算法思想,希望可以帮助大家将理论知识应用于实际而不只是读了多少篇论文,看了多少个实验结果。

Let's Go:

feat = np.random.normal(0,0.5,[4,13,13,75])
anchors = [[142, 110],[192, 243],[459, 401]]

本次示例专注于anchor解析,故随机生成feat和某一层的anchors参数。feat的维度为(4, 13, 13, 75)。anchors维度为(3,2)

def yolo_head_simluate(feats, anchors, num_classes)

进入仿真函数

   grid_shape = np.shape(feats)[1:3] # height, width
    print(grid_shape)
    grid_y = np.tile(np.reshape(np.arange(0, stop=grid_shape[0]), [-1, 1, 1, 1]),
        [1, grid_shape[1], 1, 1])
    grid_x = np.tile(np.reshape(np.arange(0, stop=grid_shape[1]), [1, -1, 1, 1]),
        [grid_shape[0], 1, 1, 1])
    grid = np.concatenate([grid_x, grid_y],-1)
    print(np.shape(grid))

第一步,将grid进行维度变化,得到(13,13,1,2)的维度。上面这段复杂的代码目的只是改变grid的维度,并将第一维和第二维从0-12进行排序。

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

第二步:修改输出层特征维度,变为(batch_size,13,13,3,85)。

    box_xy = (sigmoid(feats[..., :2]) + grid)
    box_wh = np.exp(feats[..., 2:4]) * anchors_tensor
    box_confidence = sigmoid(feats[..., 4:5])
    box_class_probs = sigmoid(feats[..., 5:])

将预测框调成真实值,其中box_xy对应框的中心的,box_wh对应长和宽。

这段代码应该重点进行理解。引用论文中的示意图:

YOLOV4中anchor与box之间的关系以及代码实现_第1张图片

bx和by通过sigmod函数将输出值限定在0-1之间,再加上grid,获得距离中心坐标的偏移量。这里grid表示图上平均划分13*13后的位置。

bw和bh通过exp(feats[:,2:4]*anchor长宽获得。

grid通过concatenate函数生成,详细解释一下grid里有什么。grid的维度是(13,13,1,2),个人理解是:13*13个点,每个点中的维度是(1,2),也就是一行两列。两列中的值均是0-12排列。也就是每个点中表示这相应位置的数,既偏移量。如,第(0,3)点中存储的是[3,0]。

另外需要注意的是,这里有个python广播的用法,示例如下:

feats=np.arange(0,30).reshape((3,2,5))
print("feats.shape={}".format(feats.shape))
grid=np.ones((1,1,2))
print("grid.shape={}".format(grid.shape))
box_xy=feats[...,:2]+grid
print("box_xy.shape={}".format(box_xy.shape))
#结果:
feats.shape=(3, 2, 5)
grid.shape=(1, 1, 2)
box_xy.shape=(3, 2, 2)
 fig = plt.figure()
    ax = fig.add_subplot(121)
    plt.ylim(-2,15)
    plt.xlim(-2,15)
    plt.scatter(grid_x,grid_y)
    plt.scatter(5,5,c='black')
    plt.gca().invert_yaxis()


    anchor_left = grid_x - anchors_tensor/2 
    anchor_top = grid_y - anchors_tensor/2 
    print(np.shape(anchors_tensor))
    rect1 = plt.Rectangle([anchor_left[0,5,5,0,0],anchor_top[0,5,5,0,1]],anchors_tensor[0,0,0,0,0],anchors_tensor[0,0,0,0,1],color="r",fill=False)
    rect2 = plt.Rectangle([anchor_left[0,5,5,1,0],anchor_top[0,5,5,1,1]],anchors_tensor[0,0,0,1,0],anchors_tensor[0,0,0,1,1],color="r",fill=False)
    rect3 = plt.Rectangle([anchor_left[0,5,5,2,0],anchor_top[0,5,5,2,1]],anchors_tensor[0,0,0,2,0],anchors_tensor[0,0,0,2,1],color="r",fill=False)

    ax.add_patch(rect1)
    ax.add_patch(rect2)
    ax.add_patch(rect3)

    ax = fig.add_subplot(122)
    plt.ylim(-2,15)
    plt.xlim(-2,15)
    plt.scatter(grid_x,grid_y)
    plt.scatter(5,5,c='black')
    plt.scatter(box_xy[0,5,5,:,0],box_xy[0,5,5,:,1],c='r')
    plt.gca().invert_yaxis()

    pre_left = box_xy[...,0] - box_wh[...,0]/2
    pre_top = box_xy[...,1] - box_wh[...,1]/2

    rect1 = plt.Rectangle([pre_left[0,5,5,0],pre_top[0,5,5,0]],box_wh[0,5,5,0,0],box_wh[0,5,5,0,1],color="r",fill=False)
    rect2 = plt.Rectangle([pre_left[0,5,5,1],pre_top[0,5,5,1]],box_wh[0,5,5,1,0],box_wh[0,5,5,1,1],color="r",fill=False)
    rect3 = plt.Rectangle([pre_left[0,5,5,2],pre_top[0,5,5,2]],box_wh[0,5,5,2,0],box_wh[0,5,5,2,1],color="r",fill=False)

    ax.add_patch(rect1)
    ax.add_patch(rect2)
    ax.add_patch(rect3)

    plt.show()

上面这段代码用于画图显示,与anchor和box无关,不做详解。

你可能感兴趣的:(深度学习,深度学习,tensorflow,神经网络)