YOLO3代码讲解
1.yolov3.cfg
1 | [convolutional] |
在YOLO3的配置文件中,有5种类型的层:
convolutional,
shortcut
1 | [shortcut] |
就是skip connection层,就行resnet用的,from -3的意思是该层输出是由前一层和前三层的输出叠加产生的。
upsample
1 | [upsample] |
双线性插值,因子为2
Route
1 | [route] |
如果属性layer有一个值,表示这层输出的是前第4层的特征图。
如果layer有两个值,表示这层输出的是这两个层通道拼接的特征图。
Yolo
1 | [yolo] |
YOLO层代表了之前描述的Detection层,anchor
表示9种anchor,但是只有被mask
索引的anchor才会被用到。比如这里是0,1,2,表示第1,2,3个anchor会被用到。在detection层每个cell预测3个box,在3个尺度上预测,最后有9个anchor。
net
1 | [net] |
下配置文件最开始有net
层,描述了输入网络的参数信息。在前传时并没有用到。
2.create module
1.convolutional layers
1 | if (x["type"] == "convolutional"): |
2.upsample
1 | #If it's an upsampling layer |
3.yolo
1 | #Yolo is the detection layer |
yolo就是检测层,分别在82,94,106层上
3.输出处理
中心坐标,objectness score经过sigmod函数变到0-1之间:
1 |
|
给中心坐标加上网格偏移:
1 | #Add the center offsets |
class score进行sigmod:
1 | prediction[:,:,5: 5 + num_classes] = torch.sigmoid((prediction[:,:, 5 : 5 + num_classes])) |
把检测特征图变成输入图片大小,
1 | prediction[:,:,:4] *= stride |
最后把不同尺度的检测特征图拼接到一个大的tensor上,
1 | #Transform |
最后输出的prediction维度为
$$1,10647,85$$
1-d:一个batch内的图片索引
2-d: $13\times13\times3+26\times26\times3+52\times52\times3=10647$
3-d: x,y,w,h,objrctness_score,class_score
4.做非极大值抑制。
1.先做object confidence的阈值抑制:
预测的tensor中包含$B\times10647$个hound ing box. objectness score低于阈值0.5的,把他的每个属性,即代表这个bounding box的整行都置为0.
1 | conf_mask = (prediction[:,:,4] > onfidence).float().unsqueeze(2) |
2.把坐标(x,y,w,h)转换成(x1,y1,x2,y2)形式
3.objectness_score和class_score处理
因为batch里面每张图片的真实检测个数可能不一样,所以每次只能执行一次非极大值抑制。也就是说,不能向量化这个非极大值抑制的操作。
1 | batch_size = prediction.size(0) |
write标志表示我们还没初始化输出,output.
先关心calss score最大的,也就是那【5:5+class_numbers】中最大的。从每行中把那80个类别分数抹掉,加上分数最高的类别索引,和该类别的分数。
1 | max_conf, max_conf_score = torch.max(image_pred[:,5:5+ num_classes], 1)#torch.max()返回两个值,一个是最大值,另一个是索引值。函数第二个参数为1表示按行取最大值并返回对应的索引值。 |
之前已经把objetness_score<0.5行都置为0了,现在去掉他们,也就是去掉这些bounding box.
1 | non_zero_ind = (torch.nonzero(image_pred[:,4])) |
4.然后执行非极大值抑制
首先提取出检测到的类别的detection。
1 | for cls in img_classes: |
根据objectness_score从高到低排序:
1 | conf_sort_index = torch.sort(image_pred_class[:,4], descending = True )[1] |
计算IOU的函数
1 | def bbox_iou(box1, box2): |
非极大值抑制
1 | if nms: |
总结
根据objectness_score的阈值筛一波,把不符合要求的整行全部置零,剩下15个box
把剩下的box的class_score处理,取最大值,得到每个box的类别
对每一个类别进行非极大值抑制
a.将该类的box按照objectness_score从高到低排列,
b.计算第i个和第i+1到最后一个box的iou,将>阈值的box筛掉,
c.再迭代。