从零掌握Faster R-CNN:基于PyTorch_Practice的目标检测实战指南

从零掌握Faster R-CNN:基于PyTorch_Practice的目标检测实战指南

【免费下载链接】PyTorch_Practice 这是我学习 PyTorch 的笔记对应的代码,点击查看 PyTorch 笔记在线电子书 【免费下载链接】PyTorch_Practice 项目地址: https://gitcode.com/gh_mirrors/py/PyTorch_Practice

引言:目标检测的痛点与解决方案

你是否在使用PyTorch实现目标检测时遇到以下问题:

  • 预训练模型无法直接适配自定义数据集
  • 训练过程中损失不收敛或检测框偏移
  • 评估指标难以量化模型性能
  • GPU资源利用效率低下

本文将通过PyTorch_Practice项目中的Faster R-CNN实现,系统解决这些问题。读完本文你将获得:

  • 完整的Faster R-CNN训练/推理流程
  • 自定义数据集适配与数据增强技巧
  • 模型调优与性能评估方法
  • 可视化工具使用指南

Faster R-CNN原理速览

网络架构解析

Faster R-CNN是两阶段目标检测算法的经典之作,其核心创新在于引入区域提议网络(RPN)替代传统的选择性搜索方法。

mermaid

核心组件功能

组件功能描述关键参数
RPN生成高质量候选区域锚框尺寸[32,64,128,256,512]
ROI池化将不同尺寸ROI转为固定尺寸输出尺寸7×7
分类头预测目标类别21类(PASCAL VOC)
回归头优化边界框坐标4个坐标偏移值

环境准备与项目结构

开发环境配置

# 克隆项目仓库
git clone https://gitcode.com/gh_mirrors/py/PyTorch_Practice
cd PyTorch_Practice

# 安装依赖
pip install torch torchvision matplotlib numpy pillow

关键文件解析

目标检测相关代码主要位于lesson8目录:

lesson8/
├── fasterrcnn_demo.py      # Faster R-CNN完整训练流程
├── detection_demo.py       # 推理与可视化演示
├── demo_img1.png           # 测试图像1
├── demo_img2.png           # 测试图像2
└── my_dataset.py           # 数据集处理类

实战步骤:从数据到部署

1. 数据集准备与加载

PennFudanPed数据集结构示例:

PennFudanPed/
├── PNGImages/          # 图像文件
│   ├── FudanPed00001.png
│   └── ...
└── PedMasks/           # 掩码文件
    ├── FudanPed00001_mask.png
    └── ...

自定义数据集类实现(my_dataset.py):

class PennFudanDataset(object):
    def __init__(self, data_dir, transforms):
        self.data_dir = data_dir
        self.transforms = transforms
        self.imgs = list(sorted(os.listdir(os.path.join(data_dir, "PNGImages"))))
        self.masks = list(sorted(os.listdir(os.path.join(data_dir, "PedMasks"))))

    def __getitem__(self, idx):
        # 加载图像和掩码
        img_path = os.path.join(self.data_dir, "PNGImages", self.imgs[idx])
        mask_path = os.path.join(self.data_dir, "PedMasks", self.masks[idx])
        img = Image.open(img_path).convert("RGB")
        
        # 处理掩码获取边界框
        mask = Image.open(mask_path)
        mask = np.array(mask)
        obj_ids = np.unique(mask)
        obj_ids = obj_ids[1:]  # 排除背景
        
        masks = mask == obj_ids[:, None, None]
        num_objs = len(obj_ids)
        boxes = []
        
        # 计算每个目标的边界框
        for i in range(num_objs):
            pos = np.where(masks[i])
            xmin = np.min(pos[1])
            xmax = np.max(pos[1])
            ymin = np.min(pos[0])
            ymax = np.max(pos[0])
            boxes.append([xmin, ymin, xmax, ymax])
            
        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        labels = torch.ones((num_objs,), dtype=torch.int64)  # 所有目标都标记为1
        masks = torch.as_tensor(masks, dtype=torch.uint8)
        
        image_id = torch.tensor([idx])
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)
        
        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["masks"] = masks
        target["image_id"] = image_id
        target["area"] = area
        target["iscrowd"] = iscrowd
        
        if self.transforms is not None:
            img, target = self.transforms(img, target)
            
        return img, target

    def __len__(self):
        return len(self.imgs)

2. 数据增强策略

自定义数据增强组合(fasterrcnn_demo.py):

class Compose(object):
    def __init__(self, transforms):
        self.transforms = transforms

    def __call__(self, image, target):
        for t in self.transforms:
            image, target = t(image, target)
        return image, target

class RandomHorizontalFlip(object):
    def __init__(self, prob):
        self.prob = prob

    def __call__(self, image, target):
        if random.random() < self.prob:
            height, width = image.shape[-2:]
            image = image.flip(-1)  # 水平翻转图像
            bbox = target["boxes"]
            # 调整边界框坐标
            bbox[:, [0, 2]] = width - bbox[:, [2, 0]]
            target["boxes"] = bbox
        return image, target

class ToTensor(object):
    def __call__(self, image, target):
        image = F.to_tensor(image)
        return image, target

# 应用数据增强
train_transform = Compose([ToTensor(), RandomHorizontalFlip(0.5)])

3. 模型构建与配置

# 加载预训练模型
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)

# 替换分类头以适应自定义数据集
num_classes = 2  # 背景 + 行人
in_features = model.roi_heads.box_predictor.cls_score.in_features
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)

# 移动模型到GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

4. 训练流程实现

# 优化器配置
params = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.SGD(params, lr=0.001, momentum=0.9, weight_decay=0.0005)
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)

# 训练循环
num_epochs = 5
for epoch in range(num_epochs):
    model.train()
    for iter, (images, targets) in enumerate(train_loader):
        images = list(image.to(device) for image in images)
        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
        
        # 前向传播计算损失
        loss_dict = model(images, targets)
        losses = sum(loss for loss in loss_dict.values())
        
        # 反向传播与参数更新
        optimizer.zero_grad()
        losses.backward()
        optimizer.step()
        
        # 打印训练信息
        print(f"Epoch [{epoch+1}/{num_epochs}], Iteration [{iter+1}/{len(train_loader)}], Loss: {losses.item():.4f}")
    
    # 更新学习率
    lr_scheduler.step()

5. 推理与可视化

def vis_bbox(img, output, classes, max_vis=40, prob_thres=0.4):
    fig, ax = plt.subplots(figsize=(12, 12))
    ax.imshow(img, aspect='equal')
    
    out_boxes = output["boxes"].cpu()
    out_scores = output["scores"].cpu()
    out_labels = output["labels"].cpu()
    
    num_boxes = out_boxes.shape[0]
    for idx in range(0, min(num_boxes, max_vis)):
        score = out_scores[idx].numpy()
        bbox = out_boxes[idx].numpy()
        class_name = classes[out_labels[idx]]
        
        if score < prob_thres:
            continue
            
        # 绘制边界框
        ax.add_patch(plt.Rectangle((bbox[0], bbox[1]), bbox[2]-bbox[0], bbox[3]-bbox[1], 
                                  fill=False, edgecolor='red', linewidth=3.5))
        # 添加类别标签和置信度
        ax.text(bbox[0], bbox[1]-2, f'{class_name} {score:.3f}', 
               bbox=dict(facecolor='blue', alpha=0.5), fontsize=14, color='white')
    plt.show()

# 推理过程
model.eval()
preprocess = transforms.Compose([transforms.ToTensor()])
input_image = Image.open("demo_img1.png").convert("RGB")
img_chw = preprocess(input_image)

if torch.cuda.is_available():
    img_chw = img_chw.to('cuda')
    model.to('cuda')

with torch.no_grad():
    output_list = model([img_chw])
    output_dict = output_list[0]

# 可视化结果
vis_bbox(input_image, output_dict, COCO_INSTANCE_CATEGORY_NAMES, prob_thres=0.5)

模型调优与性能提升

关键超参数调整

参数推荐值范围调整策略
学习率1e-4 ~ 1e-2初始设为1e-3,根据损失曲线调整
批大小1 ~ 8GPU显存允许时尽量增大
权重衰减1e-5 ~ 1e-3防止过拟合,默认1e-4
置信度阈值0.3 ~ 0.7高阈值减少误检,低阈值提高召回率

常见问题解决方案

  1. 训练损失不收敛

    • 检查数据标注是否正确
    • 尝试降低学习率或使用学习率预热
    • 确保数据增强没有破坏目标结构
  2. 检测框定位不准

    • 增加训练轮次
    • 调整边界框回归损失权重
    • 使用更复杂的数据增强
  3. 推理速度慢

    • 减少候选区域数量
    • 使用半精度推理
    • 优化前处理/后处理步骤

评估指标与模型保存

评估指标计算

from pycocotools.cocoeval import COCOeval

def evaluate(model, data_loader, device):
    model.eval()
    coco = COCO(annFile)
    cocoDt = coco.loadRes(results)
    cocoEval = COCOeval(coco, cocoDt, 'bbox')
    cocoEval.evaluate()
    cocoEval.accumulate()
    cocoEval.summarize()
    return cocoEval.stats

模型保存与加载

# 保存模型
torch.save({
    'epoch': epoch,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'loss': losses,
}, 'fasterrcnn_checkpoint.pth')

# 加载模型
checkpoint = torch.load('fasterrcnn_checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']

高级应用:多GPU训练与部署

多GPU训练配置

# 使用DataParallel实现多GPU训练
if torch.cuda.device_count() > 1:
    print(f"Using {torch.cuda.device_count()} GPUs")
    model = nn.DataParallel(model)

model.to(device)

部署优化策略

  1. 模型导出为ONNX格式
dummy_input = torch.randn(1, 3, 640, 480).to(device)
torch.onnx.export(model, dummy_input, "fasterrcnn.onnx", opset_version=11)
  1. TensorRT加速
import tensorrt as trt
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
parser = trt.OnnxParser(network, TRT_LOGGER)
with open("fasterrcnn.onnx", "rb") as model_file:
    parser.parse(model_file.read())

总结与未来展望

通过本文学习,你已经掌握了基于PyTorch实现Faster R-CNN目标检测的完整流程,包括:

  • 数据集准备与数据增强
  • 模型构建与训练
  • 推理与可视化
  • 性能评估与优化

未来可以进一步探索:

  • 结合注意力机制提升小目标检测性能
  • 尝试改进的Anchor-Free检测算法
  • 多模态目标检测融合RGB与深度信息

希望本文能帮助你在目标检测领域取得更好的成果!如有任何问题,欢迎在项目仓库提交issue交流讨论。

附录:完整代码获取

git clone https://gitcode.com/gh_mirrors/py/PyTorch_Practice
cd PyTorch_Practice/lesson8
python fasterrcnn_demo.py

该项目包含本文所有示例代码,可直接运行体验Faster R-CNN目标检测效果。

【免费下载链接】PyTorch_Practice 这是我学习 PyTorch 的笔记对应的代码,点击查看 PyTorch 笔记在线电子书 【免费下载链接】PyTorch_Practice 项目地址: https://gitcode.com/gh_mirrors/py/PyTorch_Practice

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值