首页
/ keras-retinanet项目中的RetinaNet模型架构解析

keras-retinanet项目中的RetinaNet模型架构解析

2025-07-08 07:33:59作者:蔡怀权

概述

RetinaNet是一种流行的单阶段目标检测算法,由Facebook AI Research团队提出。本文主要分析keras-retinanet项目中retinanet.py文件的核心实现,该文件包含了RetinaNet模型的主要构建逻辑。

RetinaNet模型架构

RetinaNet模型主要由三部分组成:

  1. 特征金字塔网络(FPN)
  2. 分类子网络
  3. 回归子网络

特征金字塔网络(FPN)

FPN是RetinaNet的核心组件之一,它通过自顶向下和横向连接的方式构建多尺度特征金字塔:

def __create_pyramid_features(backbone_layers, pyramid_levels, feature_size=256):
    # 从骨干网络C5层开始构建P5
    P5 = keras.layers.Conv2D(feature_size, kernel_size=1, name='C5_reduced')(backbone_layers['C5'])
    P5_upsampled = layers.UpsampleLike(name='P5_upsampled')([P5, backbone_layers['C4']])
    P5 = keras.layers.Conv2D(feature_size, kernel_size=3, name='P5')(P5)
    
    # 构建P4层
    P4 = keras.layers.Conv2D(feature_size, kernel_size=1, name='C4_reduced')(backbone_layers['C4'])
    P4 = keras.layers.Add(name='P4_merged')([P5_upsampled, P4])
    # 后续类似构建P3,P2等...

FPN通过这种方式构建了P3-P7五个特征层,每个特征层对应不同的感受野,可以检测不同尺度的目标。

分类子网络

分类子网络负责预测每个锚框的类别概率:

def default_classification_model(num_classes, num_anchors, pyramid_feature_size=256):
    # 4个3x3卷积层
    for i in range(4):
        outputs = keras.layers.Conv2D(
            filters=classification_feature_size,
            activation='relu',
            name='pyramid_classification_{}'.format(i),
            **options
        )(outputs)
    
    # 最后的分类层
    outputs = keras.layers.Conv2D(
        filters=num_classes * num_anchors,
        name='pyramid_classification',
        **options
    )(outputs)
    
    # 输出处理
    outputs = keras.layers.Reshape((-1, num_classes))(outputs)
    outputs = keras.layers.Activation('sigmoid')(outputs)

分类子网络采用4个3x3卷积层后接1个1x1卷积层的结构,最后通过sigmoid激活函数输出每个类别的概率。

回归子网络

回归子网络负责预测锚框的偏移量:

def default_regression_model(num_values, num_anchors, pyramid_feature_size=256):
    # 4个3x3卷积层
    for i in range(4):
        outputs = keras.layers.Conv2D(
            filters=regression_feature_size,
            activation='relu',
            name='pyramid_regression_{}'.format(i),
            **options
        )(outputs)
    
    # 最后的回归层
    outputs = keras.layers.Conv2D(num_anchors * num_values, name='pyramid_regression', **options)(outputs)
    outputs = keras.layers.Reshape((-1, num_values))(outputs)

回归子网络结构与分类子网络类似,但没有最后的sigmoid激活,直接输出4个坐标偏移量。

模型构建流程

完整的RetinaNet模型构建流程如下:

  1. 从骨干网络提取特征(C3-C5)
  2. 构建FPN金字塔特征(P3-P7)
  3. 在每个金字塔层级应用分类和回归子网络
  4. 生成锚框
  5. 将预测结果应用到锚框上
def retinanet(inputs, backbone_layers, num_classes):
    # 1. 构建FPN特征金字塔
    features = create_pyramid_features(backbone_layers, pyramid_levels)
    
    # 2. 获取各金字塔层级的特征
    feature_list = [features['P{}'.format(p)] for p in pyramid_levels]
    
    # 3. 在各层级应用子模型
    pyramids = __build_pyramid(submodels, feature_list)
    
    return keras.models.Model(inputs=inputs, outputs=pyramids)

后处理

RetinaNet的后处理包括:

  1. 将回归预测应用到锚框上得到检测框
  2. 使用NMS过滤重叠框
  3. 应用置信度阈值
def retinanet_bbox(model, nms=True, class_specific_filter=True):
    # 1. 计算锚框
    anchors = __build_anchors(anchor_params, features)
    
    # 2. 应用回归预测
    boxes = layers.RegressBoxes()([anchors, regression])
    
    # 3. 过滤检测结果
    detections = layers.FilterDetections(
        nms=nms,
        score_threshold=score_threshold,
        max_detections=max_detections
    )([boxes, classification])

关键实现细节

  1. 锚框生成:根据特征图大小和锚框参数动态生成锚框
  2. 特征金字塔:通过上采样和相加操作构建多尺度特征
  3. 子网络共享权重:所有金字塔层级共享分类和回归子网络的权重
  4. 焦点损失:虽然代码中未显示,但RetinaNet使用焦点损失解决类别不平衡问题

总结

keras-retinanet项目的retinanet.py文件实现了RetinaNet的核心架构,包括特征金字塔网络、分类和回归子网络以及后处理流程。通过模块化的设计,可以方便地替换骨干网络或调整模型参数。理解这个实现有助于深入掌握单阶段目标检测算法的核心思想。