YOLOX icon indicating copy to clipboard operation
YOLOX copied to clipboard

simOTA提速建议

Open scsolaris opened this issue 3 years ago • 24 comments

测试发现训练速度瓶颈主要在SimOTA,其中的for loop一张一张处理图像无法充分发挥GPU并行计算的优势。有同学(miemie2013)已经实现了并行版SimOTA,去掉了for loop,一个batch的数据都可以并行处理,实测训练速度提升了几倍,建议官方采用: yolox_head_fast.py boxes.py 用法:用yolox_head_fast.py替换原来的yolo_head.py并改一下import,然后再把boxes.py里面的bboxes_iou_batch函数拷到原版yolox的boxes.py中就可以使用。

update1:提升速度的比率跟输入图像分辨率和batch size也有关系,分辨率越大提速越小,另外用了加速版之后batch size似乎可以比原版更大,从而可以进一步提升训练速度。

update2:原版主要有两处for loop被改成了并行,一处是循环一个batch内的每张图,另一处是dynamic_k_matching中循环每一个gt_idx,前者应该是影响并行度的主要瓶颈。因此batch size是影响加速比率的最大因素,batch size越大加速比率越大。而不同输入分辨率、不同模型大小以及不同显存大小限制了batch size的上限,小模型、小分辨率可以用更大的batchsize,加速比率可以多达几倍,大模型、大分辨率可能在显存小的GPU上batch size只能是1,串行跟并行就差不多了。我是在自己的数据集上用小分辨率训练,单个2080Ti上batch size为256,其他条件不变,仅仅把原版SimOTA换成并行版,加速比率可多达4倍。@Mobu59用的1080Ti 4卡batch size为16,单卡为4,加速比率为10%。如果用V100、A100等大显存的GPU,再尽量调大batch size,即便是大模型、大分辨率应该也可以加速不少。

update3:实测发现,如果mosaic增强做得比较狠,使得合成的图上一些gt框出界比较多,会导致用并行SimOTA训练不稳定,loss可能出现nan,也可能直接训练时崩溃。debug发现这很可能跟计算pair_wise_iou有关,加一些nan/inf的过滤处理会稳定一些,比如pair_wise_ious[torch.isnan(pair_wise_ious) | torch.isinf(pair_wise_ious)] = 0 不过即便如此还是有可能崩溃。 另外,减小mosaic增强的参数范围,并使用之前yolov5的box_candidates函数来过滤增强后的box,也能增加稳定性,但只是治标不治本的办法。

scsolaris avatar Jan 14 '22 05:01 scsolaris

mark

ronghuaiyang avatar Jan 14 '22 05:01 ronghuaiyang

mark

Mobu59 avatar Jan 14 '22 10:01 Mobu59

测试发现训练速度瓶颈主要在simOTA,其中的for loop一张一张处理图像无法充分发挥GPU并行计算的优势。有同学(miemie2013)已经实现了并行版simOTA,去掉了for loop,一个batch的数据都可以并行处理,实测训练速度提升了几倍,建议官方采用: https://github.com/miemie2013/miemiedetection/blob/main/mmdet/models/heads/yolox_head_fast.py 直接替换原来的yolo_head.py再简单改一下import就可以使用。

该head.py支持VOC格式的数据集吗?

vaerdu avatar Jan 16 '22 08:01 vaerdu

该head.py支持VOC格式的数据集吗? @vaerdu head跟数据集格式无关,输入head的是已经用dataset读取的图和label,只要dataset用的是支持voc格式的就行

scsolaris avatar Jan 16 '22 08:01 scsolaris

测试发现训练速度瓶颈主要在simOTA,其中的for loop一张一张处理图像无法充分发挥GPU并行计算的优势。有同学(miemie2013)已经实现了并行版simOTA,去掉了for loop,一个batch的数据都可以并行处理,实测训练速度提升了几倍,建议官方采用: https://github.com/miemie2013/miemiedetection/blob/main/mmdet/models/heads/yolox_head_fast.py 直接替换原来的yolo_head.py再简单改一下import就可以使用。

我试着用了一下,在我这个数据集上好像只能提速10%。。。

Mobu59 avatar Jan 17 '22 11:01 Mobu59

测试发现训练速度瓶颈主要在simOTA,其中的for loop一张一张处理图像无法充分发挥GPU并行计算的优势。有同学(miemie2013)已经实现了并行版simOTA,去掉了for loop,一个batch的数据都可以并行处理,实测训练速度提升了几倍,建议官方采用: https://github.com/miemie2013/miemiedetection/blob/main/mmdet/models/heads/yolox_head_fast.py 直接替换原来的yolo_head.py再简单改一下import就可以使用。

我试着用了一下,在我这个数据集上好像只能提速10%。。。

@Mobu59 你加载数据用了cache吗?可以看看GPU利用率,如果比较低,瓶颈可能在读图和预处理。用cache可以提速一倍,然后调一调worker数量还可以再提一点速度。也可能你的训练分辨率比较大,simOTA的处理时间相对较小,所以提速不明显。

scsolaris avatar Jan 17 '22 11:01 scsolaris

@Mobu59 另外,在不超出显存容量的前提下尽量加大batch size,提升并行度,也能加速训练

scsolaris avatar Jan 17 '22 11:01 scsolaris

没有用cache,分辨率的话是640*640的

Mobu59 avatar Jan 17 '22 11:01 Mobu59

没有用cache,分辨率的话是640*640的

@Mobu59 RAM够大就用cache吧,直接cache不行的话,可以试试把原始压缩的图像拷贝到/dev/shm目录下,也比直接从硬盘读要快很多。

scsolaris avatar Jan 17 '22 12:01 scsolaris

@scsolaris 我发现改成batch assign之后,显存占用多了不少,2080Ti跑不了yolox-s,你们有类似的情况吗

Joker316701882 avatar Jan 18 '22 03:01 Joker316701882

@scsolaris 我发现改成batch assign之后,显存占用多了不少,2080Ti跑不了yolox-s,你们有类似的情况吗

@Joker316701882 这个并行实现确实是以空间换时间,显存占用增加是肯定的 。不过我用小分辨率训练yolox-nano显存占用没有明显增加,也没试过yolox-s。

scsolaris avatar Jan 18 '22 03:01 scsolaris

@scsolaris 我发现改成batch assign之后,显存占用多了不少,2080Ti跑不了yolox-s,你们有类似的情况吗

@Joker316701882 这个并行实现确实是以空间换时间,显存占用增加是肯定的 。不过我用小分辨率训练yolox-nano显存占用没有明显增加,也没试过yolox-s。

我用的YOLOX_L,1080Ti4卡16batchsize,显存没有明显增加,跟之前一样的训练策略,是可以正常跑的

Mobu59 avatar Jan 18 '22 03:01 Mobu59

感觉没什么变化

mcmingchang avatar Jan 20 '22 03:01 mcmingchang

感觉没什么变化

@mcmingchang batch size比较小的话加速确实不明显

scsolaris avatar Jan 20 '22 03:01 scsolaris

@scsolaris 请问跑demo.py,时怎么调整batch_size?

tigerdhl avatar Jan 24 '22 05:01 tigerdhl

@scsolaris 请问跑demo.py,时怎么调整batch_size?

@tigerdhl 这个问题跟SimOTA没关系吧,demo.py不会用到SimOTA......而且demo.py的本意应该就是一张一张地跑,所以输入model时batch size为1,没有命令行参数来设置batch_size。 如果实在要用demo.py同时跑多张图,就需要自己改代码了,可以参考训练或验证的代码。

scsolaris avatar Jan 24 '22 06:01 scsolaris

@scsolaris 了解了

tigerdhl avatar Jan 24 '22 06:01 tigerdhl

torch.tile()不支持,可以直接替换为x_centers.repeat()? `x_centers = (x_shifts + 0.5 * expanded_strides_per_image).unsqueeze(0).unsqueeze(1) # [1, 1, A] 每个格子中心点的x坐标。单位是1像素。 print("x_centers shape1 : ", x_centers.size()) test = x_centers.repeat((N, G, 1))

===============输出====== x_centers shape1 : torch.Size([1, 1, 3549]) x_centers shape2 : torch.Size([16, 4, 3549]) `

多谢~

lunalulu avatar Mar 15 '22 03:03 lunalulu

@lunalulu torch.tile()是pytorch 1.8.0引入的新api,跟repeat确实是等效的,参考:https://github.com/pytorch/pytorch/pull/47974

scsolaris avatar Mar 15 '22 06:03 scsolaris

@scsolaris 谢谢答复~ 修改完后出现一个报错:

` File "/home/luna/projects/objectDetection/yolox_pdc/YOLOX_optim/yolox/models/yolox_head_fast.py", line 531, in get_assignments pair_wise_cls_loss = F.binary_cross_entropy(p, gt_clss, reduction='none') # [N, G, A, 80] │ │ │ └ tensor([[[[0., 0., 1.], │ │ │ [0., 0., 1.], │ │ │ [0., 0., 1.], │ │ │ ..., │ │ │ [0., 0., 1.], │ │ │ [0.,... │ │ └ tensor([[[[0.0004, 0.0004, 0.0003], │ │ [0.0006, 0.0008, 0.0004], │ │ [0.0015, 0.0015, 0.0007], │ │ ..., │ │ ... │ └ <function binary_cross_entropy at 0x7fa18d746950> └ <module 'torch.nn.functional' from '/opt/conda/lib/python3.7/site-packages/torch/nn/functional.py'>

RuntimeError: torch.nn.functional.binary_cross_entropy and torch.nn.BCELoss are unsafe to autocast. Many models use a sigmoid layer right before the binary cross entropy layer. In this case, combine the two layers using torch.nn.functional.binary_cross_entropy_with_logits or torch.nn.BCEWithLogitsLoss. binary_cross_entropy_with_logits and BCEWithLogits are safe to autocast. ` 🙏

lunalulu avatar Mar 15 '22 07:03 lunalulu

@scsolaris 你开了fp16吗?直接用binary_cross_entropy会报这个错,原作者没考虑这个问题,这是我的修改:

 # 二值交叉熵
 with torch.cuda.amp.autocast(enabled=False):
     p = p.float()
     gt_clss = one_hots.float()
     pair_wise_cls_loss = F.binary_cross_entropy(p, gt_clss, reduction='none')  # [N, G, A, 80]

其实就是在调用binary_cross_entropy前先把float16的tensor转换回float32。

scsolaris avatar Mar 15 '22 07:03 scsolaris

@scsolaris 优秀👍

lunalulu avatar Mar 15 '22 07:03 lunalulu

遇到训练过程中loss为nan/inf的情况报错:CUDA error: device-side assert triggered 可以尝试调小batchsize或者学习率来暂时解决这个情况。

fengkh avatar Aug 14 '23 02:08 fengkh

点赞!

Reaidu avatar Dec 11 '23 06:12 Reaidu