首页
/ tensorflow/models 官方 Legacy 目标检测模块实战指南:RetinaNet、Mask R-CNN 与 ShapeMask 的 TPU/GPU 分布式训练

tensorflow/models 官方 Legacy 目标检测模块实战指南:RetinaNet、Mask R-CNN 与 ShapeMask 的 TPU/GPU 分布式训练

2026-09-05 14:38:35作者:盛欣凯Ernestine

本文围绕 official/legacy/detection 模块的训练指南展开,系统讲解如何在该仓库中用 TPU 或 GPU 分布式策略训练 RetinaNet、Mask R-CNN 和 ShapeMask 三类检测/实例分割模型,覆盖完整的命令行参数、YAML 配置文件与行内 params_override 用法,并结合入口文件 main.py、配置工厂 configs/factory.py 与模型实现 retinanet_model.py 剖析参数如何落到网络结构与损失函数上。读完你可以直接照抄命令启动训练、按数据集改写配置,并理解每个关键超参的默认值与底层作用。

1. 模块定位与目录结构

该模块位于仓库的 official/legacy/detection 目录下,是 TensorFlow 2 时代的目标检测模型实现。需要特别注意,官方 README 开头给出了弃用警告:该目录后续将被 vision/beta/ 中的新实现取代,因此它更适合作为研究检测模型训练全流程(数据解析、骨干网络、多尺度特征、目标头、分布式训练器、COCO 评估)的完整参考实现,而不是新项目的唯一长期依赖。

从源码结构看,整个模块按职责分成了清晰的子包:

目录 职责
configs/ 基础配置模板 BASE_CFG 与各模型(retinanet/maskrcnn/shapemask/olnmask)的差异化配置、配置工厂
dataloader/ TFRecord 数据读取、锚框生成与各模型专属 parser(数据解码与增广)
modeling/ 模型定义(RetinanetModelMaskrcnnModelShapeMaskModel 等)、架构工厂(backbone/FPN/heads)、损失函数、优化器
evaluation/ COCO 评估器(box、box_and_mask 等)
executor/ 分布式训练执行器 DetectionDistributedExecutor
ops/ NMS、ROI、后处理算子
utils/ 框/掩码/类别工具函数

统一入口是 official/legacy/detection/main.py,README 中所有训练命令都以它为目标。

2. 前置准备

按照 official/legacy/detection/README.md 的说法,准备工作分两步:

  1. 获取代码:从 TensorFlow models 仓库克隆代码,或使用预装好的 Google Cloud VM(镜像中已放在 ~/models)。本文引用仓库内文件时,对应本地相对路径为 official/legacy/detection/...
  2. 环境要求:在 Google Cloud 上使用 TensorFlow 2.1+,然后安装依赖:
sudo apt-get install -y python-tk && \
pip3 install -r ~/models/official/requirements.txt

其中依赖清单即仓库中的 official/requirements.txtpython-tk 是为可视化/图像相关依赖服务的;requirements.txt 一次性安装该模块运行所需的全部 Python 包。

3. 命令行接口与参数体系

在动手训练前,理解入口的参数解析链路非常关键,因为 README 中所有命令都是这条链路的产物。

3.1 关键命令行标志

main.py 中定义了核心标志(除公共标志外):

标志 默认值 说明
--mode train 运行模式:trainevaleval_once
--model retinanet 要运行的模型:retinanetmask_rcnnshapemask
--strategy_type 公共标志 分布策略:tpumirroredone_device
--tpu 公共标志 TPU 任务名(strategy_type=tpu 时使用)
--num_gpus 公共标志 GPU 数量(mirrored/one_device 时使用)
--model_dir 公共标志 模型 checkpoint 与 summary 的输出目录
--config_file 指向 YAML/JSON 配置文件,用于覆盖参数
--params_override 行内 YAML/JSON 格式的覆盖参数,优先级最高
--training_file_pattern 训练数据路径,可替代配置文件中的同名字段
--eval_file_pattern 评估数据路径
--checkpoint_path eval_once 模式使用,指向单个 checkpoint
--enable_xla False 在 GPU 上启用 XLA
--log_steps 公共标志 每 N 步打印训练耗时统计

3.2 参数生成与覆盖顺序

main.py 的 run() 展示了参数装配顺序,这也是理解 --params_override 语法的钥匙:

params = config_factory.config_generator(FLAGS.model)   # 1. 按 --model 取默认配置

params = params_dict.override_params_dict(               # 2. 叠加 --config_file
    params, FLAGS.config_file, is_strict=True)

params = params_dict.override_params_dict(               # 3. 叠加 --params_override
    params, FLAGS.params_override, is_strict=True)

params.override({                                        # 4. 强制注入运行环境参数
    'strategy_type': FLAGS.strategy_type,
    'model_dir': FLAGS.model_dir,
    'strategy_config': executor.strategy_flags_dict(),
}, is_strict=False)

params.use_tpu = (params.strategy_type == 'tpu')        # 5. 保持 use_tpu 与策略同步

要点有三:

  • 配置工厂configs/factory.py 根据 --model 的值返回 RETINANET_CFGMASKRCNN_CFGSHAPEMASK_CFGOLNMASK_CFG。因此即使省略 --params_override 中的 type 字段,--model=mask_rcnn 也能正确建模。
  • 严格模式覆盖is_strict=True 意味着 --config_file--params_override 只能写已存在的参数键,写错字段会直接报错,这是防呆设计。
  • 非 TPU 自动降级:当 strategy_type != 'tpu' 时,入口会自动把 architecture.use_bfloat16norm_activation.use_sync_bn 强制改为 Falsemain.py L197-L205)。所以 README 的行内示例中 GPU 场景才写 use_bfloat16: Falseuse_tpu: False——写与不写都会被修正到一致状态。

3.3 基础配置模板中的默认超参

所有模型配置都继承自 configs/base_config.pyBASE_CFG,以下是与训练最相关的默认值(可被配置文件覆盖):

参数路径 默认值 说明
train.batch_size 64 全局批大小(TPU 8 芯场景的常用设定)
train.total_steps 22500 训练总步数
train.iterations_per_loop 100 每个训练循环迭代数
train.optimizer momentum 0.9 + nesterov 优化器类型与参数
train.learning_rate step 策略:初始 0.08,在 15000/20000 步衰减到 0.008/0.0008,warmup 500 步 学习率调度
train.checkpoint.path / prefix 从分类预训练权重恢复的路径与前缀
train.l2_weight_decay 1e-4 L2 正则强度
train.train_file_pattern 训练 TFRecord 文件模式(必填
eval.batch_size 8 评估批大小
eval.eval_samples 5000 一次评估最多读取的样本数
eval.min_eval_interval 180 两次评估的最小间隔(秒)
eval.type box 评估器类型,Mask 系模型会改成 box_and_mask
eval.val_json_file COCO 格式 ground truth JSON
architecture.backbone resnet 骨干网络:resnetspinenet
architecture.multilevel_features fpn 多尺度特征:fpnidentity
architecture.num_classes 91 类别数,含索引 0 的背景类
anchor.num_scales / aspect_ratios / anchor_size 3 / [1.0, 2.0, 0.5] / 4.0 锚框参数
resnet.resnet_depth 50 ResNet 深度
spinenet.model_id 49 SpineNet 规格
fpn.fpn_feat_dims 256 FPN 通道数
postprocess.score_threshold / nms_iou_threshold / max_total_size 0.05 / 0.5 / 100 推理后处理阈值

各模型配置在此之上再做差异覆盖,例如 retinanet_config.py 中 RetinaNet 的 Focal Loss 参数:focal_loss_alpha: 0.25focal_loss_gamma: 1.5huber_loss_delta: 0.1box_loss_weight: 50——这组取值正对应 README 参考文献《Focal Loss for Dense Object Detection》(Lin 等,ICCV 2017)的论文配方。

4. 在 TPU 上训练 RetinaNet

4.1 原版 ResNet-50 RetinaNet

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
RESNET_CHECKPOINT="<path to the pre-trained Resnet-50 checkpoint>"
TRAIN_FILE_PATTERN="<path to the TFRecord training data>"
EVAL_FILE_PATTERN="<path to the TFRecord validation data>"
VAL_JSON_FILE="<path to the validation annotation JSON file>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu="${TPU_NAME?}" \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --params_override="{ type: retinanet, train: { checkpoint: { path: ${RESNET_CHECKPOINT?}, prefix: resnet50/ }, train_file_pattern: ${TRAIN_FILE_PATTERN?} }, eval: { val_json_file: ${VAL_JSON_FILE?}, eval_file_pattern: ${EVAL_FILE_PATTERN?} } }"

说明:

  • 预训练 ResNet-50 检测格式 checkpoint(resnet50-2018-02-07.tar.gz)可从 cloud-tpu-checkpoints 的 GCS 桶(路径 model-garden-vision/detection/ 下)下载。
  • checkpoint.prefix: resnet50/ 用于把分类 checkpoint 中的变量名映射到检测网络中的 ResNet 子图,见 modeling/checkpoint_utils.py
  • README 特别强调:detection 目录下的 ResNet 实现与 image_classification 目录下的 ResNet 实现并不相同,两者的 checkpoint 互不兼容,只能使用检测侧专用导出的版本。

从源码看,train.checkpointtrain.frozen_variable_prefix 配合工作:base_config.py 中提供了 RESNET_FROZEN_VAR_PREFIX 正则,用于冻结 ResNet-50 的 conv1 与 conv2_x 层——注释解释了动机:低层特征(边缘等)无需为检测任务重新微调,冻结后可提升训练速度且精度略有收益。

4.2 SpineNet-49 骨干的 RetinaNet

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
TRAIN_FILE_PATTERN="<path to the TFRecord training data>"
EVAL_FILE_PATTERN="<path to the TFRecord validation data>"
VAL_JSON_FILE="<path to the validation annotation JSON file>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu="${TPU_NAME?}" \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --params_override="{ type: retinanet, architecture: {backbone: spinenet, multilevel_features: identity}, spinenet: {model_id: 49}, train_file_pattern: ${TRAIN_FILE_PATTERN?} }, eval: { val_json_file: ${VAL_JSON_FILE?}, eval_file_pattern: ${EVAL_FILE_PATTERN?} } }"

关键覆盖项为 architecture.backbone: spinenetspinenet.model_id: 49。这里的 multilevel_features: identity 值得一提:SpineNet 本身已经内置多尺度输出(P2–P5),所以用 identity.py 中的 Identity 直通模块替代 FPN 是合理的组合。这一点可以从 architecture/factory.py 印证:multilevel_features_generator 只支持 fpnidentity 两种取值,选 identity 时直接返回恒等函数。

4.3 用 YAML 配置文件训练自定义 RetinaNet

更复杂的修改建议写成 YAML 文件。创建 my_retinanet.yaml,至少包含:

# my_retinanet.yaml
type: 'retinanet'
train:
  train_file_pattern: <path to the TFRecord training data>
eval:
  eval_file_pattern: <path to the TFRecord validation data>
  val_json_file: <path to the validation annotation JSON file>

然后启动:

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu="${TPU_NAME?}" \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --config_file="my_retinanet.yaml"

注意此例中 RetinaNet 是 --model 的默认值,故可省略该标志。RetinaNet 专属可覆盖字段还有(见 retinanet_config.py):

  • retinanet_parseroutput_size: [640, 640]match_threshold/unmatched_threshold: 0.5(锚框正负样本匹配阈值)、aug_rand_hflip: Truemax_num_instances: 100 等;
  • retinanet_headnum_convs: 4num_filters: 256use_separable_conv: False
  • retinanet_loss:Focal Loss 与 Huber Loss 的四个超参。

5. 在 GPU 上训练 RetinaNet

GPU 训练与 TPU 的差异集中在分布策略:多卡用 mirrored(对应 tf.distribute.MirroredStrategy),单卡用 one_device(对应 tf.distribute.OneDeviceStrategy),并额外指定 --num_gpus

多卡示例(主机挂载 8 张 GPU):

MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=mirrored \
  --num_gpus=8 \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --config_file="my_retinanet.yaml"

单卡示例:

MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=one_device \
  --num_gpus=1 \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --config_file="my_retinanet.yaml"

README 还给出了行内配置(YAML 或 JSON 均可)的完整例子,这里保留原文以便直接改造:

python3 ~/models/official/legacy/detection/main.py \
  --model_dir=<model folder> \
  --strategy_type=one_device \
  --num_gpus=1 \
  --mode=train \
  --params_override="eval:
 eval_file_pattern: <Eval TFRecord file pattern>
 batch_size: 8
 val_json_file: <COCO format groundtruth JSON file>
predict:
 predict_batch_size: 8
architecture:
 use_bfloat16: False
train:
 total_steps: 1
 batch_size: 8
 train_file_pattern: <Eval TFRecord file pattern>
use_tpu: False
"

多主机(multi-host)训练时,入口会按副本数自动缩放批大小:main.py L112-L115 中,当 num_workers >= 2 时把 train_input_fn 的批大小除以 strategy.num_replicas_in_sync,即配置文件里的 batch_size 始终是全局批大小,框架负责切分到各主机。

6. 在 TPU 上训练 Mask R-CNN

Mask R-CNN 与 RetinaNet 走同一条参数管线,区别是必须显式传 --model=mask_rcnn,且配置里多了 RPN/Fast R-CNN/Mask 三套头与 ROI 相关参数。

6.1 原版 ResNet-50 Mask R-CNN

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
RESNET_CHECKPOINT="<path to the pre-trained Resnet-50 checkpoint>"
TRAIN_FILE_PATTERN="<path to the TFRecord training data>"
EVAL_FILE_PATTERN="<path to the TFRecord validation data>"
VAL_JSON_FILE="<path to the validation annotation JSON file>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu=${TPU_NAME} \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=mask_rcnn \
  --params_override="{train: { checkpoint: { path: ${RESNET_CHECKPOINT}, prefix: resnet50/ }, train_file_pattern: ${TRAIN_FILE_PATTERN} }, eval: { val_json_file: ${VAL_JSON_FILE}, eval_file_pattern: ${EVAL_FILE_PATTERN} } }"

同样使用该检测专用 ResNet-50 checkpoint(与分类侧不兼容的说明见第 4.1 节)。

6.2 SpineNet-49 Mask R-CNN

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
TRAIN_FILE_PATTERN="<path to the TFRecord training data>"
EVAL_FILE_PATTERN="<path to the TFRecord validation data>"
VAL_JSON_FILE="<path to the validation annotation JSON file>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu="${TPU_NAME?}" \
  --model_dir="${MODEL_DIR?}" \
  --mode=train \
  --model=mask_rcnn \
  --params_override="{architecture: {backbone: spinenet, multilevel_features: identity}, spinenet: {model_id: 49}, train_file_pattern: ${TRAIN_FILE_PATTERN?} }, eval: { val_json_file: ${VAL_JSON_FILE?}, eval_file_pattern: ${EVAL_FILE_PATTERN?} } }"

6.3 用配置文件训练自定义 Mask R-CNN

创建 my_maskrcnn.yaml,最小字段集:

# my_maskrcnn.yaml
train:
  train_file_pattern: <path to the TFRecord training data>
eval:
  eval_file_pattern: <path to the TFRecord validation data>
  val_json_file: <path to the validation annotation JSON file>
TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu=${TPU_NAME} \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=mask_rcnn \
  --config_file="my_maskrcnn.yaml"

maskrcnn_config.py 可以看到 Mask R-CNN 相对基础模板的显著差异,这些都可以按需覆盖:

  • architecturemin_level: 2max_level: 6(比 RetinaNet 的 3–7 高一层特征分辨率)、include_mask: Truemask_target_size: 28
  • maskrcnn_parser:输入 output_size: [1024, 1024]rpn_match_threshold: 0.7rpn_batch_size_per_im: 256rpn_fg_fraction: 0.5mask_crop_size: 112
  • rpn_head / frcnn_head / mrcnn_head:RPN 两卷积、Fast R-CNN 两 FC(fc_dims: 1024)、Mask 头四卷积,均 256 通道;
  • roi_proposal:训练态 rpn_pre_nms_top_k: 2000rpn_post_nms_top_k: 1000rpn_nms_threshold: 0.7;测试态 test_rpn_pre_nms_top_k: 1000 等;
  • roi_samplingnum_samples_per_image: 512fg_fraction: 0.25fg_iou_thresh: 0.5
  • eval.type: 'box_and_mask':评估时同时出 box 与 mask 指标。

模型侧这些参数由 maskrcnn_model.py 消费,各头分别由 architecture/factory.py 中的 rpn_head_generatorfast_rcnn_head_generatormask_rcnn_head_generator 实例化。

7. 在 GPU 上训练 Mask R-CNN

与 RetinaNet 的 GPU 流程完全同构,只是多带 --model=mask_rcnn

# 多卡(8 GPU)
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=mirrored \
  --num_gpus=8 \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=mask_rcnn \
  --config_file="my_maskrcnn.yaml"

# 单卡
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=one_device \
  --num_gpus=1 \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=mask_rcnn \
  --config_file="my_maskrcnn.yaml"

行内配置示例(注意 Mask R-CNN 版多了 --model=mask_rcnn,且 total_steps 示例为 1000):

python3 ~/models/official/legacy/detection/main.py \
  --model_dir=<model folder> \
  --strategy_type=one_device \
  --num_gpus=1 \
  --mode=train \
  --model=mask_rcnn \
  --params_override="eval:
 eval_file_pattern: <Eval TFRecord file pattern>
 batch_size: 8
 val_json_file: <COCO format groundtruth JSON file>
predict:
 predict_batch_size: 8
architecture:
 use_bfloat16: False
train:
 total_steps: 1000
 batch_size: 8
 train_file_pattern: <Eval TFRecord file pattern>
use_tpu: False
"

8. ShapeMask:形状先验驱动的实例分割

ShapeMask 在该模块中用于验证"形状先验(shape priors)能否降低实例分割训练成本"。它复用 ResNet-50 + FPN + 类 RetinaNet 头做检测,再叠三个专用头:形状先验头、粗掩码头、细掩码头(见 architecture/factory.py 的三个 generator)。

8.1 TPU 上训练 ResNet-50 ShapeMask

TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
RESNET_CHECKPOINT="<path to the pre-trained Resnet-50 checkpoint>"
TRAIN_FILE_PATTERN="<path to the TFRecord training data>"
EVAL_FILE_PATTERN="<path to the TFRecord validation data>"
VAL_JSON_FILE="<path to the validation annotation JSON file>"
SHAPE_PRIOR_PATH="<path to shape priors>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu=${TPU_NAME} \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=shapemask \
  --params_override="{train: { checkpoint: { path: ${RESNET_CHECKPOINT}, prefix: resnet50/ }, train_file_pattern: ${TRAIN_FILE_PATTERN} }, eval: { val_json_file: ${VAL_JSON_FILE}, eval_file_pattern: ${EVAL_FILE_PATTERN} } shapemask_head: {use_category_for_mask: true, shape_prior_path: ${SHAPE_PRIOR_PATH}} }"

形状先验文件(kmeans_class_priors_91x20x32x32.npy,91 类 × 每类 20 个 32×32 的 K-means 聚类中心)可从 cloud-tpu-checkpoints 的 GCS 桶 shapemask/ 路径下载。shapemask_head.shape_prior_path 指向它,use_category_for_mask: true 表示按类别选择对应的先验。

shapemask_config.py 看,ShapeMask 默认配置与基础模板的差异包括:train.total_steps: 45000、学习率衰减点 [30000, 40000]、冻结变量前缀 SHAPEMASK_RESNET_FROZEN_VAR_PREFIX(加载分类权重后冻结 ResNet 浅层)、数据增广 aug_scale_min/max: 0.8/1.2(相比 RetinaNet 的 1.0/1.0 更激进,因为分割任务需要更多尺度鲁棒性),以及 shapemask_lossshape_prior_loss_weight: 0.1coarse_mask_loss_weight: 1.0fine_mask_loss_weight: 1.0 的三段损失权重。

另外该配置定义了硬性约束shapemask_config.py L91-L95):

shapemask_head.mask_crop_size == shapemask_parser.mask_crop_size
shapemask_head.upsample_factor == shapemask_parser.upsample_factor
shapemask_parser.outer_box_scale == architecture.outer_box_scale

即 head 与 parser 的 mask_crop_size(32)、upsample_factor(4)以及 outer_box_scale(1.25)必须保持一致,否则参数校验会失败。这是覆盖自定义配置时最容易踩的坑。

8.2 用配置文件训练 ShapeMask

my_shapemask.yaml 示例(README 保留了完整的字段注释):

# my_shapemask.yaml
train:
  train_file_pattern: <path to the TFRecord training data>
  total_steps: <total steps to train>
  batch_size: <training batch size>
eval:
  eval_file_pattern: <path to the TFRecord validation data>
  val_json_file: <path to the validation annotation JSON file>
  batch_size: <evaluation batch size>
shapemask_head:
  shape_prior_path: <path to shape priors>
TPU_NAME="<your GCP TPU name>"
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=tpu \
  --tpu=${TPU_NAME} \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=shapemask \
  --config_file="my_shapemask.yaml"

8.3 GPU 上的 ShapeMask

多卡与单卡命令与前面一致,仅 --model=shapemask

# 多卡
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=mirrored \
  --num_gpus=8 \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=shapemask \
  --config_file="my_shapemask.yaml"

# 单卡
MODEL_DIR="<path to the directory to store model files>"
python3 ~/models/official/legacy/detection/main.py \
  --strategy_type=one_device \
  --num_gpus=1 \
  --model_dir=${MODEL_DIR} \
  --mode=train \
  --model=shapemask \
  --config_file="my_shapemask.yaml"

行内配置示例:

python3 ~/models/official/legacy/detection/main.py \
  --model_dir=<model folder> \
  --strategy_type=one_device \
  --num_gpus=1 \
  --mode=train \
  --model=shapemask \
  --params_override="eval:
 eval_file_pattern: <Eval TFRecord file pattern>
 batch_size: 8
 val_json_file: <COCO format groundtruth JSON file>
train:
 total_steps: 1000
 batch_size: 8
 train_file_pattern: <Eval TFRecord file pattern>
use_tpu: False
"

9. 训练后的评估

训练完成后切换 --mode=eval 复用同一入口。README 给出的 TPU 评估命令(以 ShapeMask 为例):

python3 /usr/share/models/official/legacy/detection/main.py \
   --strategy_type=tpu \
   --tpu=${TPU_NAME} \
   --model_dir=${MODEL_DIR} \
   --mode=eval \
   --model=shapemask \
   --params_override="{eval: { val_json_file: ${VAL_JSON_FILE}, eval_file_pattern: ${EVAL_FILE_PATTERN}, eval_samples: 5000 } }"
  • MODEL_DIR 必须指向训练时保存的 ShapeMask 模型路径(eval 模式会从 model_dir 读取最新 checkpoint 周期性评估,见 main.py L148-L155evaluate_from_model_dir 调用)。
  • GPU 上评估把 strategy_type 换成 mirrored(并指定 num_gpus)即可。
  • eval_samples: 5000 即基础配置 eval.eval_samples 的默认值,控制单次评估读取的样本上限。
  • val_json_file 对 COCO 数据集是必需的(COCO 格式的 ground truth JSON 可在 COCO 官网获取);对自数据集则可不提供——README 指出自数据集的 ground truth 可以直接编码在 TFRecord 文件内。

此外入口还支持 --mode=eval_once --checkpoint_path=<path> 对单个 checkpoint 一次性评估(main.py L156-L167),便于在多个实验目录间对比。

10. 数据输入与模型构建的源码印证

把 README 的命令落到代码层,调用链是:命令行 → 配置工厂 → 模型工厂 → 架构工厂 → 执行器

10.1 数据读取

train_file_pattern / eval_file_pattern 最终由 dataloader/input_reader.pyInputFn 消费:

  1. tf.data.Dataset.list_files 展开文件模式,训练时打乱文件顺序;
  2. 多输入管道场景下按 ctx.num_input_pipelines 分片(train.input_sharding / eval.input_sharding 控制);
  3. interleavecycle_length=32 并发读取 TFRecord(tf.data.TFRecordDataset);
  4. 训练集额外 repeat() + shuffle(1000);评估集按 eval_samples(即 num_examplestake() 截断;
  5. map(parser_fn) 调用模型专属 parser 完成解码与增广,最后 batch(batch_size, drop_remainder=True)

parser 由 dataloader/factory.pyarchitecture.parser 字段选择(RetinaNet 用 retinanet_parser,Mask R-CNN 用 maskrcnn_parser,ShapeMask 用 shapemask_parser),TFRecord 字段解码在 dataloader/tf_example_decoder.py。这解释了为什么配置文件必须提供 train_file_pattern——它是唯一的数据入口(train_dataset_type 固定为 tfrecord)。

10.2 模型前向与损失

以 RetinaNet 为例,retinanet_model.py 展示了配置参数如何变成网络:

# 构造函数:backbone / FPN / head 全部来自架构工厂
self._backbone_fn = factory.backbone_generator(params)
self._fpn_fn = factory.multilevel_features_generator(params)
self._head_fn = factory.retinanet_head_generator(params)

# 前向:输入 -> 骨干 -> 多尺度特征 -> 分类/回归头(按 min_level~max_level 分层输出)
backbone_features = self._backbone_fn(inputs, is_training=...)
fpn_features = self._fpn_fn(backbone_features, is_training=...)
cls_outputs, box_outputs = self._head_fn(fpn_features, is_training=...)

# 损失:Focal 分类损失 + box_loss_weight × Huber 框损失 + L2 正则
model_loss = cls_loss + self._box_loss_weight * box_loss
total_loss = model_loss + l2_regularization_loss

其中输入层的 dtype 由 use_bfloat16 决定(tf.bfloat16 if self._use_bfloat16 else tf.float32),bfloat16 路径下头部输出会先转回 float32 再算损失——这就是 TPU 命令默认 use_bfloat16: True 而 GPU 命令显式写 False 的底层原因。anchors_per_location 则直接等于 anchor.num_scales × len(anchor.aspect_ratios)(默认 3×3=9),修改锚框参数时两处会同步生效。

10.3 训练执行

run() 构造好 train_input_fn / eval_input_fn 后交给 executor/detection_executor.pyDetectionDistributedExecutor,它封装了 Keras 分布式训练循环、checkpoint 保存与 min_eval_interval 触发的周期性评估,total_steps 到达即停止。

11. 实操注意事项汇总

结合 README 与源码,以下是最容易出错的点:

  1. checkpoint 兼容性:detection 侧 ResNet 与 image_classification 侧 ResNet 实现不同,分类预训练权重必须走 train.checkpoint: { path: ..., prefix: resnet50/ } 的映射加载,且只能用检测侧导出的 checkpoint。
  2. 参数键必须真实存在--config_file--params_override 都是严格模式覆盖,拼错字段名会直接抛错而非静默忽略。
  3. ShapeMask 的等值约束:head 与 parser 之间的 mask_crop_sizeupsample_factorouter_box_scale 必须保持一致,否则 params.validate() 失败。
  4. GPU 上别指望 bfloat16:入口会强制关闭 use_bfloat16use_sync_bn,显式写它们只是让意图可见。
  5. num_classes 含背景architecture.num_classes: 91 是 COCO 的 80 个前景类 + 1 个背景类(索引 0)+ 其他约定类别的结果,换数据集时注意调整。
  6. 评估数据 vs 训练数据的 sharding:默认 train.input_sharding: Falseeval.input_sharding: True,即训练时全副本共享文件列表、评估时分片读取以加速。
  7. 弃用提示:如第 1 节所述,官方计划用 vision/beta/ 的新实现取代本模块,新工程建议先评估官方 vision 目录下的检测方案(仓库中 official/visionofficial/projects 下有若干后继检测项目),本模块的价值在于其参数体系、分布式训练与评估流程的完整参考。

12. 参考

  1. Focal Loss for Dense Object Detection. Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He, Piotr Dollár. ICCV 2017(RetinaNet 的 Focal Loss 理论依据,README 原文引用的参考文献)。

延伸阅读建议从 official/legacy/detection/README.md 出发,配合 configs/base_config.pymodeling/factory.pydataloader/input_reader.py 通读一遍,即可完整掌握该模块"配置驱动 + 工厂构建 + 分布式执行"的设计骨架。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384