看过上一篇的同学们应该都知道,今天我们要进入make_labels这个关键的函数了
值得一提的是,今天上午来上班的时候,发现自己的电脑歇菜了,这外星人也不经用啊,我担心的是我的里面的代码和数据集怎么办,可急死我了。我怀疑是昨天卸载了360,这个流氓软件肯定动我系统文件了。强行360背锅。
没办法,捣鼓一上午也打不开,然后选择制作一个u盘启动盘,然后把关键的一些数据拷贝到U盘里,然后选择恢复出厂设置,不过,这个恢复出厂设置是真的⑨啊
144H remaining···············································,当场休克啊。
2.2 make_labels函数的详解
好了回到正题上来,我们先上make_labels函数的代码
def make_labels(resize_img_size, ANCHORS_GROUP, CLASS_NUM, boxes, ANCHORS_GROUP_AREA):
"""
:param resize_img_size: resize之后的图片的高宽
:param ANCHORS_GROUP: 9个anchor的宽高
:param CLASS_NUM: 类别总数
:param boxes: 目标的坐标位置
:param ANCHORS_GROUP_AREA: anchor的面积
:return: 一个featuremap
"""
labels = {}
for feature_size, anchors in ANCHORS_GROUP.items():
labels[feature_size] = torch.zeros(
[int(resize_img_size[0] / feature_size), int(resize_img_size[1] / feature_size), 3, 5 + CLASS_NUM])
for box in boxes:
cls, xmin, ymin, xmax, ymax = box
cx = (xmin + xmax) / 2
cy = (ymin + ymax) / 2
w = xmax - xmin
h = ymax - ymin
cx_offset, cx_index = math.modf(cx / feature_size)
cy_offset, cy_index = math.modf(cy / feature_size)
for i, anchor in enumerate(anchors):
anchor_area = ANCHORS_GROUP_AREA[feature_size][i]
p_w, p_h = w / anchor[0], h / anchor[1]
conf = IOU(gt_box=[xmin, ymin, xmax, ymax],
anchor=[cx - (anchor[0] / 2), cy - (anchor[1] / 2), cx + (anchor[0] / 2),
cy + (anchor[1] / 2)])
labels[feature_size][int(cy_index), int(cx_index), i] = torch.tensor(
[conf, cx_offset, cy_offset, torch.log(p_w), torch.log(p_h), *one_hot(CLASS_NUM, int(cls))]
)
return labels
打眼一瞅,妈呀,3个for循环,别怕,咱们一个一个来说。
参数我就不一一介绍了,代码里我写过注释的。
第一个for循环
for feature_size, anchors in ANCHORS_GROUP.items():
labels[feature_size] = torch.zeros(
[int(resize_img_size[0] / feature_size), int(resize_img_size[1] / feature_size), 3, 5 + CLASS_NUM])
featurefe_size是32,16,8就是下采样的倍数,anchors对应的就是当前这个featuremap下的3个anchor的宽高,然后我们创建一了全零的tensor,它的维度是【下采样featurefe_size后的高,下采样featurefe_size后的宽,3,5+类别总数】,比如一个图片的宽高是640*640,你下采样32倍后,此时这个label的维度就是 【20,20,3,5+类别总数】,括号里面的3表示3个anchor,5表示【conf,cx_offset,cy_offset,p_w,p_h】,讲到这里你就应该知道,我上一篇提问题的答案了吧。至于conf,cx_offset,cy_offset,p_w,p_h是什么,看下面。
第二个for循环
for box in boxes:
cls, xmin, ymin, xmax, ymax = box
cx = (xmin + xmax) / 2
cy = (ymin + ymax) / 2
w = xmax - xmin
h = ymax - ymin
cx_offset, cx_index = math.modf(cx / feature_size)
cy_offset, cy_index = math.modf(cy / feature_size)
这是不是回答了上面的5个里面的2个参数,cx_offset就是目标中心点的x坐标,cy_offset就是目标中心的y坐标,w就是目标的宽,h就是目标的高,然后你会看到我们又用了math.modf这个函数,它的作用就是分开小数和整数部分,一会还很有用的东西就是cx_index和cy_index是什么,我们第三个for循环来讲
第三个for循环
for i, anchor in enumerate(anchors):
anchor_area = ANCHORS_GROUP_AREA[feature_size][i]
p_w, p_h = w / anchor[0], h / anchor[1]
conf = IOU(gt_box=[xmin, ymin, xmax, ymax],
anchor=[cx - (anchor[0] / 2), cy - (anchor[1] / 2), cx + (anchor[0] / 2),
cy + (anchor[1] / 2)])
labels[feature_size][int(cy_index), int(cx_index), i] = torch.tensor(
[conf, cx_offset, cy_offset, torch.log(p_w), torch.log(p_h), *one_hot(CLASS_NUM, int(cls))]
我们可以看到,我们用w和h除以了anchor的w,h,得到了p_w,p_h这个两个变量,这个两个变量也是5中的两个参数,那么为什么要除以anchor的w,h呢?这就是小马哥牛x的地方,大家慢慢体会。conf就是anchor和目标矩形框的IOU,至于什么是IOU,IOU就是两个矩形的交集/并集,最后我们就可以以往刚刚创建的全零的label里面填值了,填在哪里呢?就填在cx_index和cy_index处。我知道,这么讲下来还是有点抽象。于是我准备给大家画一个图来模拟一下。
这只是一个下采样8倍的featuremap的对应其中一个anchor计算过程。图画的不好,先这样,到时候让小罗帮我出一个精修的图。
这个部分是我觉得YOLO最难理解的部分了,不过理顺了,你就大彻大悟了。
由此可见你我理解起来都这么费劲的话,小马哥当时是多么强大啊,能想到这些真的是无敌的存在啊。再次致敬。
ok,数据准备的部分我们就到这里了,下一期我们就可以开始训练了
我要去搞我的那台歇菜的电脑了。
至此,敬礼,salute!!!!
差点忘了咩咩狗,上图