接上篇文章,李沐沐神的《动手学深度学习》中的show_bboxes还是比较好理解的,于是来看这两个方法
以下内容建议对照源代码理解
首先我们来设置boxes1和boxes2的初始值
boxes1 = torch.tensor([[1,2,5,6],[2,1,4,6],[-1,2,7,6],
[1,2,5,8]])
boxes2 = torch.tensor([[0,3,5,7],[1,2,3,7],[0,4,5,7],
[0,5,5,7]])
设置了第一组的四个锚框的左横,下纵,右横,上纵坐标(详情上一篇文章)和第二组的四个锚框坐标
boxes1[:,2],boxes1[:,0]
'''结果'''
(tensor([5, 4, 7, 5]), tensor([ 1, 2, -1, 1]))
boxes1[:,3],boxes1[:,1]
'''结果'''
(tensor([6, 6, 6, 8]), tensor([2, 1, 2, 2]))
很显然这两个语句将这一组锚框的右横、左横和上纵、下纵坐标表示了出来,而右横坐标-左横坐标便得出了这一个锚框的长,上纵坐标-下纵坐标便得出了这个锚框的宽,相乘便是这个锚框的面积
下面的方法便是求一组锚框的面积
(boxes1[:,2]-boxes1[:,0])*(boxes1[:,3]-boxes1[:,1])
'''结果'''
tensor([16, 10, 32, 24])
与上面求得的各个坐标相对应
于是便有了这个方法
box_area = lambda boxes: ((boxes[:, 2] - boxes[:, 0]) *
(boxes[:, 3] - boxes[:, 1]))
下面的语句中包含
inter_upperlefts = torch.max(boxes1[:, None, :2], boxes2[:, :2])
inter_lowerrights = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])
而其中的torch.max(boxes1[:, None, :2], boxes2[:, :2])与 torch.min(boxes1[:, None, 2:], boxes2[:, 2:])实在让人费解,到底为什么要在boxes中增加一个None呢?
让我们带着上面假设的boxes1和boxes2继续向下看
首先我们要知道带None和不带None有什么区别
torch.max(boxes1[:,:2],boxes2[:,:2])
'''结果'''
tensor([[1, 3],
[2, 2],
[0, 4],
[1, 5]])
给boxes1中四个锚框取名为A1,A2,A3,A4,boxes2中四个锚框取名为B1,B2,B3,B4,能够看出这是将A1B1做比较,A2B2、A3B3、A4B4分别做比较
torch.max(boxes1[:,None,:2],boxes2[:,:2])
'''结果'''
tensor([[[1, 3],
[1, 2],
[1, 4],
[1, 5]],
[[2, 3],
[2, 2],
[2, 4],
[2, 5]],
[[0, 3],
[1, 2],
[0, 4],
[0, 5]],
[[1, 3],
[1, 2],
[1, 4],
[1, 5]]])
答案是将A1与所有B做比较,A2与所有B作比较…
接着来看min部分的代码
torch.min(boxes1[:, 2:], boxes2[:, 2:])
'''结果'''
tensor([[5, 6],
[3, 6],
[5, 6],
[5, 7]])
torch.min(boxes1[:, None, 2:], boxes2[:, 2:])
'''结果'''
tensor([[[5, 6],
[3, 6],
[5, 6],
[5, 6]],
[[4, 6],
[3, 6],
[4, 6],
[4, 6]],
[[5, 6],
[3, 6],
[5, 6],
[5, 6]],
[[5, 7],
[3, 7],
[5, 7],
[5, 7]]])
同样也是答案是将A1与所有B做比较,A2与所有B作比较…,这样就知道了加None的作用
像这张图,相交部分的下横坐标与左纵坐标取两个锚框的max值
相交部分的上横坐标与右纵坐标取两个锚框的min值
inters = (inter_lowerrights - inter_upperlefts).clamp(min=0)
inters
'''结果'''
tensor([[[4, 3],
[2, 4],
[4, 2],
[4, 1]],
[[2, 3],
[1, 4],
[2, 2],
[2, 1]],
[[5, 3],
[2, 4],
[5, 2],
[5, 1]],
[[4, 4],
[2, 5],
[4, 3],
[4, 2]]])
将这两组答案相减,便得到了所有锚框交接的长和宽,clamp(min=0)意思是将小于0的长和宽变为0,因为长和宽都不为0
将长和宽相乘便是相交锚框的面积
inter_areas = inters[:, :, 0] * inters[:, :, 1]
inter_areas
'''结果'''
tensor([[12, 8, 8, 4],
[ 6, 4, 4, 2],
[15, 8, 10, 5],
[16, 10, 12, 8]])
再算出原始锚框的面积
areas1 = box_area(boxes1)
areas2 = box_area(boxes2)
相交部分的所有面积(同样有None,人们也叫这个机制为广播机制)
union_areas = areas1[:, None] + areas2 - inter_areas
union_areas
'''结果'''
tensor([[24, 18, 23, 22],
[24, 16, 21, 18],
[37, 34, 37, 37],
[28, 24, 27, 26]])
相除便得到了io比
inter_areas / union_areas
''''''
tensor([[0.5000, 0.4444, 0.3478, 0.1818],
[0.2500, 0.2500, 0.1905, 0.1111],
[0.4054, 0.2353, 0.2703, 0.1351],
[0.5714, 0.4167, 0.4444, 0.3077]])
设置初始值
生成锚框的数量和真实锚框的数量
io比
num_anchors, num_gt_boxes = 4, 4
jaccard=torch.tensor([[0.5000, 0.4444, 0.3478, 0.1818],
[0.2500, 0.2500, 0.1905, 0.1111],
[0.4054, 0.2353, 0.2703, 0.1351],
[0.5714, 0.4167, 0.4444, 0.3077]])
max_ious, indices = torch.max(jaccard, dim=1)
max_ious, indices
'''结果'''
(tensor([0.5000, 0.2500, 0.4054, 0.5714]), tensor([0, 0, 0, 0]))
dim=0即在横方向比较,max_ious储存了所有行最大的io比,indices储存了最大io比的位置,这里很巧都是第一个最大
设置最小的io比,即小于这个的io比不做考虑
iou_threshold = 0.3
anc_i = torch.nonzero(max_ious >= iou_threshold).reshape(-1)
torch.nonzero(max_ious >= iou_threshold).reshape(-1)
'''结果'''
tensor([0, 2, 3])
只有序号为0,2,3的位置算作有效io比
而下一段代码
box_j = indices[max_ious >= iou_threshold]
box_j
'''结果'''
tensor([0, 0, 0])
表示了有效io比的行里最大的io比,与上面的anc_i对应
后面的就比较好理解了
剩下的多看看视频理解老师的思路就可以了