yolov2架构总结
模型细节
yolov2 损失函数
Loss总结
正负样本理解
推理(VOCdata上)
思考:
YOLOv2的优缺点:
优点:
缺点:
如何优化YOLOv2?
参考
图来自:2.1 YOLO入门教程:YOLOv2(1)-解读YOLOv2 - 知乎
图来自:【精读AI论文】YOLO V2目标检测算法_哔哩哔哩_bilibili
Joseph Redmon的官方代码: darknet/region_layer.c at master · pjreddie/darknet · GitHub
AlexeyAB版本代码: darknet/region_layer.c at master · AlexeyAB/darknet · GitHub
下面以 AlexeyAB版本讨论:
代码注释参考:Darknet/region_layer.c at master · BBuf/Darknet · GitHub
yolov2 输出 13*13*5*(4+1+20) 张量(VOC数据集)
13*13 个 grid cell;每个 grid cell 有5个 预测框,每个预测框 有 4个坐标(x, y, w, h) + 1 个置信度(c) + 20 个条件类别概率。
对于每张图像,损失函数包含两部分:
Joseph Redmon版本中, coord_scale = coord_scale * (2 - truth.w*truth.h)。有人说是:
在计算boxes的w和h误差时,YOLOv1中采用的是平方根以降低boxes的大小对误差的影响,而YOLOv2是直接计算,但是根据ground truth的大小对权重系数进行修正:l.coord_scale * (2 - truth.w*truth.h)(这里和都归一化到(0,1)),这样对于尺度较小的其权重系数会更大一些,可以放大误差,起到和YOLOv1计算平方根相似的效果。
参考链接
但是我在最新代码中没有发现这句,估计是代码版本问题。代码中是这句:
float iou = delta_region_box(truth, l.output, l.biases, best_n, best_index, i, j, l.w, l.h, l.delta, l.coord_scale);
计算两个框的IOU和 tx, ty, tw, th 与传入框的x, y, w, h 的LOSS
float delta_region_box(box truth, float *x, float *biases, int n, int index, int i, int j, int w, int h, float *delta, float scale)
{
box pred = get_region_box(x, biases, n, index, i, j, w, h);
float iou = box_iou(pred, truth);
float tx = (truth.x*w - i);
float ty = (truth.y*h - j);
float tw = log(truth.w / biases[2*n]);
float th = log(truth.h / biases[2*n + 1]);
if(DOABS){
tw = log(truth.w*w / biases[2*n]);
th = log(truth.h*h / biases[2*n + 1]);
}
delta[index + 0] = scale * (tx - logistic_activate(x[index + 0])) * logistic_gradient(logistic_activate(x[index + 0]));
delta[index + 1] = scale * (ty - logistic_activate(x[index + 1])) * logistic_gradient(logistic_activate(x[index + 1]));
delta[index + 2] = scale * (tw - x[index + 2]);
delta[index + 3] = scale * (th - x[index + 3]);
return iou;
}
重新整理下源码中的Loss 函数:w,h代表特征图的宽高,B代表每个grid cell 预测框的个数 = A(Anchor框)的个数。上标C表示计算置信度损失,上标x,y,w,h 表示计算坐标损失,上标Class表示计算类别损失。
表示:当前cell, 一个预测框 B 和全图标注框 T 的 maxIOU <= 0.6,那么该项为1,否则为0。表示只在迭代前12800张图像时为1,否则为0。。
表示:当前标注框T,中心点落在的那个cell中,T与该cell中所有 Anchor,计算只考虑形状,不考虑位置的IOU((x,y)移动到(0,0)),取最大的为 。也就是一个有标注框中心落在的 cell 中,只有最大的对应的B,参与了 后面的三项损失计算。其中,置信度的标签与YOLOv1一致,为该B与当前标注框T的IOU。
所以总的Loss = L1 + L2。
网上大佬总结的为:
含义和我总结的是一致的。
yolov1损失函数的设计与yolov2的区别是什么?
正样本的选择yolov1和yolov2是一致的,即标注框的中心落在哪个cell,哪个cell中的一个预测框就“负责”预测该标注框,这里“负责”的意思是,该框被选为了正样本,那么会计算该预测框与真实框的 坐标损失、分类损失和置信度损失。置信度损失的标签定义v1和v2依旧是一样的,就是预测框和标注框的IOU。
不同点在哪里呢?
如何选择 正样本,也就是那个预测框,v1和v2 是不同的。
v1 是 选择两个预测框与真实框的IOU最大的那个。
v2因为引入了Anchor ,做法却是 计算当前cell中的所有Anchor 与 当前标注框的IOU,选择最大的IOU的Anchor 对应的 预测框 作为正样本。并且计算该IOU,并没有考虑位置,而是把二者的(x, y) 移动到 (0, 0)计算的,估计这么做是为了简化吧。
为什么v2是选择 Anchor和标注框计算IOU,从而选择正样本?代码中是这么写的。
l.bias_match和 DOABS 都为1,因此预测框的 w和h 变为了 Anchor的,x, y变成了 0,0。因为Anchor和预测框是1对1的,这样就得到了最合适的预测框的索引。然后通过该索引计算正样本的置信度标签,也就是该预测框和标注框的IOU。
for(n = 0; n < l.n; ++n){
int index = size*(j*l.w*l.n + i*l.n + n) + b*l.outputs;
box pred = get_region_box(l.output, l.biases, n, index, i, j, l.w, l.h);
if(l.bias_match){
pred.w = l.biases[2*n];
pred.h = l.biases[2*n+1];
if(DOABS){
pred.w = l.biases[2*n]/l.w;
pred.h = l.biases[2*n+1]/l.h;
}
}
//printf("pred: (%f, %f) %f x %f\n", pred.x, pred.y, pred.w, pred.h);
pred.x = 0;
pred.y = 0;
float iou = box_iou(pred, truth_shift);
if (iou > best_iou){
best_index = index;
best_iou = iou;
best_n = n;
}
}
v1和v2负样本的选择的区别?
相同点:二者都是把负样本的置信度往0进行优化
不同点:如何选择负样本不同。
v1 把 正样本那个cell中那个低IOU值的预测框以及所有cell中没有标注框中心的那些预测框(每个cell 两个)设为 负样本。这些预测框的置信度往0优化。
v2 先计算当前cell 中 每个 预测框与 所有 标注框 的 最大IOU,一张图像输入,那么会有 13*13*5= 845 个最大IOU,也是一共 845个预测框,若每个最大IOU小于等于0.6,那么设置为负样本。将这些预测框的置信度往0优化。
yolov1因为有FC,所以固定输入448,输出为 7*7*30,然后是后处理。
yolov2因为没有FC,所以输入可变为 32倍,假设输入是416,那么输出为 13*13*5(4+1+20),然后是后处理。
二者的后处理一致。
yolo v1 和 v2 都是 把一张图像(W, H, 3)编码为一个3D张量,记为(w, h, c)。w和h表示将图像降采样了 W/w和H/h倍,而c表示将坐标(4) + 置信度(1) + 条件概率(20d)存到该向量中。而这25d向量就包含了提取的信息。输出张量的每个像素表示了图像中的某块感受野。
darknet/region_layer.c at master · AlexeyAB/darknet · GitHub
深度学习知识十四 yolo v2 损失函数源码(训练核心代码)解读和其实现原理、网络的输出格式_yangdeshun888的博客-CSDN博客
darknet源码阅读之region_layer.c_beingod0的摸爬滚打-CSDN博客
GitHub - BBuf/Darknet: AlexeyAB-DarkNet源码解析