EfficientDet实战:环境配置、COCO数据集训练与模型对比全解析
2026/9/16 17:28:14 网站建设 项目流程

最近在组里做目标检测模型的横向对比实验,需要把 EfficientDet 也拉进来跑一通。实验本身不复杂,但环境配置、数据集转换和训练参数这一套流程,确实踩了不少坑。EfficientDet 的核心优势在于用 BiFPN 做加权特征融合,加上复合缩放策略,让模型在精度和计算量之间取得了一个不错的平衡点。这篇博文就围绕 EfficientDet 的环境配置、个人数据集训练以及对比实验中的经验展开,适合正在做目标检测实验对比、或者想用 EfficientDet 训练自己数据集的同学参考。

我会从整体设计思路开始讲,然后按环境配置、数据准备、训练调参、问题排查的顺序一步步展开。所有操作都是我在真实项目里跑通过的方式,不同环境可能会有细微差异,但核心思路是通用的。

1. 对比实验选型:为什么是 EfficientDet

1.1 从 EfficientNet 到 EfficientDet 的设计思路

EfficientDet 是 Google Brain 在 2020 年前后提出的目标检测模型系列。它继承了 EfficientNet 的神经架构搜索思路,核心创新有两个:一是 BiFPN(Bidirectional Feature Pyramid Network,双向特征金字塔网络),二是复合缩放(Compound Scaling)。BiFPN 的核心思想是给不同分辨率的特征图学习一个权重,在融合时让贡献更大的层获得更高权重,而不是像传统 FPN 那样简单相加。复合缩放则是对 Backbone 深度、BiFPN 层数、Head 层数和输入分辨率进行统一缩放,衍生出了 D0 到 D7 一系列不同规模和精度的模型。

放到对比实验里,EfficientDet 最值得关注的是它提供了一条非常平滑的“效率-精度曲线”。同一个模型家族里,你可以从 D0 一路试到 D7,找到一个适合自己硬件条件和数据规模的点。我在对比实验里通常会把 D1 或 D2 作为候选,因为它们在 COCO 上的 mAP 已经比较可观,同时显存占用和训练时间都还处于可控范围。

1.2 在横向对比里怎么定位 EfficientDet

做模型对比时,不能只看 mAP 一个指标。我一般会同时记录参数量、推理 FPS、单卡训练耗时、显存峰值这类信息。EfficientDet 在 COCO 上的表现,D0 大约能对应早期 YOLOv3 的水平,但参数量和计算量更小;D2 以上精度会明显拉开差距,不过训练时长和显存需求也水涨船高。如果你的数据集只有几千张甚至更少,我不建议一上来就上 D4 以上的大模型。小数据集 + 大模型很容易过拟合,而且在个人 GPU 上训练时间会被拉得很长,对调参非常不友好。

我在实际对比中使用的是单卡 RTX 3090 24G,训练 EfficientDet-D1 和 D2 都比较轻松。如果你只有 8G 显存,建议从 D0 或 D1 开始,batch size 控制在 4 左右,输入分辨率适当降到 640 或者 512。这个定位很关键,后面所有环境配置、数据准备和训练参数,都要先确定“我要跑哪个型号”。

2. 环境配置:一套可靠到能直接复用的方案

2.1 用 Anaconda 隔离 Python 环境

环境配置是整个流程里最容易让人心态爆炸的一步。我强烈建议用 Anaconda 创建独立虚拟环境,不要把依赖装到系统 Python 里。创建命令很简单:

conda create -n effdet python=3.8 conda activate effdet

Python 版本我建议固定用 3.8。不是越新越好,EfficientDet 这类项目大多依赖 pycocotools、albumentations、opencv-python 等库,Python 3.9、3.10 在某些历史版本上可能遇到不兼容问题。环境隔离的好处是:即使这个项目把依赖搞坏了,也不会影响你机器上其他深度学习项目。

2.2 PyTorch 和 CUDA 的版本匹配原则

安装 PyTorch 时不要无脑装最新版。先确认两件事:你的显卡驱动支持的 CUDA 版本,以及 EfficientDet 项目代码兼容的 PyTorch 版本。像我用的 RTX 3090,驱动支持 CUDA 11.3,所以当时选择 PyTorch 1.10 + cu113 的组合就非常稳妥:

conda install pytorch==1.10.0 torchvision==0.11.0 cudatoolkit=11.3 -c pytorch

如果你习惯用 pip,也可以从 PyTorch 官网的 whl 地址安装:

pip install torch==1.10.0+cu113 torchvision==0.11.0+cu113 -f https://download.pytorch.org/whl/torch_stable.html

装完以后一定要验证 GPU 是否可用:

import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))

这里有个容易忽略的点:PyTorch 的 cu113 指的是它编译时使用的 CUDA 运行时版本,并不要求系统驱动必须是 CUDA 11.3。NVIDIA 驱动是向后兼容的,驱动版本足够新就行,很多人在这一步被误导过。

2.3 项目依赖及 pycocotools 编译问题

环境配好后,拉取 EfficientDet 的 PyTorch 实现仓库。我使用的是 zylo117 的 Yet-Another-EfficientDet-Pytorch 仓库,这是目前社区里训练自定义数据集资料比较全的一个版本:

git clone https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch cd Yet-Another-EfficientDet-Pytorch

接下来安装依赖。除了 PyTorch 之外,核心依赖有 pycocotools、albumentations、opencv-python、tqdm、tensorboard 等。我实际安装的命令是:

pip install pycocotools albumentations==0.4.6 opencv-python tqdm tensorboard

pycocotools是最容易出问题的一个包。在 Linux 下如果缺少 gcc 或者 Python 开发头文件,编译会直接报错;Windows 下则要安装 Visual Studio Build Tools。不想折腾编译的话,直接用 conda 安装预编译版本:

conda install -c conda-forge pycocotools

另一个容易踩坑的是albumentations版本。新版本 API 变化比较大,老代码里from albumentations import Compose, Normalize之类的调用方式可能在新版里行为不同,导致数据增强环节报错。我试下来 0.4.6 这个版本比较稳定。

2.4 用推理 demo 验证环境是否健康

环境装完之后别急着准备数据。先把仓库里自带的 demo 跑通:

python inference.py -p project_name -c 0 \ -i /path/to/test.jpg -w weights/efficientdet-d0.pth

这个步骤的意义是验证整条链路:模型能不能加载、GPU 能不能参与推理、图片预处理会不会报错。能跑出带框的图片,说明环境基本没问题。如果这一步都跑不通,先排查环境,不要急着进数据环节,否则后面会分不清到底是数据问题还是环境问题。我用 PyCharm 和 VSCode 时都会把解说器切换到刚才创建的 conda 环境里,但训练命令仍然习惯在终端执行,这样日志输出和中断控制都更直接。

3. 个人数据集准备:从标注到 COCO 格式的完整流程

3.1 标注工具选择与标注规范

训练目标检测模型,数据标注是绕不开的环节。我用的最多的还是 labelImg,够轻量、跨平台、操作简单。如果你有大量图片要标注,可以考虑 Roboflow 这样的在线工具,团队协作和版本管理更方便。但注意,不管用哪个工具,最后最好统一导出为 Pascal VOC XML 格式或者 COCO JSON 格式,中间格式越统一,转换脚本就越省事。

标注规范这块我要多说一句。你在标注框时,类别名称一定不要出现中文字符和空格,比如car可以,car_black也可以,但黑色轿车这类命名容易在后面 JSON 解析、路径拼接时出问题。另外,同一张图如果存在目标重叠或者遮挡,框尽量贴合目标外接矩形,不要凭感觉扩大或缩小。我做过一次实验,仅仅是把一批标注重新校准后,mAP 就提升了 3 个多点,可见标注质量直接影响训练效果。

3.2 VOC 目录结构与格式转换

EfficientDet 仓库训练自定义数据集时,最方便的方式是把标注转成 COCO 格式。通常先组织成 VOC 目录结构:

VOCdevkit/ └── VOC2007/ ├── Annotations/ # 存放 XML 标注文件 ├── JPEGImages/ # 存放原图 ├── ImageSets/ │ └── Main/ # 存放 train.txt, val.txt └── labels.txt # 类别列表

然后使用仓库里的转换脚本生成 COCO JSON。在 Yet-Another-EfficientDet-Pytorch 中,通常先运行get_data_from_voc.py读取 XML 并生成中间文件,再运行voc_to_coco.py得到 COCO 格式的annotations.json。实际运行时要根据自己的数据集路径和类别列表修改脚本里的配置:

python get_data_from_voc.py \ --datasets ./VOCdevkit/ \ --output ./dataset python voc_to_coco.py

这一步很多朋友会卡住,因为get_data_from_voc.py里写死了 VOC 的类别列表。如果你的数据集类别不是 PASCAL VOC 的 20 类,一定要把脚本中的类别列表改成你自己的。我第一轮跑转换时没注意,结果生成的 JSON 里所有类别 id 都错位了,训练出来 mAP 直接趴地板。所以转换完以后一定要检查 JSON 文件,确认类别数量和 bbox 坐标是否正常。

3.3 类别 id 的坑:背景占 0,类别从 1 开始

EfficientDet 的检测头在训练时会把类别 0 作为背景类,所以你的目标类别 id 要从 1 开始。比如你的数据集有personcar两类,那么person就是 1,car就是 2。在配置文件的obj_list里也要保持同样的顺序:

project_name: my_effdet obj_list: ['person', 'car'] save_weights_to: './weights'

如果obj_list和标注 JSON 里的类别顺序对不上,常见的表现是训练时 loss 不下降,或者推理时所有框都预测成同一个类别。所以模型没训练好之前,先确认这两处一致,可以省掉很多无效调试。

3.4 训练集、验证集、测试集的科学划分

数据划分会影响整个实验的可信度。我的习惯是:先按 8:1:1 划分为 train/val/test,并且要保证划分是随机且按类别分布均衡的。如果直接用文件夹前 80% 的图片当训练集,后 20% 当验证集,很容易造成类别分布不均衡,尤其是小样本类别可能全都在测试集里,验证指标就失真了。Voc 脚本里一般会生成train.txtval.txt,如果没有,可以自己写个小脚本随机打乱,记录文件名并分配。划分完成后,最好统计一下每个 set 中各类别的目标数量,做到心里有数。

另外,除非你数据量特别大,否则建议从训练集里留出一部分图片完全不做任何数据增强,作为离线验证集。这样你看到验证 mAP 才是模型在相对真实分布上的表现,而不是增强后的分布。

4. 训练过程:参数选择、监控与评估

4.1 预训练权重与迁移学习策略

在个人数据集上训练目标检测模型,强烈建议加载 COCO 预训练权重,而不是从零训练。从零训练需要的数据量和时间都大得多。下载对应的 D0/D1 权重后,放到weights目录,训练脚本会读取这些权重来初始化模型。加载权重时要注意一个细节:如果你的数据集类别数和 COCO 的 80 类不一致,最后一层分类头的权重尺寸会不匹配。仓库代码一般会自动跳过不匹配的层,或者你在配置里指定 new class 数量后,它会重新初始化头部。遇到报错不要慌,检查一下这里。

迁移学习的常用做法是先冻结 Backbone,训练几个 epoch 让 Head 先稳定下来,之后再解冻 Backbone 做全参数微调。在 EfficientDet 里,你可以通过修改配置中的backbone层的requires_grad来实现。不过这个仓库不一定直接在配置里支持,你可以通过加载权重后手动设置:

for param in model.backbone.parameters(): param.requires_grad = False

先冻结训练 10 个 epoch,再解开继续跑,这样能避免一开始就大幅破坏预训练特征。我的经验是,在小数据集上这个策略比直接全参数训练稳定很多。

4.2 核心训练参数建议

训练脚本的核心参数如下:

python train.py \ -c 0 \ -p my_effdet \ --batch_size 4 \ --num_epochs 100 \ --num_workers 8 \ --lr 2e-3 \ --weight_decay 1e-4

-c指定配置文件索引,-p是项目名,--batch_size根据显存调整,--num_workers一般是 CPU 核数的两倍以内,--lr用学习率预热加余弦退火会更稳。我的推荐参数如下:

参数建议值说明
batch_size4~8显存不足时优先降到 2,不要乱调分辨率
num_epochs50~150几千张图的数据集,100 个 epoch 左右比较合适
initial_lr1e-3~3e-3加载预训练权重时可用稍大初始 lr
lr_schedulercosine相比 step 更平滑,后期不容易震荡
weight_decay1e-4防止过拟合
输入分辨率640~1024根据模型 D0-D3 调整

学习率这块有个常见误区:迁移学习时初始学习率设得太高,前几个 epoch 就会把预训练特征破坏掉。我看到过有人直接把 lr 调到 0.01,loss 一开始下降得很快,后来验证精度一直上不去。个人经验,加载 COCO 权重时初始学习率2e-3是相对安全的范围,如果训练集特别小,建议再降到1e-3以下。

4.3 TensorBoard 监控与 loss 曲线判读

训练时开启 TensorBoard 能帮你快速判断模型是否健康:

tensorboard --logdir logs

浏览器打开http://localhost:6006就能看到 loss 曲线、学习率变化以及验证指标。我判断训练状态基本就三条:第一,loss 在前 10 个 epoch 内是否有明显下降趋势,如果一直不降,先检查学习率和数据加载是否正常;第二,训练 loss 和验证 loss 的差距,如果训练 loss 持续下降但验证 loss 反弹,说明过拟合,考虑加数据增强或降低 epoch;第三,类别 AP 分布是否均匀,如果某个类别 AP 明显低,多半是标注数量不足或标注质量有问题。

4.4 验证与推理:评估模型真实水平

验证可以用仓库的val.py脚本,传入项目配置和权重路径,运行后输出 mAP@0.5 和 mAP@0.5:0.95。注意 COCO 风格评估中mAP@0.5:0.95对框的定位精度要求更高,如果只是业务落地看个大概,mAP@0.5就够用。推理过程则是:

python inference.py -p my_effdet -c 0 \ -w weights/my_effdet.pth \ -i /path/to/test_images

推理结果会输出带检测框的图片。这一步我一般会找几张最难的正样本检查,比如小目标、遮挡目标、密集目标。如果这些场景下漏检严重,哪怕整体 mAP 不低,上线效果也可能打折扣。这也是对比实验时很容易忽视的一环:指标漂亮不代表实际场景可用。

5. 常见问题与避坑实录

这里把我实际训练过程中遇到的典型问题和解决方法整理成一个速查表,遇到问题时可以直接对照排查。

典型问题可能原因解决办法
安装 pycocotools 编译报错缺少 gcc / VS Build Tools / Python 头文件conda install -c conda-forge pycocotools安装预编译版本
albumentations 版本不兼容老代码用了旧 API固定安装albumentations==0.4.6
CUDA out of memorybatch_size 过大或分辨率过高减小 batch_size,优先于降低分辨率
训练 loss 不下降学习率过大、数据标签错位、类别 id 不正确先用小 lr 试跑 10 个 epoch,检查配置文件 obj_list
验证 AP 很低但训练 loss 正常模型过拟合或标注质量差增加数据增强、降低训练 epoch、检查标注框贴合度
转换脚本报 KeyErrorXML 结构不标准或类别列表不一致手动解析一个 XML 检查字段,删掉异常标注
中文路径或空格导致读取失败文件路径含中文和空格数据集路径和图片名统一用英文和下划线
num_workers 过高导致卡死DataLoader 频繁重启子进程调低 num_workers 到 4 或 8,Windows 下建议设置为 0
预训练权重加载维度错误类别数量和新数据不一致确认配置文件类别数,允许头部重新初始化

5.1 一个让我印象深刻的 loss 异常案例

有一次我训练一直不收敛,training loss 在 4.5 附近波动,val mAP 只有 0.02。当时怀疑了好多地方,最终发现是get_data_from_voc.py生成中间文件时,把某个类别的 bbox 坐标按x_min, y_min, x_max, y_max存成了x_center, y_center, width, height。由于仓库后续脚本默认前者,坐标对不上,模型完全学不到东西。这个错误特别隐蔽,因为它不会直接报错,只是结果完全不可用。所以数据集格式转换后,建议可视化几个标注框,确保 bbox 能正确画在原图上再训练。

5.2 关于显存优化和 batch size 的经验

EfficientDet 在训练时显存占用大头是特征金字塔和检测头,尤其是输入分辨率较高时。我在 24G 显存的 3090 上,D2 模型、batch_size 8、分辨率 896 时显存占用大约 15G;如果换成 8G 显存的卡,同样配置会直接 OOM。遇到 OOM 时不要急着换小模型,先试 batch_size 降至 2 或 4。如果还需要更省显存,可以打开 AMP(自动混合精度)训练,仓库代码如果是 PyTorch 1.6 以上,通常支持torch.cuda.amp。混合精度在大部分情况下能省接近一半显存,精度损失很小。

5.3 对比实验中的几个操作建议

既然标题是“对比实验系列”,最后再补几条我做横向对比时的操作建议:

  • 统一评价脚本。不同模型的 mAP 计算方式要统一到同一套评估代码上,不然对比没有意义。
  • 固定输入分辨率和 batch size。EfficientDet 和 YOLO 系列的输入尺寸不同,但至少固定图像缩放范围,让对比更公平。
  • 记录训练耗时和显存峰值。模型 A mAP 比模型 B 高 1 个点,但训练耗时多一倍,这个结论要写在报告里。
  • 别只跑一次实验。小数据集上单次实验结果波动比较大,条件允许的话跑 2 到 3 次取平均。

我个人在实际测试中的体会是,EfficientDet 的环境配置门槛并不高,真正花时间的反而是数据集转换和排查那些不报错的“隐性错误”。如果你准备在自己数据集上做对比实验,我建议第一步先跑通 demo,第二步用极少量的图片(比如 50 张)快速把整套训练流程走一遍,确认从数据转换到权重保存都能跑通,再上全量数据。这样即便出问题,排查范围也小得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询