Open sjwvdjdb opened 1 year ago
@sjwvdjdb 您好,请问您想修改的是有监督还是半监督部分的正负样本分配策略呢
请问分别对应哪部分代码呢,我都想看看
一方面,我在yolov5l_custom_ssod.yaml文件的Loss部分加入了assigner_type == 'SimOTA',top_k=10,来使用loss.py的
self.ota_assigner = YOLOAnchorAssigner(self.na, self.nl, self.anchors, self.anchor_t, det.stride, \
self.nc, self.num_keypoints, single_targets=self.single_targets, ota=self.ota, top_k=self.top_k) 虽然没有报错,但是训练所得模型变差了 另一方面,我把yolov5l_custom_ssod.yaml文件的Loss.type由'ComputeLoss'改为’ComputeFastXLoss',它报了以下错误
Traceback (most recent call last):
File "/media/wyx/project/zlm_ssl/efficientteacher/train.py", line 86, in
我看到loss.py和ssod_loss.py中使用的都是YOLOAnchorAssigner,那么simota_assigner.py和tal_assigner.py是否是无用的?
@sjwvdjdb 您好,我给您介绍一下哈:1.assigner_type == 'SimOTA' 在这里的意思是使用YOLOv7中提到的基于anchor的OTA技术,所以理论上这个应该是会提升mAP的,这一块的代码我自己测试过一遍,但是我测试的是YOLOv7的配置,您可以看到v7的anchor设置其实与v5是不一样的,所以这里我需要是重新用v5的配置起一遍SimOTA来验证这个事哈,我会排期做这个实验 2. ComputeFastXLoss在这里以为着使用和YOLOX一样的anchor free的OTA技术,所以需要将anchor置为[1],然后head也需要改成YOLOX的head,其余可以保持不变 3.是的,当前我们的ssod_loss是只支持yolov5和yolov7这两种基于anchor的损失函数计算的,后续的更新还在验证中。
感谢回复,这几天测试,我发现即便是换成yolov7的配置也不行,效果并没有提升,我的配置如下:
Model: depth_multiple: 0.33 # model depth multiple width_multiple: 0.5 # layer channel multiple Backbone: name: 'YoloV7' activation: 'SiLU' Neck: name: 'YoloV7' in_channels: [512, 1024, 1024] out_channels: [256, 512, 1024] activation: 'SiLU' Head: name: 'YoloV7' activation: 'SiLU' anchors: [[16,27, 39,21, 23,42],[49,29, 73,28, 31,76],[61,67, 119,35, 88,80]] # P5/32] Loss: type: 'ComputeLoss' assigner_type: 'SimOTA' top_k: 10 cls: 0.3 obj: 0.7 anchor_t: 4.0
此外,loss.py文件的ComputeLoss类中的ota_loss函数,一开始用self.ota_assigner分配正负样本,到了中间又用了一次self.assigner分配正负样本,是否是这里出错导致的精度一般?我己经将第二次self.assigner后面的代码注释掉了,目前正在测试效果,如果结果正常我再给你新的回复
`def otaloss(self, p, targets): device = targets.device lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) bs, as, gjs, gis, ota_targets, anchors = self.ota_assigner(p, targets) pre_gen_gains = [torch.tensor(pp.shape, device=device)[[3, 2, 3, 2]] for pp in p]
# Losses
for i, pi in enumerate(p): # layer index, layer predictions
b, a, gj, gi = bs[i], as_[i], gjs[i], gis[i] # image, anchor, gridy, gridx
tobj = torch.zeros_like(pi[..., 0], device=device) # target obj
n = b.shape[0] # number of targets
if n:
ps = pi[b, a, gj, gi] # prediction subset corresponding to targets
# Regression
grid = torch.stack([gi, gj], dim=1)
pxy = ps[:, :2].sigmoid() * 2. - 0.5
#pxy = ps[:, :2].sigmoid() * 3. - 1.
pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i]
pbox = torch.cat((pxy, pwh), 1) # predicted box
selected_tbox = ota_targets[i][:, 2:6] * pre_gen_gains[i]
selected_tbox[:, :2] -= grid
iou = bbox_iou(pbox.T, selected_tbox, x1y1x2y2=False, CIoU=True) # iou(prediction, target)
lbox += (1.0 - iou).mean() # iou loss
# Objectness
tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio
# Classification
selected_tcls = ota_targets[i][:, 1].long()
if self.nc > 1: # cls loss (only if multiple classes)
t = torch.full_like(ps[:, 5:5+self.nc], self.cn, device=device) # targets
t[range(n), selected_tcls] = self.cp
lcls += self.BCEcls(ps[:, 5:5+self.nc], t) # BCE
obji = self.BCEobj(pi[...,-1], tobj)
lobj += obji * self.balance[i] # obj loss
if self.autobalance:
self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item()
tcls, tbox, indices, anchors = self.assigner(p, targets) # targets
for i, pi in enumerate(p): # layer index, layer predictions
b, a, gj, gi = indices[i] # image, anchor, gridy, gridx
tobj = torch.zeros_like(pi[..., 0], device=device) # target obj
n = b.shape[0] # number of targets
if n:
ps = pi[b, a, gj, gi] # prediction subset corresponding to targets
# Regression
pxy = ps[:, :2].sigmoid() * 2. - 0.5
pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i]
pbox = torch.cat((pxy, pwh), 1) # predicted box
iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target)
lbox += (1.0 - iou).mean() # iou loss
# Objectness
score_iou = iou.detach().clamp(0).type(tobj.dtype)
if self.sort_obj_iou:
sort_id = torch.argsort(score_iou)
b, a, gj, gi, score_iou = b[sort_id], a[sort_id], gj[sort_id], gi[sort_id], score_iou[sort_id]
tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * score_iou # iou ratio
# Landmark
if self.num_keypoints >0:
plandmarks = ps[:,-self.num_keypoints*2:]
for idx in range(self.num_keypoints):
plandmarks[:, (0+(2*idx)):(2+(2*idx))] = plandmarks[:, (0+(2*idx)):(2+(2*idx))] * anchors[i]
lmark = lmark + self.LandMarkLoss(plandmarks, tlandmarks[i], lmks_mask[i])
# Classification
if self.nc > 1: # cls loss (only if multiple classes)
t = torch.full_like(ps[:, 5:5+self.nc], self.cn, device=device) # targets
t[range(n), tcls[i]] = self.cp
lcls += self.BCEcls(ps[:, 5:5+self.nc], t) # BCE
# Append targets to text file
# with open('targets.txt', 'a') as file:
# [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)]
obji = self.BCEobj(pi[..., 4], tobj)
lobj += obji * self.balance[i] # obj loss
if self.autobalance:
self.balance = [x / self.balance[self.ssi] for x in self.balance]
lbox *= self.box_w
lobj *= self.obj_w
lcls *= self.cls_w
bs = tobj.shape[0] # batch size
loss = lbox + lobj + lcls
loss_dict = dict(box=lbox, obj=lobj, cls=lcls, loss=loss * bs)
# loss_dict = dict(box = lbox, obj = lobj, cls = lcls)
return loss * bs, loss_dict
`
我想我找到原因了,在built_ota_targets这一部分中有一句txywh = this_target[:, 2:6] * 640 #TODO,应该是对应640输入的,由于数据集需要,我的输入其实是320,我把数值修改以后好像就没有问题了,不知道我说的是否正确?
@sjwvdjdb 您好,我给您介绍一下哈:1.assigner_type == 'SimOTA' 在这里的意思是使用YOLOv7中提到的基于anchor的OTA技术,所以理论上这个应该是会提升mAP的,这一块的代码我自己测试过一遍,但是我测试的是YOLOv7的配置,您可以看到v7的anchor设置其实与v5是不一样的,所以这里我需要是重新用v5的配置起一遍SimOTA来验证这个事哈,我会排期做这个实验 2. ComputeFastXLoss在这里以为着使用和YOLOX一样的anchor free的OTA技术,所以需要将anchor置为[1],然后head也需要改成YOLOX的head,其余可以保持不变 3.是的,当前我们的ssod_loss是只支持yolov5和yolov7这两种基于anchor的损失函数计算的,后续的更新还在验证中。
您好,请问你用v7做实验,用的是yolov7的检测头吗?还是用的yolov5的
请问你这样在config的loss里面修改是属于修改了有监督还是半监督呢
@sjwvdjdb 您好,请问您想修改的是有监督还是半监督部分的正负样本分配策略呢
请问您能否讲解一下如何修改半监督的分类策略呢,是跟全监督的修改保持一致吗。因为我观察到默认的cfg中有use-ota选项
你好,如果我想改动正负样本分配策略,应该修改哪一部分代码,我看到了models/assigner中已经写有几种策略,但我不知道如何调用他们