常见问题解答¶
我们在这里列出了一些许多用户遇到的常见问题及其对应的解决方案。如果您发现任何常见问题并有帮助他人解决问题的方法,请随时丰富此列表。 如果这里的内容没有涵盖您的问题,请使用 提供的模板 创建一个问题,并确保您在模板中填写所有必要的信息。
PyTorch 2.0 支持¶
MMDetection 中绝大多数算法现在都支持 PyTorch 2.0 及其 torch.compile
函数。用户只需安装 MMDetection 3.0.0rc7 或更高版本即可享受此功能。 如果在使用过程中发现任何不支持的算法,请随时向我们反馈。 我们也欢迎社区的贡献,以基准测试使用 torch.compile
函数带来的速度提升。
要启用 torch.compile
函数,只需在 train.py
或 test.py
之后添加 --cfg-options compile=True
。 例如,要为 RTMDet 启用 torch.compile
,可以使用以下命令
# Single GPU
python tools/train.py configs/rtmdet/rtmdet_s_8xb32-300e_coco.py --cfg-options compile=True
# Single node multiple GPUs
./tools/dist_train.sh configs/rtmdet/rtmdet_s_8xb32-300e_coco.py 8 --cfg-options compile=True
# Single node multiple GPUs + AMP
./tools/dist_train.sh configs/rtmdet/rtmdet_s_8xb32-300e_coco.py 8 --cfg-options compile=True --amp
需要注意的是,PyTorch 2.0 对动态形状的支持尚未完善。 在大多数目标检测算法中,不仅输入形状是动态的,而且损失计算和后处理部分也是动态的。 这会导致使用 torch.compile
函数时训练速度变慢。 因此,如果您希望启用 torch.compile
函数,您应该遵循以下原则
输入网络的图像为固定形状,不是多尺度
设置
torch._dynamo.config.cache_size_limit
参数。 TorchDynamo 将转换并缓存 Python 字节码,编译后的函数将存储在缓存中。 当下次检查发现函数需要重新编译时,该函数将被重新编译并缓存。 但是,如果重新编译次数超过设置的最大值(64),则该函数将不再被缓存或重新编译。 如上所述,目标检测算法的损失计算和后处理部分也是动态计算的,这些函数需要每次重新编译。 因此,将torch._dynamo.config.cache_size_limit
参数设置为较小的值可以有效减少编译时间
在 MMDetection 中,可以通过环境变量 DYNAMO_CACHE_SIZE_LIMIT
设置 torch._dynamo.config.cache_size_limit
参数。 例如,命令如下所示
# Single GPU
export DYNAMO_CACHE_SIZE_LIMIT = 4
python tools/train.py configs/rtmdet/rtmdet_s_8xb32-300e_coco.py --cfg-options compile=True
# Single node multiple GPUs
export DYNAMO_CACHE_SIZE_LIMIT = 4
./tools/dist_train.sh configs/rtmdet/rtmdet_s_8xb32-300e_coco.py 8 --cfg-options compile=True
关于 PyTorch 2.0 的 dynamo 的常见问题,您可以参考 这里
安装¶
MMCV 和 MMDetection 之间的兼容性问题;“ConvWS 已在卷积层中注册”;“AssertionError: 使用了 MMCV==xxx 但不兼容。 请安装 mmcv>=xxx, <=xxx。”
兼容的 MMDetection、MMEngine 和 MMCV 版本如下所示。 请选择正确的 MMCV 版本以避免安装问题。
MMDetection 版本 | MMCV 版本 | MMEngine 版本 |
---|---|---|
main | mmcv>=2.0.0, \<2.2.0 | mmengine>=0.7.1, \<1.0.0 |
3.3.0 | mmcv>=2.0.0, \<2.2.0 | mmengine>=0.7.1, \<1.0.0 |
3.2.0 | mmcv>=2.0.0, \<2.2.0 | mmengine>=0.7.1, \<1.0.0 |
3.1.0 | mmcv>=2.0.0, \<2.1.0 | mmengine>=0.7.1, \<1.0.0 |
3.0.0 | mmcv>=2.0.0, \<2.1.0 | mmengine>=0.7.1, \<1.0.0 |
3.0.0rc6 | mmcv>=2.0.0rc4, \<2.1.0 | mmengine>=0.6.0, \<1.0.0 |
3.0.0rc5 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.3.0, \<1.0.0 |
3.0.0rc4 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.3.0, \<1.0.0 |
3.0.0rc3 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.3.0, \<1.0.0 |
3.0.0rc2 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.1.0, \<1.0.0 |
3.0.0rc1 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.1.0, \<1.0.0 |
3.0.0rc0 | mmcv>=2.0.0rc1, \<2.1.0 | mmengine>=0.1.0, \<1.0.0 |
注意
如果您想安装 mmdet-v2.x,可以在 这里 找到兼容的 MMDetection 和 MMCV 版本表。 请选择正确的 MMCV 版本以避免安装问题。
在 MMCV-v2.x 中,
mmcv-full
重命名为mmcv
,如果您想安装不带 CUDA 操作的mmcv
,您可以安装mmcv-lite
。
“没有名为 'mmcv.ops' 的模块”;“没有名为 'mmcv._ext' 的模块”。
使用
pip uninstall mmcv-lite
卸载环境中现有的mmcv-lite
。按照 安装说明 安装
mmcv
。
在 Windows 上安装期间,“需要 Microsoft Visual C++ 14.0 或更高版本”。
此错误发生在构建 pycocotools 的 'pycocotools._mask' 扩展程序时,环境缺少相应的 C++ 编译依赖项。 您需要在微软官方网站 visual-cpp-build-tools 下载它,选择“使用 C++ 桌面开发”选项来安装最小依赖项,然后重新安装 pycocotools。
使用 Albumentations
如果您想使用
albumentations
,我们建议使用pip install -r requirements/albu.txt
或pip install -U albumentations --no-binary qudida,albumentations
。 如果您只是使用pip install albumentations>=0.3.2
,它将同时安装opencv-python-headless
(即使您已经安装了opencv-python
)。 请参考 官方文档 获取详细信息。使用某些算法时会引发 ModuleNotFoundError
Instaboost、全景分割、LVIS 数据集等需要一些额外的依赖项。 请注意错误消息并安装相应的包,例如:
# for instaboost pip install instaboostfast # for panoptic segmentation pip install git+https://github.com/cocodataset/panopticapi.git # for LVIS dataset pip install git+https://github.com/lvis-dataset/lvis-api.git
编码¶
我是否需要在进行一些代码修改后重新安装 mmdet
如果您遵循最佳实践并使用
pip install -e .
安装 mmdet,对代码进行的任何本地修改都将生效,无需重新安装。如何使用多个 MMDetection 版本进行开发
您可以拥有多个文件夹,例如 mmdet-3.0、mmdet-3.1。 当您运行训练或测试脚本时,它将采用当前文件夹中的 mmdet 包。
要使用环境中安装的默认 MMDetection 而不是您正在使用的那个,您可以从这些脚本中删除以下行
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
PyTorch/CUDA 环境¶
“RTX 30 系列显卡在构建 MMCV 或 MMDet 时失败”
临时解决方案:执行
MMCV_WITH_OPS=1 MMCV_CUDA_ARGS='-gencode=arch=compute_80,code=sm_80' pip install -e .
。常见问题是nvcc fatal : Unsupported gpu architecture 'compute_86'
。这意味着编译器应该针对 sm_86 进行优化,即英伟达 30 系列显卡,但 CUDA 工具包 11.0 尚未支持此类优化。此解决方案通过添加MMCV_CUDA_ARGS='-gencode=arch=compute_80,code=sm_80'
修改编译标志,这告诉nvcc
针对 **sm_80** 进行优化,即英伟达 A100。虽然 A100 与 30 系列显卡不同,但它们使用类似的安培架构。这可能会降低性能,但它能工作。PyTorch 开发人员已更新,默认编译器标志应通过 pytorch/pytorch#47585 解决。因此,使用 PyTorch-nightly 也可能能够解决此问题,但我们尚未测试它。
“无效设备函数”或“没有可执行的内核映像”。
检查您的 cuda 运行时版本(在
/usr/local/
下)、nvcc --version
和conda list cudatoolkit
版本是否匹配。运行
python mmdet/utils/collect_env.py
检查 PyTorch、torchvision 和 MMCV 是否针对正确的 GPU 架构构建。您可能需要设置TORCH_CUDA_ARCH_LIST
以重新安装 MMCV。GPU 架构表可以在这里找到 here,例如,运行TORCH_CUDA_ARCH_LIST=7.0 pip install mmcv
构建 Volta GPU 的 MMCV。在使用旧 GPU(例如,colab 上的 Tesla K80 (3.7))时,可能会出现兼容性问题。检查运行环境是否与编译 mmcv/mmdet 时使用的环境相同。例如,您可能使用 CUDA 10.0 编译 mmcv,但在 CUDA 9.0 环境中运行它。
“未定义符号”或“无法打开 xxx.so”。
如果这些符号是 CUDA/C++ 符号(例如,libcudart.so 或 GLIBCXX),请检查 CUDA/GCC 运行时是否与用于编译 mmcv 的运行时相同,即运行
python mmdet/utils/collect_env.py
查看"MMCV Compiler"
/"MMCV CUDA Compiler"
是否与"GCC"
/"CUDA_HOME"
相同。如果这些符号是 PyTorch 符号(例如,包含 caffe、aten 和 TH 的符号),请检查 PyTorch 版本是否与用于编译 mmcv 的版本相同。
运行
python mmdet/utils/collect_env.py
检查 PyTorch、torchvision 和 MMCV 是否由相同环境构建并在相同环境中运行。
setuptools.sandbox.UnpickleableException: DistutilsSetupError(“‘ext_modules’ 选项的每个元素都必须是 Extension 实例或 2 元组”)
如果您使用的是 miniconda 而不是 anaconda,请检查 Cython 是否已安装,如 #3379 所示。您需要先手动安装 Cython,然后运行命令
pip install -r requirements.txt
。您可能还需要检查
setuptools
、Cython
和PyTorch
之间的兼容性。
“段错误”。
检查您的 GCC 版本并使用 GCC 5.4。这通常是由 PyTorch 与环境(例如,PyTorch 的 GCC < 4.9)之间的不兼容造成的。我们还建议用户避免使用 GCC 5.5,因为许多反馈报告 GCC 5.5 会导致“段错误”,而将其更改为 GCC 5.4 就可以解决问题。
检查 PyTorch 是否已正确安装并可以使用 CUDA 操作,例如,在终端中键入以下命令。
python -c 'import torch; print(torch.cuda.is_available())'
查看它们是否能正确输出结果。
如果 Pytorch 已正确安装,请检查 MMCV 是否已正确安装。
python -c 'import mmcv; import mmcv.ops'
如果 MMCV 已正确安装,那么上述两个命令就不会出现问题。
如果 MMCV 和 Pytorch 已正确安装,您可以使用
ipdb
、pdb
设置断点,或直接在 mmdetection 代码中添加 “print” 来查看导致段错误的哪一部分。
训练¶
“损失为 Nan”
检查数据集注释是否有效:零大小的边界框会导致回归损失为 Nan,因为通常使用用于边界框回归的变换。一些小尺寸(宽度或高度小于 1)的框在数据增强(例如,instaboost)后也会导致此问题。因此,请检查数据并尝试过滤掉这些零大小的框,并在遇到此问题时跳过对小尺寸框的一些有风险的增强。
降低学习率:学习率可能过大,原因可能是:例如,批次大小的改变。您可以将它们重新调整到可以稳定训练模型的值。
延长热身迭代:有些模型对训练开始时的学习率很敏感。您可以延长热身迭代,例如,将
warmup_iters
从 500 更改为 1000 或 2000。添加梯度裁剪:一些模型需要梯度裁剪来稳定训练过程。默认的
grad_clip
为None
,您可以添加梯度裁剪以避免过大的梯度,即,在您的配置文件中设置optim_wrapper=dict(clip_grad=dict(max_norm=35, norm_type=2))
。
“GPU 内存不足”
当存在大量地面实况框时,可能会出现这种情况,这可能会在目标分配期间导致 OOM。您可以在分配器的配置中设置
gpu_assign_thr=N
,这样分配器将在 GT 框超过 N 个时通过 CPU 计算框重叠。在主干网络中设置
with_cp=True
。这使用 PyTorch 中的次线性策略来减少主干网络中的 GPU 内存消耗。尝试使用混合精度训练,方法是遵循
config/fp16
中的示例。可能需要对不同模型的loss_scale
进行进一步调整。尝试使用
AvoidCUDAOOM
避免 GPU 内存不足。它将在调用torch.cuda.empty_cache()
后首先重试。如果仍然失败,它将通过将输入类型转换为 FP16 格式来重试。如果仍然失败,它将尝试将输入从 GPU 复制到 CPU 以继续计算。尝试在您的代码中使用 AvoidOOM,以便在 GPU 内存不足时使代码继续运行。from mmdet.utils import AvoidCUDAOOM output = AvoidCUDAOOM.retry_if_cuda_oom(some_function)(input1, input2)
您也可以尝试使用
AvoidCUDAOOM
作为装饰器,以便在 GPU 内存不足时使代码继续运行。from mmdet.utils import AvoidCUDAOOM @AvoidCUDAOOM.retry_if_cuda_oom def function(*args, **kwargs): ... return xxx
“RuntimeError:预计在开始新的迭代之前已在先前的迭代中完成归约”
此错误表示您的模块具有在生成损失中未使用的参数。这种现象可能是由于在 DDP 模式下在您的代码中运行不同的分支造成的。
您可以在配置文件中设置
find_unused_parameters = True
来解决上述问题,但这会降低训练速度。您可以在配置文件中设置
detect_anomalous_params = True
或model_wrapper_cfg = dict(type='MMDistributedDataParallel', detect_anomalous_params=True)
(更多详细信息请参考 MMEngine)来获取这些未使用参数的名称。注意detect_anomalous_params = True
会降低训练速度,因此建议仅用于调试。
保存最佳模型
可以通过配置
default_hooks = dict(checkpoint=dict(type='CheckpointHook', interval=1, save_best='auto'),
来开启。在auto
参数的情况下,返回的评估结果中的第一个键将用作选择最佳模型的依据。您也可以直接在评估结果中设置键来手动设置它,例如,save_best='coco/bbox_mAP'
。
评估¶
COCO 数据集,AP 或 AR = -1
根据 COCO 数据集的定义,图像中小型区域分别小于 1024 (32*32)、9216 (96*96)。
如果相应区域没有目标,则 AP 和 AR 的结果将设置为 -1。
模型¶
style
在 ResNet 中ResNet 中的
style
参数允许pytorch
或caffe
样式。它指示 Bottleneck 模块中的差异。Bottleneck 是1x1-3x3-1x1
卷积层的堆叠结构。在caffe
模式下,具有stride=2
的卷积层是第一个1x1
卷积,而在pyorch
模式下,是第二个3x3
卷积具有stride=2
。示例代码如下if self.style == 'pytorch': self.conv1_stride = 1 self.conv2_stride = stride else: self.conv1_stride = stride self.conv2_stride = 1
ResNeXt 参数描述
ResNeXt 来自论文
Aggregated Residual Transformations for Deep Neural Networks
。 它引入了分组并使用“基数”来控制分组数量,以在精度和复杂度之间取得平衡。 它通过两个超参数baseWidth
和cardinality
来控制内部 Bottleneck 模块的基本宽度和分组参数。 MMDetection 中的一个示例配置名称是mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py
,其中mask_rcnn
表示使用 Mask R-CNN 的算法,x101
表示使用 ResNeXt-101 的主干网络,64x4d
表示瓶颈块有 64 个组,每个组的基本宽度为 4。norm_eval
在主干网络中由于检测模型通常很大,输入图像的分辨率也很高,这会导致检测模型的小批量,这会使训练过程中 BatchNorm 计算的统计数据的方差变得很大,并且不像预训练主干网络期间获得的统计数据那样稳定。 因此,训练中通常使用
norm_eval=True
模式,直接使用预训练主干网络中的 BatchNorm 统计数据。 一些使用大批量的算法使用norm_eval=False
模式,例如 NASFPN。 对于没有 ImageNet 预训练的主干网络,且批量相对较小,可以考虑使用SyncBN
。