YOLO思路理解

看了不少讲YOLO的文章,总感觉没有把关键细节说清楚,看了好像懂了,但细想到操作层面,又没完全懂。尝试简单总结捋一下,主要是v1,后面的不定期补充吧。

YOLOv1

整体思路是通过一些技巧,把目标检测转化为一个回归问题,一步到位,提高检测速度。原论文网络结构叫做darknet,各种卷积块+两个全连接层,当时还没发明批量归一化batch normalization,现在可以加上,中间的激活层选用Leaky ReLU,当然也可以使用其它深度网络,比如ResNet等。

首先看训练。将448*448(目标检测的分辨率要高于图像分类)的图片平均分成7*7=49cell,或叫grid。每个cell预测2个框bounding box,简称bbox,类似锚框anchor。这个bbox尺寸最小为0,最大为整个图片。每个bbox的定位localization只需要4个值,有不同的格式,如两点式(左上角和右下角坐标:x1, y1, x2, y2)、左上角式(左上角+宽高:x, y, w, h)、中心点式(中心点+宽高:x, y, w, h),原论文是中心点式。每个bbox还有1个置信度Conf,这就一共(4+1)*2=10个值。除了预测bbox,还要从比如20个物体种类里预测1个类别,每个类别给出一个概率,一共20个值,最后输出N*7*7*30N为图片数。这些数值可以随机初始化,两个bbox可以一大一小初始化,提高效率。

因为是回归任务,所以x, y, w, h都要进行归一化,x, y为相对于cell左上角的坐标,其值为0~1之间,w, h要除以图片的宽高,也就是448*448,其值也为0~1之间。有的文章将其除以cell的宽高,这导致w, h的值为0~7之间,也能计算,但感觉不合适。

刚才提到了置信度Conf。虽然1个cell预测了2个bbox,但YOLOv1里,1个cell只预测1个object,两个bbox其实是竞争关系,最终只有一个bbox得到了更新。训练计算损失时,看谁的Conf大,谁才被考虑进损失函数进行更新。而Conf=Pr(Object)*IoUIoU为预测的bboxground_truth_box的交并比。再看Pr(Object),如果ground_truth_box的中心坐标落在某cell里,那么Pr(Object)=1,否则为0。所以当Pr(Object)=1时,就是比谁的IoU大,当Pr(Object)=0时,label_Conf也为0。可以认为,最终预测输出的也是Pr(Object)IoU的乘积,只不过预测的Pr(Object)是一个连续值,而不是label的非1即0。

插一些闲话,这里有几个单词术语让人头大,试着自己理解下,不一定对:

  • grount truth为真实值,简称gt,是真实的目标物体的框子,所以,感觉也可以说成是objecttarget
  • label是标号,范围比gt大。gt只是正值,而在没有目标的区域,也是一个label
  • prediction是预测,detection是检测,infer是训练完了最后用于测试集的推理预测。其实意思差不多少。
  • 说到测试集test,一般这样理解:来了一批带label的数据,可以将其划分为训练集train和验证集validation,如果训练后的模型参数在验证集的表现还不错,那就把模型用在没有label的测试集test上预测推理,进行实践应用,所以test只用一次,且你不知道结果是否正确。不过,现在不少文章、代码所说的测试集其实是验证集,得自行分辨。

目标类别label_classes采用onehot编码,比如某个label_box是第5类,且中心在某个cell,那么label_classes就是[0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0],否则全为0。训练或推理时,输出就没这么干净了,每一个都是0~1之间的概率值,这个概率值其实是条件概率Pr(Class-i|Object),所以最终还要将这个概率值Pr(Class-i|Object)乘以Conf,然后取这20个中的最大值为最终预测种类,这样更保险,意思是你必须先有目标,再来谈这是个什么类别。

每个cell只有1个label_box,所以label形状其实应该是N*7*7*25,但为了与训练的N*7*7*30一致,会在后面补0。总结一下:

  • 如果一个cell包含了gt的中心点,那么label最后一维的张量类似这样:[0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, x, y, w, h, 1, 0,0,0,0,0],最后5个0为补足;该cell的训练值为[c0,... c19, x1, y1, w1, h1, Conf1, x2, y2, w2, h2, Conf2, ],如果bbox1的定位[x1, y1, w1, h1]与目标值[x, y, w, h]IoU更大,那么[c0,... c19, x1, y1, w1, h1, Conf1]会向label靠拢。至于bbox2[x2, y2, w2, h2, Conf2],可能是自生自灭吧?这30个量的顺序不关键,有一些不同的排列法。
  • 如果一个cell没有包含了label_box的中心点,那么最后一维的张量全是0,也就是torch.zeros(25),也补足至torch.zeros(30)。该cell的两个bbox的训练值的Conf1Conf2都会向0靠拢,其它值自生自灭?

可以看到,输出N*7*7*30中会有一些值自生自灭并不进行更新,那最终呈现结果时,会对输出进行筛选整理,比如筛掉低Conf、进行NMS等。

再看看原论文的损失函数。

image.png

其中S=7, B=21obj(i)表示如果label_box中心戳中了第i个cell,则值为1,否则为0。1obj(i,j)表示如果label_box中心戳中了第i个cell,且第j个bboxlabel_boxIoU较大,则值为1,否则为0。1noobj(i,j)与其相反。
第1行,1obj(i,j)bbox坐标与label_box的方差,一般权重λcoord=5
第2行,类似第1行,但宽高必须开方参与计算,避免大尺寸偏差重要性大于小尺寸的偏差。
第3行,类似1/2行,1obj(i,j)bboxConf的方差,label_Conf一般为1。
第4行,没有被目标中心戳中的cell的2个bboxConf的方差,一般权重λnoobj=0.5label_Conf为0。
第5行,1obj(i)cell的类别概率的方差损失。

推理时,预测了7*7*2=98bbox,首先筛掉低Conf的,比如小于0.4的,然后使用非极大值抑制NMSNMS一般是按照预测类别分别独立计算的(也有所有类一视同仁的做法),比如都是预测猫,那么选择一个Conf最大的bbox,如果其它也预测猫的bbox与这个最大ConfbboxIoU超过了一个阈值,例如0.5,那么就筛掉。这一部分不只是针对Yolo,而是目标检测通用做法。

怎么评价预测结果呢?这里引入一个全类平均正确率mAP,也是先按类计算,首先看预测框的IoU是否超过了阈值(比如0.5),超过了为TP,否则FP。然后将这些框按Conf倒序排列,每个gt最多一个框与之对应,开始统计Recall=TP/(TP+FN)Prec=TP/(TP+FP),然后求出Recall-Prec关系图的面积,即为AP,最后对所有种类求平均,则为mAPmAP越大越好,0.9就很不错了。更详细的做法是针对多个阈值进行计算再取平均,记为mAP@0.5:0.05:0.95

  • 问题1:如果两个目标中心戳中同一个cell,会发生什么事?
    超纲了,YOLOv1只能考虑一个cell一个object
  • 问题2:如果是同一类,但是是不同的目标呢?NMS怎么处理?
    这两个目标如果在同一个cell,见问题1;否则,这两个目标的bboxIoU会很小或者为0,所以NMS会都保留。
  • 问题3:如果置信度>1,或预测种类的概率之和>1,会怎样处理?
    对于置信度,数值看起来不合理,但应该也不影响最终结果的呈现,训练中可以试试用torch.clamp进行限制。预测种类的话,可以直接取最大值。另外,同一个目标属于两个种类,也不算离谱吧,比如正在播放猫和老鼠的电视机?后续再研究吧。
  • 问题4:如果两个bbox初始化后,与label_boxIoU都是0呢?
    IoU相同,代码默认取第一个值,所以第一个bbox会进行学习。

YOLOv2(Yolo 9000)

主要改进:

  1. 加入了batch normalization
  2. 448*448ImageNet上进行预训练。
  3. grid变成13*13,且每个cell预测9个bbox,并给出先验的大小。再根据COCOVOC的数据进行聚类,最后选择K=5,效果还可以。聚类时用1-IoU做为距离。
    image.png
  4. 摒弃全连接层,全用卷积。
  5. 优化bbox的坐标和宽高公式: bx = σ(tx) + cxby = σ(ty) + cybw = pw * exp(tw)bh = ph * exp(th)Pr * IoU = σ(to)t为需要学习的参数,bx, by, bw, bhbbox的定位,cx, cycell的左上角坐标,pw, ph为先验框的尺寸。为啥用指数,可能为了限制为正值?
  6. passthrough层将上一层一拆四(尺寸降半),与上一层的卷积结果(刚好也尺寸降半)直接叠加进行输出,从而保留上一层的小尺寸细节。有点残差的意思。
  7. 分层分类,采用WordTree,在分类数据集和检测数据集上联合训练,提高识别种类到9000+。

YOLOv3

主要改进:

  1. 基础网络升级至darknet53,之前是19。
  2. 分类损失采用二分类交叉熵损失binary cross-entropy loss,因为目标可能属于多个分类。
  3. 使用3个尺度预测,引入FPN (Feature Pyramid Network),特征图大小分别是8*816*1632*32

分隔线,pjreddie退出YOLO,后续版本重在工程应用。

YOLOv4

主要各种调参、缝合、数据增强。

YOLOv5

小而快,打比赛推荐。

YOLOX

旷世开源,效果不错。

总结

纸上得来终觉浅,试试吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容