R-CNN到Faster R-CNN:两阶段检测的演进之路

系列文章 目标检测第 1 篇 / 共 8 篇

从 R-CNN 到 YOLO 全系列,深入目标检测的技术迭代与工业部署实践。

  1. R-CNN到Faster R-CNN:两阶段检测的演进之路
  2. YOLO v1:实时目标检测的革命
  3. YOLO v2/v3:多尺度检测的进化之路
  4. YOLO v4:CSPNet与数据增强的艺术
  5. YOLO v5:工业化的成功
  6. YOLO v8:Ultralytics的现代架构
  7. YOLO变种:RT-DETR、YOLO-NAS等
  8. YOLO实战:从训练到部署

引言

在深度学习目标检测的发展历程中,R-CNN系列占据着举足轻重的地位。从2014年的R-CNN到2016年的Faster R-CNN,短短两年间,目标检测领域发生了翻天覆地的变化。

为什么需要了解R-CNN系列?

虽然YOLO系列后来居上,但R-CNN系列的两阶段检测思想至今仍有重要价值:

  • 精度优势:两阶段检测在精度上仍有优势
  • 理论基础:为理解目标检测提供重要理论基础
  • 技术演进:展示了深度学习在目标检测中的演进过程
  • YOLO铺垫:理解R-CNN的局限性,才能更好理解YOLO的革命性

本系列学习路径

R-CNN系列(两阶段) → YOLO v1(一阶段革命) → YOLO进化 → 现代YOLO

📄 论文信息
作者 Ross Girshick, et al. (UC Berkeley)
发表 CVPR (2014)
arXiv 1311.2524

目标检测基础回顾

什么是目标检测?

目标检测 = 目标定位 + 目标分类

输入:图像
输出:每个目标的边界框 + 类别标签

示例:
图像中有:人、汽车、狗
输出:
- 人:边界框(x1,y1,x2,y2) + 类别"person"
- 汽车:边界框(x1,y1,x2,y2) + 类别"car"  
- 狗:边界框(x1,y1,x2,y2) + 类别"dog"

传统方法 vs 深度学习方法

传统方法(2014年前)

步骤1:特征提取
- HOG(方向梯度直方图)
- SIFT(尺度不变特征变换)
- LBP(局部二值模式)

步骤2:分类器
- SVM(支持向量机)
- AdaBoost
- 随机森林

问题:
✗ 特征表达能力有限
✗ 手工设计特征
✗ 精度不高
✗ 速度慢

深度学习方法(2014年后)

步骤1:CNN特征提取
- 自动学习特征
- 端到端训练
- 强大表达能力

步骤2:检测头
- 分类 + 回归
- 端到端优化

优势:
✅ 特征自动学习
✅ 端到端训练
✅ 精度大幅提升
✅ 可扩展性强

R-CNN:CNN特征提取的开创

核心思想

R-CNN = Region-based CNN

传统思路:
图像 → 特征提取 → 分类

R-CNN思路:
图像 → 候选区域 → CNN特征提取 → 分类

关键创新

  1. Region Proposals:使用Selective Search生成候选区域
  2. CNN特征:用CNN替代手工特征
  3. 分类器:SVM分类器 + 边界框回归

R-CNN架构详解

Region Proposal生成

Selective Search算法

def selective_search(image, scale=1.0, sigma=0.8, min_size=50):
    """
    Selective Search算法生成候选区域
    
    Args:
        image: 输入图像
        scale: 图像缩放因子
        sigma: 高斯模糊参数
        min_size: 最小区域大小
    
    Returns:
        regions: 候选区域列表 [(x, y, w, h), ...]
    """
    import cv2
    from skimage import segmentation, color
    
    # 1. 图像预处理
    img_lbl, regions = segmentation.slic(
        image, compactness=30, n_segments=100, sigma=sigma
    )
    
    # 2. 计算区域特征
    img_color = color.rgb2lab(image)
    
    # 3. 层次聚类
    regions = []
    for region in img_lbl:
        # 计算区域边界框
        y, x = np.where(img_lbl == region)
        if len(x) > min_size:
            regions.append((x.min(), y.min(), x.max()-x.min(), y.max()-y.min()))
    
    return regions

# 示例使用
image = cv2.imread('image.jpg')
regions = selective_search(image)
print(f"生成了 {len(regions)} 个候选区域")

Selective Search的优势

  • ✅ 多尺度检测
  • ✅ 多样化区域形状
  • ✅ 计算效率较高
  • ✅ 召回率较高

CNN特征提取

AlexNet作为特征提取器

import torch
import torch.nn as nn
import torchvision.models as models

class RCNNFeatureExtractor(nn.Module):
    def __init__(self, num_classes=1000):
        super(RCNNFeatureExtractor, self).__init__()
        
        # 使用预训练的AlexNet
        alexnet = models.alexnet(pretrained=True)
        
        # 移除最后的分类层
        self.features = alexnet.features
        self.classifier = alexnet.classifier[:-1]  # 移除最后一层
        
        # 添加新的分类层
        self.fc = nn.Linear(4096, num_classes)
    
    def forward(self, x):
        # 特征提取
        x = self.features(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        
        return x

# 使用示例
model = RCNNFeatureExtractor(num_classes=20)  # VOC 20类

训练过程

R-CNN训练步骤

def train_rcnn(model, regions, image, gt_boxes, gt_labels):
    """
    R-CNN训练过程
    
    Args:
        model: CNN特征提取器
        regions: 候选区域
        image: 输入图像
        gt_boxes: 真实边界框
        gt_labels: 真实标签
    """
    
    # 1. 为每个候选区域提取特征
    features = []
    labels = []
    
    for region in regions:
        # 裁剪区域
        x, y, w, h = region
        roi = image[y:y+h, x:x+w]
        
        # 调整到固定尺寸 (227x227 for AlexNet)
        roi_resized = cv2.resize(roi, (227, 227))
        
        # 特征提取
        with torch.no_grad():
            feature = model(torch.tensor(roi_resized).unsqueeze(0))
            features.append(feature)
        
        # 标签分配(IoU > 0.5为正样本)
        iou = calculate_iou(region, gt_boxes)
        if iou.max() > 0.5:
            labels.append(gt_labels[iou.argmax()])
        else:
            labels.append(0)  # 背景类
    
    return features, labels

def calculate_iou(box1, boxes2):
    """计算IoU"""
    x1, y1, w1, h1 = box1
    x2, y2, w2, h2 = boxes2[:, 0], boxes2[:, 1], boxes2[:, 2], boxes2[:, 3]
    
    # 计算交集
    x_left = np.maximum(x1, x2)
    y_top = np.maximum(y1, y2)
    x_right = np.minimum(x1 + w1, x2 + w2)
    y_bottom = np.minimum(y1 + h1, y2 + h2)
    
    intersection = np.maximum(0, x_right - x_left) * np.maximum(0, y_bottom - y_top)
    
    # 计算并集
    area1 = w1 * h1
    area2 = w2 * h2
    union = area1 + area2 - intersection
    
    return intersection / union

边界框回归

Bounding Box Regression

class BBoxRegressor(nn.Module):
    def __init__(self, feature_dim=4096):
        super(BBoxRegressor, self).__init__()
        self.regressor = nn.Linear(feature_dim, 4)  # 预测 (dx, dy, dw, dh)
    
    def forward(self, features):
        return self.regressor(features)
    
    def encode_bbox(self, gt_bbox, anchor_bbox):
        """
        编码边界框回归目标
        
        Args:
            gt_bbox: 真实边界框 (x, y, w, h)
            anchor_bbox: 锚框 (x, y, w, h)
        
        Returns:
            targets: 回归目标 (dx, dy, dw, dh)
        """
        gt_x, gt_y, gt_w, gt_h = gt_bbox
        anchor_x, anchor_y, anchor_w, anchor_h = anchor_bbox
        
        # 计算回归目标
        dx = (gt_x - anchor_x) / anchor_w
        dy = (gt_y - anchor_y) / anchor_h
        dw = np.log(gt_w / anchor_w)
        dh = np.log(gt_h / anchor_h)
        
        return np.array([dx, dy, dw, dh])
    
    def decode_bbox(self, predictions, anchor_bbox):
        """
        解码边界框回归预测
        
        Args:
            predictions: 模型预测 (dx, dy, dw, dh)
            anchor_bbox: 锚框 (x, y, w, h)
        
        Returns:
            bbox: 预测边界框 (x, y, w, h)
        """
        dx, dy, dw, dh = predictions
        anchor_x, anchor_y, anchor_w, anchor_h = anchor_bbox
        
        # 解码预测
        pred_x = dx * anchor_w + anchor_x
        pred_y = dy * anchor_h + anchor_y
        pred_w = anchor_w * np.exp(dw)
        pred_h = anchor_h * np.exp(dh)
        
        return np.array([pred_x, pred_y, pred_w, pred_h])

R-CNN的局限性

计算效率低

问题分析:
- 每个候选区域都要通过CNN
- 2000个候选区域 × CNN前向传播
- 大量重复计算

示例:
图像:500×500
候选区域:2000个
CNN:AlexNet (约1GFLOPs)
总计算量:2000 × 1GFLOPs = 2000GFLOPs

训练复杂

训练步骤:
1. 预训练CNN(ImageNet)
2. 微调CNN(VOC数据集)
3. 训练SVM分类器
4. 训练边界框回归器

问题:
- 多阶段训练
- 存储空间大
- 训练时间长

速度慢

推理时间:
- 特征提取:2000 × 0.5s = 1000s
- SVM分类:2000 × 0.01s = 20s
- 边界框回归:2000 × 0.01s = 20s
- 总计:约17分钟/图像

无法实时应用

[1]


Fast R-CNN:共享计算优化

📄 论文信息
作者 Ross Girshick (Microsoft Research)
发表 ICCV (2015)
arXiv 1504.08083

核心创新

Fast R-CNN = 共享特征提取 + ROI Pooling

R-CNN问题:
图像 → 2000个候选区域 → 2000次CNN前向传播

Fast R-CNN解决方案:
图像 → 1次CNN前向传播 → ROI Pooling → 分类+回归

关键组件

ROI Pooling

ROI Pooling的作用:将不同尺寸的候选区域转换为固定尺寸的特征

import torch
import torch.nn as nn
import torch.nn.functional as F

class ROIPooling(nn.Module):
    def __init__(self, output_size):
        super(ROIPooling, self).__init__()
        self.output_size = output_size
    
    def forward(self, feature_map, rois):
        """
        ROI Pooling前向传播
        
        Args:
            feature_map: 特征图 (B, C, H, W)
            rois: 候选区域 (N, 5) [batch_idx, x1, y1, x2, y2]
        
        Returns:
            pooled_features: 池化后的特征 (N, C, output_h, output_w)
        """
        batch_size, channels, height, width = feature_map.size()
        num_rois = rois.size(0)
        
        # 初始化输出
        pooled_features = torch.zeros(num_rois, channels, self.output_size[0], self.output_size[1])
        
        for i, roi in enumerate(rois):
            batch_idx, x1, y1, x2, y2 = roi.int()
            
            # 确保坐标在有效范围内
            x1 = max(0, min(x1, width-1))
            y1 = max(0, min(y1, height-1))
            x2 = max(x1+1, min(x2, width))
            y2 = max(y1+1, min(y2, height))
            
            # 提取ROI特征
            roi_feature = feature_map[batch_idx, :, y1:y2, x1:x2]
            
            # 自适应池化到固定尺寸
            pooled_roi = F.adaptive_avg_pool2d(roi_feature, self.output_size)
            pooled_features[i] = pooled_roi
        
        return pooled_features

# 使用示例
roi_pooling = ROIPooling(output_size=(7, 7))
feature_map = torch.randn(1, 256, 32, 32)  # 特征图
rois = torch.tensor([[0, 10, 10, 20, 20], [0, 15, 15, 25, 25]])  # 候选区域
pooled_features = roi_pooling(feature_map, rois)
print(f"池化后特征尺寸: {pooled_features.shape}")  # (2, 256, 7, 7)

端到端训练

Fast R-CNN网络架构

class FastRCNN(nn.Module):
    def __init__(self, num_classes=21):
        super(FastRCNN, self).__init__()
        
        # 特征提取网络(VGG16)
        self.features = nn.Sequential(
            # VGG16的卷积层
            nn.Conv2d(3, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),
            
            nn.Conv2d(64, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),
            
            # ... 更多卷积层
        )
        
        # ROI Pooling
        self.roi_pooling = ROIPooling(output_size=(7, 7))
        
        # 分类头
        self.classifier = nn.Sequential(
            nn.Linear(256 * 7 * 7, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
        )
        
        # 分类分支
        self.cls_score = nn.Linear(4096, num_classes)
        
        # 回归分支
        self.bbox_pred = nn.Linear(4096, num_classes * 4)
    
    def forward(self, images, rois):
        # 特征提取
        feature_map = self.features(images)
        
        # ROI Pooling
        pooled_features = self.roi_pooling(feature_map, rois)
        
        # 展平
        pooled_features = pooled_features.view(pooled_features.size(0), -1)
        
        # 分类器
        features = self.classifier(pooled_features)
        
        # 分类和回归
        cls_scores = self.cls_score(features)
        bbox_preds = self.bbox_pred(features)
        
        return cls_scores, bbox_preds

多任务损失函数

Fast R-CNN损失函数

class FastRCNNLoss(nn.Module):
    def __init__(self, num_classes=21):
        super(FastRCNNLoss, self).__init__()
        self.num_classes = num_classes
        self.cls_criterion = nn.CrossEntropyLoss()
        self.bbox_criterion = nn.SmoothL1Loss()
    
    def forward(self, cls_scores, bbox_preds, labels, bbox_targets):
        """
        计算Fast R-CNN损失
        
        Args:
            cls_scores: 分类预测 (N, num_classes)
            bbox_preds: 回归预测 (N, num_classes * 4)
            labels: 真实标签 (N,)
            bbox_targets: 回归目标 (N, 4)
        """
        # 分类损失
        cls_loss = self.cls_criterion(cls_scores, labels)
        
        # 回归损失(仅对正样本计算)
        pos_mask = labels > 0
        if pos_mask.sum() > 0:
            pos_bbox_preds = bbox_preds[pos_mask]
            pos_bbox_targets = bbox_targets[pos_mask]
            bbox_loss = self.bbox_criterion(pos_bbox_preds, pos_bbox_targets)
        else:
            bbox_loss = 0
        
        # 总损失
        total_loss = cls_loss + bbox_loss
        
        return total_loss, cls_loss, bbox_loss

Fast R-CNN的优势

速度提升

计算对比:

R-CNN:
- 2000个候选区域 × CNN前向传播
- 总计算量:2000 × 1GFLOPs = 2000GFLOPs

Fast R-CNN:
- 1次CNN前向传播 + ROI Pooling
- 总计算量:1GFLOPs + ROI Pooling
- 加速比:约10-20倍

[2]

端到端训练

训练流程:
1. 预训练CNN(ImageNet)
2. 端到端微调(VOC数据集)

优势:
- 简化训练流程
- 更好的特征学习
- 端到端优化

精度提升

VOC 2007数据集结果:
- R-CNN: mAP = 58.5%
- Fast R-CNN: mAP = 66.9%
- 提升:+8.4%

[1][2]


Faster R-CNN:端到端检测

📄 论文信息
作者 Shaoqing Ren, et al. (Microsoft Research)
发表 NIPS (2015)
arXiv 1506.01497

核心创新

Faster R-CNN = RPN + Fast R-CNN

Fast R-CNN问题:
图像 → Selective Search → 候选区域 → Fast R-CNN

Faster R-CNN解决方案:
图像 → RPN → 候选区域 → Fast R-CNN

关键组件

Region Proposal Network (RPN)

RPN的作用:用CNN替代Selective Search生成候选区域

class RPN(nn.Module):
    def __init__(self, in_channels=256, num_anchors=9):
        super(RPN, self).__init__()
        self.num_anchors = num_anchors
        
        # 共享卷积层
        self.conv = nn.Conv2d(in_channels, 512, 3, padding=1)
        self.relu = nn.ReLU(inplace=True)
        
        # 分类头(前景/背景)
        self.cls_head = nn.Conv2d(512, num_anchors * 2, 1)
        
        # 回归头(边界框回归)
        self.bbox_head = nn.Conv2d(512, num_anchors * 4, 1)
    
    def forward(self, features):
        """
        RPN前向传播
        
        Args:
            features: 特征图 (B, C, H, W)
        
        Returns:
            cls_scores: 分类分数 (B, num_anchors*2, H, W)
            bbox_preds: 回归预测 (B, num_anchors*4, H, W)
        """
        # 共享卷积
        x = self.relu(self.conv(features))
        
        # 分类和回归
        cls_scores = self.cls_head(x)
        bbox_preds = self.bbox_head(x)
        
        return cls_scores, bbox_preds

Anchor机制

Anchor的作用:为每个位置预设多个尺度和宽高比的候选框

def generate_anchors(base_size=16, ratios=[0.5, 1, 2], scales=[8, 16, 32]):
    """
    生成Anchor
    
    Args:
        base_size: 基础尺寸
        ratios: 宽高比
        scales: 尺度
    
    Returns:
        anchors: Anchor坐标 (num_anchors, 4)
    """
    anchors = []
    
    for scale in scales:
        for ratio in ratios:
            # 计算宽高
            w = base_size * scale * np.sqrt(ratio)
            h = base_size * scale / np.sqrt(ratio)
            
            # 中心点坐标(以(0,0)为中心)
            x1 = -w / 2
            y1 = -h / 2
            x2 = w / 2
            y2 = h / 2
            
            anchors.append([x1, y1, x2, y2])
    
    return np.array(anchors)

# 使用示例
anchors = generate_anchors()
print(f"生成了 {len(anchors)} 个Anchor")
print(f"Anchor形状: {anchors.shape}")  # (9, 4)

完整Faster R-CNN架构

class FasterRCNN(nn.Module):
    def __init__(self, num_classes=21):
        super(FasterRCNN, self).__init__()
        
        # 共享特征提取网络
        self.features = self._build_feature_extractor()
        
        # RPN
        self.rpn = RPN(in_channels=256, num_anchors=9)
        
        # Fast R-CNN
        self.roi_pooling = ROIPooling(output_size=(7, 7))
        self.classifier = self._build_classifier(num_classes)
    
    def _build_feature_extractor(self):
        """构建特征提取网络"""
        return nn.Sequential(
            # VGG16的卷积层
            nn.Conv2d(3, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),
            
            # ... 更多卷积层
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
        )
    
    def _build_classifier(self, num_classes):
        """构建分类器"""
        return nn.Sequential(
            nn.Linear(256 * 7 * 7, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(4096, num_classes),
        )
    
    def forward(self, images):
        # 特征提取
        features = self.features(images)
        
        # RPN预测
        rpn_cls, rpn_bbox = self.rpn(features)
        
        # 生成候选区域
        rois = self._generate_rois(rpn_cls, rpn_bbox)
        
        # ROI Pooling
        pooled_features = self.roi_pooling(features, rois)
        
        # 分类
        pooled_features = pooled_features.view(pooled_features.size(0), -1)
        cls_scores = self.classifier(pooled_features)
        
        return cls_scores, rois

训练策略

交替训练(Alternating Training)

def train_faster_rcnn(model, dataloader, num_epochs=10):
    """
    Faster R-CNN训练
    
    训练策略:
    1. 训练RPN
    2. 用RPN生成候选区域训练Fast R-CNN
    3. 微调RPN
    4. 微调Fast R-CNN
    """
    
    # 阶段1:训练RPN
    print("阶段1:训练RPN")
    for epoch in range(num_epochs // 4):
        for images, gt_boxes, gt_labels in dataloader:
            # RPN损失
            rpn_loss = compute_rpn_loss(model, images, gt_boxes)
            
            # 反向传播
            rpn_loss.backward()
            optimizer.step()
    
    # 阶段2:训练Fast R-CNN
    print("阶段2:训练Fast R-CNN")
    for epoch in range(num_epochs // 4):
        for images, gt_boxes, gt_labels in dataloader:
            # 用RPN生成候选区域
            with torch.no_grad():
                rois = model.generate_rois(images)
            
            # Fast R-CNN损失
            fast_rcnn_loss = compute_fast_rcnn_loss(model, images, rois, gt_boxes, gt_labels)
            
            # 反向传播
            fast_rcnn_loss.backward()
            optimizer.step()
    
    # 阶段3:微调RPN
    print("阶段3:微调RPN")
    for epoch in range(num_epochs // 4):
        # ... 微调RPN
    
    # 阶段4:微调Fast R-CNN
    print("阶段4:微调Fast R-CNN")
    for epoch in range(num_epochs // 4):
        # ... 微调Fast R-CNN

def compute_rpn_loss(model, images, gt_boxes):
    """计算RPN损失"""
    features = model.features(images)
    rpn_cls, rpn_bbox = model.rpn(features)
    
    # 计算RPN分类损失
    cls_loss = F.cross_entropy(rpn_cls, rpn_labels)
    
    # 计算RPN回归损失
    bbox_loss = F.smooth_l1_loss(rpn_bbox, rpn_targets)
    
    return cls_loss + bbox_loss

Faster R-CNN的优势

端到端训练

训练流程:
1. 预训练CNN(ImageNet)
2. 端到端训练(VOC数据集)

优势:
- 统一优化目标
- 更好的特征学习
- 简化训练流程

速度大幅提升

速度对比:
- R-CNN: 17分钟/图像
- Fast R-CNN: 2.3秒/图像
- Faster R-CNN: 0.2秒/图像

提升:85倍加速

[3]

精度保持

VOC 2007数据集结果:
- R-CNN: mAP = 58.5%
- Fast R-CNN: mAP = 66.9%
- Faster R-CNN: mAP = 70.0%

精度:持续提升

[1][2][3]


性能对比

速度对比

方法 推理时间 加速比 说明
R-CNN 17分钟 基准
Fast R-CNN 2.3秒 440× 共享计算
Faster R-CNN 0.2秒 5100× 端到端

精度对比

方法 VOC 2007 mAP VOC 2012 mAP 说明
R-CNN 58.5% 53.7% 基准
Fast R-CNN 66.9% 65.7% +8.4%
Faster R-CNN 70.0% 68.4% +11.5%

训练时间对比

方法 训练时间 存储需求 说明
R-CNN 84小时 200GB 多阶段训练
Fast R-CNN 9小时 2.5GB 端到端训练
Faster R-CNN 12小时 2.8GB 端到端训练

[1][2][3]


R-CNN系列的贡献与局限

✅ 主要贡献

开创性工作

R-CNN系列的开创性:
- 首次将CNN应用于目标检测
- 证明了深度学习在目标检测中的有效性
- 为后续工作奠定了基础

技术演进

技术演进路径:
R-CNN → Fast R-CNN → Faster R-CNN
  ↓         ↓           ↓
CNN特征   共享计算    端到端训练

精度优势

两阶段检测的优势:
- 精度高:mAP > 70%
- 稳定性好:训练稳定
- 可解释性强:分阶段处理

❌ 主要局限

速度限制

速度瓶颈:
- 两阶段处理:候选区域生成 + 检测
- 无法实时应用:> 0.1秒
- 计算复杂度高:O(N²)

架构复杂

架构复杂性:
- 多组件:RPN + Fast R-CNN
- 训练复杂:交替训练
- 调参困难:超参数多

小目标检测差

小目标检测问题:
- 特征分辨率低
- 候选区域质量差
- 检测精度低

为YOLO革命做铺垫

R-CNN系列的启示

精度与速度的权衡

R-CNN系列启示:
- 精度高但速度慢
- 两阶段检测的局限性
- 需要新的检测范式

端到端训练的重要性

端到端训练优势:
- 统一优化目标
- 更好的特征学习
- 简化训练流程

实时检测的需求

实时检测需求:
- 自动驾驶:实时性要求
- 视频分析:实时处理
- 移动应用:资源受限

YOLO革命的前奏

YOLO革命的前奏:
- R-CNN系列证明了CNN的有效性
- 但速度无法满足实时需求
- 需要一阶段检测的新范式
- 为YOLO的诞生奠定了基础

R-CNN家族三代对比

graph LR
    subgraph RCNN["R-CNN (2014)<br/>17 min/img · 58.5 mAP"]
        R1[Input] --> R2[Selective Search<br/>2000 Regions]
        R2 --> R3["CNN ×2000<br/>Very Slow"]
        R3 --> R4["SVM + BBox Reg"]
    end
    subgraph FastRCNN["Fast R-CNN (2015)<br/>2.3s/img · 66.9 mAP"]
        F1[Input] --> F2["CNN ×1<br/>Fast"]
        F2 --> F3["ROI Pooling"]
        F3 --> F4["FC + Softmax<br/>+ BBox Reg"]
    end
    subgraph FasterRCNN["Faster R-CNN (2015)<br/>0.2s/img · 70.0 mAP"]
        G1[Input] --> G2["CNN + RPN<br/>Shared Features"]
        G2 --> G3["ROI Pooling<br/>+ Detection"]
    end

总结

R-CNN系列的核心贡献

  1. 开创性工作:首次将CNN应用于目标检测
  2. 技术演进:从R-CNN到Faster R-CNN的完整演进
  3. 精度提升:mAP从58.5%提升到70.0%
  4. 速度优化:从17分钟优化到0.2秒

技术演进总结

R-CNN (2014):
- CNN特征提取
- SVM分类器
- 精度:58.5%

Fast R-CNN (2015):
- 共享特征提取
- ROI Pooling
- 精度:66.9%

Faster R-CNN (2015):
- RPN + Fast R-CNN
- 端到端训练
- 精度:70.0%

为YOLO系列做铺垫

R-CNN系列虽然精度高,但速度慢,无法满足实时检测需求。这为YOLO系列的一阶段检测革命奠定了基础。


参考资料

  1. R-CNN: Girshick, R., et al. (2014). "Rich Feature Hierarchies for Accurate Object Detection and Semantic Segmentation." CVPR 2014. arXiv:1311.2524.
  2. Fast R-CNN: Girshick, R. (2015). "Fast R-CNN." ICCV 2015. arXiv:1504.08083.
  3. Faster R-CNN: Ren, S., et al. (2015). "Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks." NeurIPS 2015. arXiv:1506.01497.
  4. Mask R-CNN: He, K., et al. (2017). "Mask R-CNN." ICCV 2017. arXiv:1703.06870.

代码实现

数据集

  • PASCAL VOC - 目标检测基准数据集
  • COCO - 大规模目标检测数据集

文章目录