yolov5+csl旋转目标检测代码解析1
本篇主要记录学习yolov5+csl旋转目标检测的原理,主要是代码中损失函数部分的细节。参考知乎 略略略 https://zhuanlan.zhihu.com/p/358441134; yangxue https://zhuanlan.zhihu.com/p/111493759
一、Define criteria
源码位置:utils/loss.py
# Define criteria
BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device))
BCEtheta = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['theta_pw']], device=device))
BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device))
# BCEtheta是相对于yolov5自加的,csl基于角度分类的部分。
nn.BCEWithLogits()本质上和nn.BCELoss()没有区别,只是在BCELoss上对pred加了个logits函数(也就是sigmoid函数),例子如下:
import torch
import torch.nn as nn
label = torch.Tensor([1, 1, 0])
pred = torch.Tensor([3, 2, 1])
pred_sig = torch.sigmoid(pred)
loss = nn.BCELoss()
print(loss(pred_sig, label))
loss = nn.BCEWithLogitsLoss()
print(loss(pred, label))
loss = nn.BCEWithLogitsLoss()
print(loss(pred_sig, label))
输出结果分别为:
tensor(0.4963)
tensor(0.4963)
tensor(0.5990)
可以看到,nn.BCEWithLogitsLoss()相当于是在nn.BCELoss()中预测结果pred的基础上先做了个sigmoid,然后继续正常算loss。所以这就涉及到一个比较奇葩的bug,如果网络本身在输出结果的时候已经用sigmoid去处理了,算loss的时候用nn.BCEWithLogitsLoss()…那么就会相当于预测结果算了两次sigmoid,可能会出现各种奇奇怪怪的问题——比如网络收敛不了
二、loss计算
loss部分似乎没有过多的修改,在每个原本obj/cls等loss出现的地方加上theta(角度)损失就好,角度损失采用分类损失(损失函数都是BCE)。
三、head部分
backbone部分特征提取不是重点,添加csl的时候也不需要作修改,下面看一下head部分————detect层(位于models/yolo.py)
如图,输出部分相较于原来+180,即多了180个角度分类结果。之后类似改动(+180)不再赘述。
但是我对比了一下,整个yolo.py只有另外一处也是**no = na * (nc + 185)**这种改动,其余改动均是作者加的注释部分。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 不听话的兔子君!