简介:本资源面向计算机视觉入门与进阶学习者,提供一套基于Faster-RCNN的车辆、行人及交通信号目标检测完整项目,适合课程设计、毕业设计或算法练手场景。压缩包共89个文件,约3.61MB,以30个Python源码文件与36个pyc编译文件为主,另含12张jpg测试图片、项目报告pdf、说明文档md及类别配置json等,覆盖从数据读取到模型推理的全流程。项目按backbone、network_files、train_utils等模块组织,包含ResNet50+FPN、MobileNetV2、VGG等特征提取网络,以及RPN、ROI Head、混合精度训练、多GPU训练、mAP评估与预测脚本,并配有详细注释。已有226人学习,读者可据此掌握Faster-RCNN网络结构、自定义数据集读取、训练验证流程与结果可视化,快速复现车辆行人及交通信号检测实验。
1. 从一份能跑通的 Faster-RCNN 交通目标检测包说起
红绿灯、行人和车辆这三类目标,是自动驾驶感知和智慧交通项目里绕不开的基本盘。但真正动手时,多数人卡住的地方不是网络结构本身,而是数据标注格式对不上、预训练权重加载报错、训练到一半 loss 变 NaN、推理画框坐标偏移这些琐碎问题。这份基于 Faster-RCNN 的车辆行人及交通信号目标检测资源包,把 Python 源码、Pascal VOC 格式数据集、训练好的权重、项目报告和逐行注释一起打包,省掉了从零搭工程的时间。它适合两类人:一是刚接触目标检测、想找一个结构完整、能直接跑通的工程练手;二是已经用过 YOLO 系列、想对比两阶段检测器在交通场景下精度与速度差异的从业者。整个工程基于 PyTorch 1.6 以上版本,用 ResNet50+FPN 做骨干网络,训练脚本、验证脚本、预测脚本、mAP 曲线绘制一应俱全,拿到手就能复现完整流程。
2. 工程结构与核心模块拆解:backbone、RPN 和 ROI Head 怎么配合
2.1 目录布局与各模块职责
拿到压缩包解压后,根目录下大致是这么几块:backbone放特征提取网络,network_files放 Faster-RCNN 主体结构,train_utils放训练验证工具,根目录下散落着my_dataset.py、transforms.py、split_data.py、train_res50_fpn.py、predict.py、validation.py、plot_curve.py等脚本。这个划分方式很清晰,改网络去network_files,换骨干去backbone,调数据增强去transforms.py,各管各的。
network_files里几个文件值得单独说。rpn_function.py是区域建议网络,负责在特征图上生成候选框;roi_head.py是 ROI Head,把候选框映射回特征图并做分类和回归;faster_rcnn_framework.py把 backbone、RPN、ROI Head 串成完整模型;transform.py处理图像和标注的同步变换;det_utils.py放的是框编码解码、NMS 这些底层工具函数。boxes.py里实现了BoxCoder和Matcher,前者负责锚框与真实框之间的偏移量编解码,后者负责把候选框和真实标注做匹配,是训练能否收敛的关键。
backbone目录下提供了三种选择:resnet50_fpn_model.py、mobilenetv2_model.py、vgg_model.py。默认训练脚本用的是 ResNet50+FPN,精度最高但显存占用也最大;MobileNetV2 适合显存紧张或者想部署到边缘设备的场景;VGG 是 Faster-RCNN 原论文用的骨干,现在用得少了,但作为对比基线仍有参考价值。feature_pyramid_network.py是 FPN 的实现,把不同尺度的特征图融合后输出给 RPN 和 ROI Head,对小目标检测提升明显——交通场景里的远处行人和小信号灯就吃这个红利。
2.2 数据读取与增强链路
my_dataset.py里定义了一个继承自torch.utils.data.Dataset的类,核心逻辑是读 Pascal VOC 格式的 XML 标注,解析出每个目标的类别和边界框坐标,再配合transforms.py做同步增强。这里有个容易忽略的点:图像增强必须对图像和标注框做同样的几何变换,否则框就飘了。工程里用的是一个组合变换类,把随机翻转、随机裁剪等操作封装在一起,保证图像和框同步。
# my_dataset.py 核心逻辑示意 class VOCDataSet(Dataset): def __init__(self, voc_root, transforms, train_set=True): # 读取 ImageSets/Main/train.txt 或 val.txt # 解析 Annotations 下的 XML 文件 ... def __getitem__(self, idx): # 读图像 -> 读标注 -> 同步增强 -> 转 tensor image = Image.open(img_path).convert("RGB") boxes, labels = self.parse_xml(xml_path) image, boxes, labels = self.transforms(image, boxes, labels) return image, boxes, labelstransforms.py里实现了RandomHorizontalFlip、RandomResize等,每个变换都同时接收 image、boxes、labels 三个参数,返回变换后的三者。参数方面,RandomResize里有个max_size控制短边缩放后的长边上限,默认 1333,显存不够就往下调,但别低于 600,否则小目标特征全丢了。
2.3 训练脚本与多 GPU 支持
train_res50_fpn.py是主训练脚本,里面几个参数需要根据自己机器调整。--data-path指向数据集根目录,--epochs默认 10 轮左右,--batch-size在单卡 8G 显存下建议设 2 到 4,--lr初始学习率 0.005 配合余弦退火。脚本里用了 PyTorch 1.6 之后才支持的混合精度训练,torch.cuda.amp那套,能省显存提速,但前提是 PyTorch 版本必须 1.6.0 以上,低于这个版本会直接报AttributeError。
train_multi_GPU.py是多卡版本,用DistributedDataParallel做数据并行。启动方式和单卡不同,得用torch.distributed.launch或者torchrun:
# 单机 4 卡训练示例 python -m torch.distributed.launch --nproc_per_node=4 --use_env train_multi_GPU.py \ --data-path ./data \ --epochs 20 \ --batch-size 4 \ --lr 0.01 \ --output-dir ./save_weights--nproc_per_node是每台机器的进程数,一般等于 GPU 数量。--use_env让脚本从环境变量读 rank 信息,不加这个参数在某些 PyTorch 版本下会报找不到LOCAL_RANK。多卡训练时batch-size指的是单卡 batch,总 batch 是它乘以卡数,学习率也要相应放大。
3. 从零跑通训练与推理:环境、数据、权重加载的完整操作链
3.1 环境配置与依赖安装
环境这块,官方推荐 Python 3.6 到 3.8,PyTorch 1.6.0 以上,Ubuntu 或 CentOS,不建议 Windows。Windows 下pycocotools装起来麻烦,得用pycocotools-windows替代,而且多卡训练支持也差。如果手头只有 Windows 机器,建议用 WSL2 或者直接上云服务器。
# 创建虚拟环境 conda create -n faster_rcnn python=3.8 -y conda activate faster_rcnn # 安装 PyTorch 1.6+,根据 CUDA 版本选对应命令 pip install torch==1.8.0 torchvision==0.9.0 # 安装其他依赖 pip install -r requirements.txt # pycocotools 按平台选 # Linux: pip install pycocotools # Windows: pip install pycocotools-windowsrequirements.txt里除了 PyTorch 和 torchvision,还有 numpy、pillow、matplotlib、tqdm 这些常规库。装完后建议跑一句python -c "import torch; print(torch.cuda.is_available())"确认 GPU 可用,返回 False 的话后面训练会慢到怀疑人生。
3.2 数据集准备与格式校验
工程用的是 Pascal VOC 格式,目录结构应该是:
data/ ├── VOC2012/ │ ├── JPEGImages/ # 所有 jpg 图片 │ ├── Annotations/ # 对应的 xml 标注 │ └── ImageSets/ │ └── Main/ │ ├── train.txt │ └── val.txtsplit_data.py用来划分训练集和验证集,按比例把图片名写进 train.txt 和 val.txt。如果自己换数据集,XML 里的类别名要和pascal_voc_classes.json里的对上,这个 json 文件定义了类别名到数字标签的映射。交通场景下一般就是vehicle、person、traffic_light这几类,改 json 的时候注意索引从 1 开始,0 留给背景。
注意:XML 里如果有类别名拼写不一致,比如
traffic light和traffic_light混用,训练时会被当成两个类,mAP 直接腰斩。跑之前用脚本扫一遍所有 XML 的类别名,统一成 json 里的写法。
3.3 训练启动与权重加载
训练命令不复杂,关键是参数要对:
python train_res50_fpn.py \ --data-path ./data/VOC2012 \ --epochs 15 \ --batch-size 4 \ --lr 0.005 \ --output-dir ./save_weights \ --weights ./save_weights/resNetFpn-model-10.pth # 断点续训或加载预训练--weights参数可以加载之前保存的权重继续训练,也可以加载在 COCO 上预训练的骨干权重做迁移学习。如果从零开始训练,不传这个参数就行。训练过程中每轮结束会在output目录下写result_faster.txt,记录 loss 和 mAP,plot_curve.py读这个文件画曲线。
record_mAP.txt是工程自带的训练记录,里面能看到作者跑出来的 mAP 大概在什么水平。交通场景三类目标,ResNet50+FPN 在 VOC 格式数据上 mAP 通常能到 0.75 以上,具体看数据质量和标注精度。
3.4 推理与结果可视化
predict.py是单张图片推理脚本,加载权重后对testdata里的图片做检测并画框保存。核心流程是:读图 → 预处理 → 模型前向 → 后处理(NMS、置信度过滤)→ 画框。
# predict.py 核心推理逻辑 model.eval() with torch.no_grad(): images, _ = model.transform(images, None) # 预处理 predictions = model(images) # 前向 results = model.postprocess(predictions, images.image_sizes) # 后处理 # 过滤低置信度,画框 for box, label, score in zip(results[0]["boxes"], results[0]["labels"], results[0]["scores"]): if score > 0.5: draw_box_utils.draw_box(img, box, label, score)draw_box_utils.py负责画框和类别标签,支持中文标签需要额外配置字体。testdata目录下有 test1 到 test6 六张测试图,以及对应的_result.jpg结果图,可以直接对比推理效果。置信度阈值默认 0.5,交通信号灯这种小目标可以降到 0.3 试试,但误检会变多。
4. 避坑与排查:训练不收敛、显存爆炸、mAP 异常的常见原因
4.1 loss 出现 NaN 或一直不下降
现象:训练几个 batch 后 loss 变成 NaN,或者 loss 在 2.0 附近震荡不降。
原因:学习率设太大是最常见的,Faster-RCNN 对学习率比 YOLO 敏感,初始 lr 超过 0.01 很容易炸。另一个原因是数据标注里有宽高为 0 的框,计算回归 loss 时除零。
解决:把初始学习率降到 0.005 甚至 0.001,配合 warmup 策略。检查 XML 标注,过滤掉宽高小于 2 像素的框。如果用了混合精度训练,偶尔也会因为梯度下溢出 NaN,把amp关掉试试。
4.2 显存不足报 CUDA out of memory
现象:训练启动后报RuntimeError: CUDA out of memory,或者跑几个 batch 后爆显存。
原因:batch-size太大、图像分辨率太高、ResNet50+FPN 本身显存占用就不小。默认max_size=1333在 8G 显存上单卡 batch 超过 4 基本会炸。
解决:先把batch-size降到 2,再把transforms.py里的max_size从 1333 降到 800,min_size从 800 降到 600。还不行就换 MobileNetV2 骨干,显存占用能降一半左右,精度损失大概 3 到 5 个点。
4.3 mAP 异常低或某类目标检测不到
现象:训练完 mAP 只有 0.2 到 0.3,或者某一类目标完全检测不出来。
原因:类别名和 json 映射对不上、验证集和训练集图片重叠、标注框坐标越界。还有一种情况是pascal_voc_classes.json里类别顺序和 XML 里不一致,导致标签错位。
解决:用validation.py单独跑验证集,看混淆矩阵哪类错得最多。检查split_data.py划分时有没有把同一张图同时分到训练和验证。标注框坐标不能超出图像宽高,越界的框在增强时会出问题。
4.4 多卡训练速度反而变慢
现象:用了train_multi_GPU.py四卡训练,速度比单卡还慢。
原因:数据加载成了瓶颈,num_workers设太小,或者磁盘 IO 跟不上。另外DistributedDataParallel的find_unused_parameters如果设成 True 会拖慢速度。
解决:把num_workers从默认的 4 调到 8 或 16,数据放在 SSD 上。检查模型里有没有定义但没参与前向的参数,没有的话把find_unused_parameters设成 False。多卡训练时batch-size是单卡值,总 batch 等于它乘以卡数,学习率要按线性缩放规则相应调大。
4.5 推理结果框偏移或重复框
现象:预测出来的框位置明显偏了,或者同一个目标画了好几个重叠框。
原因:框偏移通常是预处理和后处理没对齐,比如推理时用了 resize 但没记录缩放比例,后处理时没把框映射回原图尺寸。重复框是 NMS 阈值设太高。
解决:检查predict.py里postprocess是否用了image_sizes做坐标还原。NMS 阈值默认 0.5,重复框多就降到 0.3 到 0.4。另外注意transform.py里的标准化参数要和训练时一致,均值方差对不上也会导致框偏移。
5. 进阶技巧:换骨干、调锚框、导出推理结果
5.1 替换骨干网络做精度与速度权衡
工程默认用 ResNet50+FPN,想换 MobileNetV2 的话,改train_res50_fpn.py里的模型构建部分,把 backbone 换成mobilenetv2_model.py里定义的网络。MobileNetV2 参数量只有 ResNet50 的三分之一左右,推理速度快一倍以上,适合部署到 Jetson 这类边缘设备。代价是 mAP 会降几个点,尤其是小目标。
# 换 MobileNetV2 骨干示意 from backbone.mobilenetv2_model import MobileNetV2 from network_files import FasterRCNN backbone = MobileNetV2(weights_path="./mobilenet_v2.pth").features backbone.out_channels = 1280 # MobileNetV2 输出通道数 model = FasterRCNN(backbone, num_classes=4) # 3 类 + 背景out_channels必须和骨干输出通道对齐,ResNet50 是 2048,MobileNetV2 是 1280,设错了会在 RPN 那层报维度不匹配。换完骨干后学习率可以适当调小,因为预训练权重的特征分布不同。
5.2 锚框尺寸调整适配交通场景
Faster-RCNN 默认锚框尺寸是[32, 64, 128, 256, 512],长宽比[0.5, 1.0, 2.0]。交通场景里行人偏瘦高,信号灯很小,默认锚框不一定最优。如果数据里目标普遍偏小,把最小锚框从 32 降到 16,增加一档小尺度。如果行人检测效果差,把长宽比加上 0.3 和 3.0 两档。
# 在 faster_rcnn_framework.py 里调整锚框参数 anchor_sizes = ((16,), (32,), (64,), (128,), (256,)) # 增加小尺度 aspect_ratios = ((0.3, 0.5, 1.0, 2.0, 3.0),) * len(anchor_sizes) # 增加极端比例改完锚框后,RPN 的回归目标分布会变,建议重新从头训练而不是加载旧权重微调。锚框数量增加会拖慢 RPN 速度,但召回率会提升,具体加多少看验证集上的 mAP 变化。
5.3 导出推理结果与 mAP 曲线分析
训练完想分析模型在各类目标上的表现,validation.py跑完会输出每类的 AP 和总 mAP。plot_curve.py读result_faster.txt画 loss 和 mAP 曲线,能直观看到有没有过拟合。如果训练 loss 还在降但验证 mAP 已经平了,说明该早停了。
# 跑验证集看每类 AP python validation.py \ --data-path ./data/VOC2012 \ --weights ./save_weights/resNetFpn-model-15.pth # 画训练曲线 python plot_curve.py --txt-path ./output/result_faster.txt导出的检测结果可以存成 json 或 csv,方便后续做误检分析。我一般会把置信度 0.3 到 0.5 之间的框单独拎出来看,这批框往往是模型最纠结的,调锚框或者加数据对它们影响最大。从那以后我每次训完模型,都强制把验证集里漏检和误检的图各抽 20 张过一遍,比只看 mAP 数字有用得多。希望帮到你。
本文还有配套的精品资源,点击获取