cursor日志0225
你这段手改里有一个关键错误:mask_np[pink_mask] = FSD_PINK_VALUE 在 RM 分支里不对,应该是 RM_PINK_VALUE。
你这段手改里有一个关键错误:
mask_np[pink_mask] = FSD_PINK_VALUE 在 RM 分支里不对,应该是 RM_PINK_VALUE。
我已经按你要求重新做了一遍,并且把 RM 的 train/val 在两个类里都补齐,和 FSD 触发逻辑保持一致:
已恢复并修正的内容
- RMSegmentation:已加后视镜折叠增强(train + val)
- RMSegmentation_sifting:也同步加了同样增强(防止 sifting 模式不一致)
- 粉色区域标签:统一为 RM_PINK_VALUE(表示无路面标识)
- 验证阶段 debug:也保存 RM 可视化图(沿用你当前配置开关)
你可以重点检查这些位置
SegmentationDataset.pyLines 1239-1263
if (self.mode == 'train' or (self.mode == 'val' and MIRROR_FOLD_APPLY_TO_VAL)) and should_apply_mirror_fold():
...
img_np[pink_mask] = MIRROR_FOLD_PINK_COLOR_RGB
mask_np[pink_mask] = RM_PINK_VALUE
SegmentationDataset.pyLines 1297-1328
_save_seg_debug("rm", img, mask, imagepath)
...
if MIRROR_FOLD_DEBUG_APPLY_TO_VAL:
_save_seg_debug("rm", img, mask, imagepath)
SegmentationDataset.pyLines 1534-1557
# RMSegmentation_sifting 同样的 mirror_fold 注入
mask_np[pink_mask] = RM_PINK_VALUE
SegmentationDataset.pyLines 1607-1638
# RMSegmentation_sifting 的 train/val debug 保存
_save_seg_debug("rm", ...)
另外我也把你前面被误改到 FSD 的地方纠回来了(FSD 保持 FSD_PINK_VALUE)。
你现在可以直接重新跑一轮,重点看 rm debug 图里粉色区是否稳定出现且无标识。
==================
CityBddSegmentation、CitySegmentation 类并未实际使用,以后不用专门改,不确定的时候可以问我下。现在有一个新需求,为fsd分支新增一个类别路沿,之前0代表不可行驶区域,1代表可行驶区域,现在新增2代表路沿,请帮我修改代码,让fsd分支支持这个新增类别
yolov5s_custom_seg_big.yaml
+1-1
n_segcls: 2
n_segcls: 2
n_segcls: 3
train2.py
+1-1
mIoU = test.seg_validation(model=ema.ema, valloader=seg_valloader, device=device, n_segcls=2,
mIoU = test.seg_validation(model=ema.ema, valloader=seg_valloader, device=device, n_segcls=2,
mIoU = test.seg_validation(model=ema.ema, valloader=seg_valloader, device=device, n_segcls=3,
test.py
+6-1
if n_segcls == 2:
'pixAcc: %.3f, mIoU: %.3f, class0: %.3f, class1: %.3f' % (pixAcc, mIoU, IoU[0], IoU[1]))
if n_segcls == 2:
if n_segcls in (2, 3):
'pixAcc: %.3f, mIoU: %.3f, class0: %.3f, class1: %.3f' % (pixAcc, mIoU, IoU[0], IoU[1]))
test_custom.py
+7-2
if n_segcls == 2:
'pixAcc: %.3f, mIoU: %.3f, class0: %.3f, class1: %.3f' % (pixAcc, mIoU, IoU[0], IoU[1]))
segtest_fsd(root=opt.segdata, weights=opt.weights, batch_size=64, n_segcls=2, base_size=opt.base_size) # 19 for cityscapes
if n_segcls == 2:
segtest_fsd(root=opt.segdata, weights=opt.weights, batch_size=64, n_segcls=2, base_size=opt.base_size) # 19 for cityscapes
if n_segcls in (2, 3):
'pixAcc: %.3f, mIoU: %.3f, class0: %.3f, class1: %.3f' % (pixAcc, mIoU, IoU[0], IoU[1]))
if len(IoU) == 3:
tbar.set_description(
'pixAcc: %.3f, mIoU: %.3f, class0: %.3f, class1: %.3f, class2: %.3f' % (pixAcc, mIoU, IoU[0], IoU[1], IoU[2]))
segtest_fsd(root=opt.segdata, weights=opt.weights, batch_size=64, n_segcls=3, base_size=opt.base_size) # 19 for cityscapes
已按你的新需求完成,且遵循“CityBddSegmentation、CitySegmentation 后续不主动改”的约定。
这次为 FSD 新增 2=路沿,我做了这些必要修改:
- models/yolov5s_custom_seg_big.yaml
- n_segcls 从 2 改为 3(FSD 头输出通道变为3)
- train2.py
- 训练内 FSD 验证调用从 n_segcls=2 改为 n_segcls=3
- 即 test.seg_validation(..., n_segcls=3, ...)
- test.py
- seg_validation() 中 FSD 分支选择从 if n_segcls == 2 改为 if n_segcls in (2, 3),保证3类时仍走 FSD 头
- 进度条显示新增 len(IoU)==3 的输出格式(class0/1/2)
- test_custom.py
- 同样把 FSD 头选择改为 if n_segcls in (2, 3)
- 新增 len(IoU)==3 的显示
- 脚本末尾 segtest_fsd(..., n_segcls=3, ...)
你需要确认的数据侧前提
为了真正训练出“路沿=2”,你的 FSD 标注 mask 里要有该类别值:
- 0 不可行驶
- 1 可行驶
- 2 路沿
并且不要把 2 映射成忽略类。当前 CustomSegmentation 流程只把 127/255 处理为忽略,不会吞掉 2。
如果你愿意,我下一步可以帮你加一个很小的检查:训练前随机扫几张 FSD 标注,打印是否出现类别 2,避免“配置改了但数据里没有路沿类”。
===============
网络结构中yolov5s_custom_seg_big.yaml (87) 是fsd分支的输出吧,那rm分支的输出在哪里
是的,yolov5s_custom_seg_big.yaml 里这一层就是“分割头入口”,但它同时输出 FSD 和 RM 两个分支,不是只输出 FSD。
关键点:
- 在 yaml 中只有一个分割头配置:
yolov5s_custom_seg_big.yamlLines 87-87
[[16, 12, 8], 1, SegMaskPSP, [n_segcls, 3, 512, False]],
- SegMaskPSP 在实现里返回的是两个张量:
yolo.pyLines 534-544
output_fsd = self.m(x[0])
output_rm = self.decoder1(feat)
return output_fsd,output_rm
所以 RM 输出不在 yaml 里单独再写一行,而是在这个 SegMaskPSP 模块内部 decoder1(feat) 产出。
训练代码也印证了这一点:
- FSD 用 pred[1][0]
- RM 用 pred_rm[1][1]
train2.pyLines 785-851
pred = model(imgs)
segloss = compute_seg_loss(pred[1][0], segtargets.to(device))
...
pred_rm = model(seg_rm_imgs)
seg_rm_loss = compute_seg_loss(pred_rm[1][1], seg_rm_targets.to(device))
所以结论:RM 分支输出就在同一个 SegMaskPSP 层里,是它返回 tuple 的第二个分量。
那n_segcls: 3 的改动会不会对rm分支造成影响?代码中格是怎么控制rm分支和fsd分支的类别和类别数量的
不会影响 RM 分支(按你当前这套代码实现来说)。
现在代码里怎么控制 FSD / RM 类别数
1) n_segcls 只喂给 FSD 输出通道
yaml 的 n_segcls 在建模时传给 SegMaskPSP:
yolo.pyLines 1387-1392
def parse_model(d, ch):
...
anchors, nc, gd, gw, n_segcls = ..., d['n_segcls']
在 SegMaskPSP 里:
- self.c_out = n_segcls(FSD通道数)
- FSD最后一层 Conv(..., self.c_out, ...)
yolo.pyLines 410-433
self.c_out = n_segcls
...
nn.Conv2d(c_hid//4, self.c_out, kernel_size=1, padding=0)
2) RM 通道数是单独写死的 class_num1 = 14
同一个 SegMaskPSP 内,RM 用的是另一条 decoder1 分支,输出通道是 self.class_num1,当前固定 14:
yolo.pyLines 414-460
self.class_num1 = 14
...
nn.Conv2d(c_hid//4, self.class_num1, kernel_size=1, padding=0)
所以你把 n_segcls: 2 -> 3,改变的是 FSD,不会改 RM 的 14 类。
3) 训练/验证也分开取分支
训练里:
- FSD 用 pred[1][0]
- RM 用 pred_rm[1][1]
train2.pyLines 825-851
segloss = compute_seg_loss(pred[1][0], ...)
seg_rm_loss = compute_seg_loss(pred_rm[1][1], ...)
验证里:
- FSD 传 n_segcls=3,走 outputs[1][0]
- RM 传 n_segcls=14,走 outputs[1][1]
结论
- n_segcls: 3 是给 FSD 新增“路沿类”用的,不会直接影响 RM 分支类别数。
- RM 类别数目前由 SegMaskPSP.class_num1 = 14 + 训练/验证中 RM 分支选择共同决定。
如果后续你想让 RM 类别数也可配置,我可以帮你改成 yaml 里单独加 n_rmcls。
更多推荐
所有评论(0)