YOLOF 全称是 You Only Look One-level Feature, 其通过详细的实验指出特征金字塔 FPN 模块的成功在于其对目标优化问题的分治解决方案,而不是多尺度特征融合。针对该结论,设计了一个简洁优雅的无需复杂 FPN 的网络结构,仅仅依靠单尺度特征即可取得相匹配的效果,并且具备极快的推理速度。
论文
Chen Q , Wang Y , Yang T , et al. You Only Look One-level Feature[J]. 2021.
YOLOF的整体网络架构如下所示:
链接
数据集可参考文献.
MSCOCO2017
- 硬件(Ascend)
- 架构
- 想要获取更多信息,请检查以下资源:
.
└─yolof
├─README.md
├─ascend310_infer # 实现310推理源代码
├─scripts
├─run_single_train.sh # 使用Ascend环境单卡训练
├─run_distribute_train_ascend.sh # 使用Ascend环境八卡并行训练
├─run_distribute_train_gpu.sh # 使用GPU环境八卡并行训练
├─run_single_train_gpu.sh # 使用GPU环境单卡训练
├─run_infer_310.sh # Ascend推理shell脚本
├─run_eval.sh # 使用Ascend环境运行推理脚本
├─run_eval_gpu.sh # 使用GPU环境运行推理脚本
├─src
├─dataset.py # 数据预处理
├─init_params.py # 参数初始化
├─lr_generator.py # 学习率生成函数
├─coco_eval # coco数据集评估
├─utils.py # 回归框解码
├──model_utils
├──config.py # 参数生成
├──device_adapter.py # 设备相关信息
├──local_adapter.py # 设备相关信息
├──moxing_adapter.py # 装饰器(主要用于ModelArts数据拷贝)
├──YOLOF
├──anchor_generator.py # 生成锚框
├──box_utils.py # 计算IOU
├──dilated_encoder.py # 模型neck部分网络结构
├──loss.py # 模型损失计算
├──resnet.py # 模型骨干网部分网络结构
├──uniform_matcher.py # 模型正负样本匹配策略
├──uniform_matcher.py # 模型正负样本匹配策略
├──utils.py # 模型参数优化策略
├──yolof.py # 网络模型定义
├──yolof_head.py # 模型预测头结构
├─train.py # 网络训练脚本
├─export.py # 导出 AIR,MINDIR模型的脚本
├─postprogress.py # 310推理后处理脚本
└─eval.py # 网络推理脚本
└─create_data.py # 构建Mindrecord数据集脚本
└─default_config.yaml # 参数配置
在脚本中使用到的主要参数是:
img_width: 1333
img_height: 800
feature_shapes: [[25, 42]]
feature_max: 42
# LR
lr_init: 0.0001
lr_end_rate: 0.0001
warmup_epochs: 1
lr: 0.12
# train config
epoch_size: 12
run_eval: False
momentum: 0.9
weight_decay: 0.0001
distribute: True
device_num: 8
loss_scale: 1024
workers: 8
batch_size: 8
pre_trained: ""
filter_weight: False
pre_trained_epoch_size: 0
save_checkpoint_path: "/cache/train"
save_checkpoint_epochs: 1
keep_checkpoint_max: 10
# test config
test_batch_size: 1
min_score: 0.05
nms_thershold: 0.6
max_boxes: 100
nms_pre: 1000
checkpoint_path: ""
# bbox_assign_sampler
num_bboxes: 5250
# resnet
freeze_layer: True
backbone: 'resnet_v1.5_50'
resnet_block: [3, 4, 6, 3]
resnet_in_channels: [64, 256, 512, 1024]
resnet_out_channels: [256, 512, 1024, 2048]
# neck
extras_out_channels: [512]
in_channels: 2048
out_channels: 512
block_mid_channels: 128
num_residual_blocks: 4
# head
num_cls_convs: 2
num_reg_convs: 4
num_base_priors: 5
#anchor
strides: [32]
scales: [1, 2, 4, 8, 16]
ratios: [1.0]
target_means: [.0, .0, .0, .0]
target_stds: [1.0, 1.0, 1.0, 1.0]
add_ctr_clamp: True
ctr_clamp: 32
clip_border: True
# mindrecord
mindrecord_dir: "/cache/data"
prefix: "yolof.mindrecord"
is_training: True
# data_aug
keep_ratio: True
num_gts: 128
flip_ratio: 0.5
shift_ratio: 0.5
max_shift_px: 32
filter_thr_px: 1
# coco dataset
dataset: coco
num_classes: 80
coco_root: "/cache/data"
val_data_type: "val2017"
train_data_type: "train2017"
instance_set: "annotations/instances_{}.json"
coco_classes: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
'train', 'truck', 'boat', 'traffic light', 'fire hydrant',
'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog',
'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra',
'giraffe', 'backpack', 'umbrella', 'handbag', 'tie',
'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
'kite', 'baseball bat', 'baseball glove', 'skateboard',
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup',
'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink',
'refrigerator', 'book', 'clock', 'vase', 'scissors',
'teddy bear', 'hair drier', 'toothbrush']
# other dataset
image_dir: "/disk2/dataset/"
anno_path: "/disk2/dataset/anno"
# matcher
match_times: 4
neg_ignore_thresh: 0.7
pos_ignore_thresh: 0.15
# loss
gamma: 2.0
alpha: 0.25
on_value: 1
off_value: 0
reduction: "sum"
用法
使用shell脚本进行训练。shell脚本的用法如下:
# 八卡并行训练示例:
创建 RANK_TABLE_FILE
bash scripts/run_distribute_train.sh DEVICE_NUM RANK_TABLE_FILE CONFIG_PATH MINDRECORD_DIR PRE_TRAINED(optional) PRE_TRAINED_EPOCH_SIZE(optional)
# 单卡训练示例:
bash scripts/run_single_train.sh DEVICE_ID MINDRECORD_DIR CONFIG_PATH PRE_TRAINED(optional) PRE_TRAINED_EPOCH_SIZE(optional)
注意:
RANK_TABLE_FILE相关参考资料见链接, 获取device_ip方法详见链接.
运行
数据集结构
└─cocodataset
├─train2017
├─val2017
├─annotations
训练前,先创建MindRecord文件,以COCO数据集为例,yaml文件配置好coco数据集路径和mindrecord存储路径
# your cocodataset dir
coco_root: /home/DataSet/cocodataset/
# mindrecord dataset dir
mindrecord_dr: /home/DataSet/MindRecord_COCO
# 生成训练数据集
python create_data.py --prefix yolof.mindrecord --is_training True --config_path
(例如:python create_data.py --prefix yolof.mindrecord --is_training True --config_path /home/yolof/default_config.yaml)
# 生成测试数据集
python create_data.py --prefix yolof_eval.mindrecord --is_training False --config_path
(例如:python create_data.py --prefix yolof_eval.mindrecord --is_training False --config_path /home/yolof/default_config.yaml)
Ascend:
# 八卡并行训练示例(在yolof目录下运行):
bash scripts/run_distribute_train.sh [DEVICE_NUM] [RANK_TABLE_FILE] [MINDRECORD_DIR] [CONFIG_PATH] [PRE_TRAINED(optional)] [PRE_TRAINED_EPOCH_SIZE(optional)]
# example: bash scripts/run_distribute_train.sh 8 ~/hccl_8p.json /home/DataSet/MindRecord_COCO/ /home/retinanet/config/default_config.yaml
# 单卡训练示例(在yolof目录下运行):
bash scripts/run_single_train.sh [DEVICE_ID] [MINDRECORD_DIR] [CONFIG_PATH]
# example: bash scripts/run_single_train.sh 0 /home/DataSet/MindRecord_COCO/ /home/retinanet/config/default_config.yaml
GPU:
# 八卡并行训练示例(在retinanet目录下运行):
bash scripts/run_distribute_train_gpu.sh [DEVICE_NUM] [MINDRECORD_DIR] [CONFIG_PATH] [VISIABLE_DEVICES(0,1,2,3,4,5,6,7)] [PRE_TRAINED(optional)] [PRE_TRAINED_EPOCH_SIZE(optional)]
# example: bash scripts/run_distribute_train_gpu.sh 8 /home/DataSet/MindRecord_COCO/ /home/retinanet/config/default_config_gpu.yaml 0,1,2,3,4,5,6,7
结果
训练结果将存储在示例路径中。checkpoint将存储在 ./ckpt
路径下,训练日志将被记录到 ./log.txt
中,训练日志部分示例如下:
epoch: 2 step: 458, loss is 120.56251
lr:[0.000003]
Epoch time: 164034.415, per step time: 358.154
epoch: 3 step: 458, loss is 11.834166
lr:[0.000028]
Epoch time: 164292.012, per step time: 358.716
epoch: 4 step: 458, loss is 10.49008
lr:[0.000046]
Epoch time: 164822.921, per step time: 359.875
epoch: 5 step: 458, loss is 12.134182
lr:[0.000064]
Epoch time: 164531.610, per step time: 359.239
- 如果要在modelarts上进行模型的训练,可以参考modelarts的官方指导文档 开始进行模型的训练和推理,具体操作如下:
# 在ModelArts上使用分布式训练示例:
# 数据集存放方式
# ├── MindRecord_COCO # dir
# ├── annotations # annotations dir
# ├── instances_val2017.json # annotations file
# ├── checkpoint # checkpoint dir
# ├── pred_train # predtrained dir
# ├── MindRecord_COCO.zip # train mindrecord file and eval mindrecord file
# (1) 选择a(修改yaml文件参数)或者b(ModelArts创建训练作业修改参数)其中一种方式。
# a. 设置 "enable_modelarts=True"
# 设置 "distribute=True"
# 设置 "keep_checkpoint_max=5"
# 设置 "save_checkpoint_path=/cache/train/checkpoint"
# 设置 "mindrecord_dir=/cache/data/MindRecord_COCO"
# 设置 "epoch_size=550"
# 设置 "modelarts_dataset_unzip_name=MindRecord_COCO"
# 设置 "pre_trained=/cache/data/train/train_predtrained/pred file name" 如果没有预训练权重 pre_trained=""
# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。
# 在modelarts的界面上设置方法a所需要的参数
# 注意:路径参数不需要加引号
# (2)设置网络配置文件的路径 "_config_path=/The path of config in default_config.yaml/"
# (3) 在modelarts的界面上设置代码的路径 "/path/retinanet"。
# (4) 在modelarts的界面上设置模型的启动文件 "train.py" 。
# (5) 在modelarts的界面上设置模型的数据路径 ".../MindRecord_COCO"(选择MindRecord_COCO文件夹路径) ,
# 模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。
# (6) 开始模型的训练。
# 在modelarts上使用模型推理的示例
# (1) 把训练好的模型地方到桶的对应位置。
# (2) 选择a或者b其中一种方式。
# a.设置 "enable_modelarts=True"
# 设置 "mindrecord_dir=/cache/data/MindRecord_COCO"
# 设置 "checkpoint_path=/cache/data/checkpoint/checkpoint file name"
# 设置 "instance_set=/cache/data/MindRecord_COCO/annotations/instances_{}.json"
# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。
# 在modelarts的界面上设置方法a所需要的参数
# 注意:路径参数不需要加引号
# (3) 设置网络配置文件的路径 "_config_path=/The path of config in default_config.yaml/"
# (4) 在modelarts的界面上设置代码的路径 "/path/retinanet"。
# (5) 在modelarts的界面上设置模型的启动文件 "eval.py" 。
# (6) 在modelarts的界面上设置模型的数据路径 "../MindRecord_COCO"(选择MindRecord_COCO文件夹路径) ,
# 模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。
# (7) 开始模型的推理。
用法
使用shell脚本进行评估。shell脚本的用法如下:
Ascend:
bash scripts/run_eval.sh [DEVICE_ID] [DATASET] [MINDRECORD_DIR] [CHECKPOINT_PATH] [ANN_FILE PATH] [CONFIG_PATH]
# example: bash scripts/run_eval.sh 0 coco /home/DataSet/MindRecord_COCO/ /home/model/retinanet/ckpt/retinanet_500-458.ckpt /home/DataSet/cocodataset/annotations/instances_{}.json /home/retinanet/config/default_config.yaml
GPU:
bash scripts/run_eval_gpu.sh [DEVICE_ID] [DATASET] [MINDRECORD_DIR] [CHECKPOINT_PATH] [ANN_FILE PATH] [CONFIG_PATH]
# example: bash scripts/run_eval_gpu.sh 0 coco /home/DataSet/MindRecord_COCO/ /home/model/retinanet/ckpt/retinanet_500-458.ckpt /home/DataSet/cocodataset/annotations/instances_{}.json /home/retinanet/config/default_config_gpu.yaml
checkpoint 可以在训练过程中产生.
结果
计算结果将存储在示例路径中,您可以在 eval.log
查看.
Ascend:
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.347
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.503
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.385
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.134
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.366
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.501
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.302
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.412
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.414
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.152
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.434
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.598
========================================
mAP: 0.34747137754625645
GPU:
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.349
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.504
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.385
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.136
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.366
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.506
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.302
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.414
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.415
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.156
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.434
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.608
========================================
mAP: 0.34852168035724435
用法
导出模型前要修改config.py文件中的checkpoint_path配置项,值为checkpoint的路径。
python export.py --file_name [RUN_PLATFORM] --file_format[EXPORT_FORMAT] --checkpoint_path [CHECKPOINT PATH]
EXPORT_FORMAT
可选 ["AIR", "MINDIR"]
运行
python export.py --file_name retinanet --file_format MINDIR --checkpoint_path /cache/checkpoint/retinanet_550-458.ckpt
在ModelArts上导出MindIR示例
# (1) 选择a(修改yaml文件参数)或者b(ModelArts创建训练作业修改参数)其中一种方式。
# a. 设置 "enable_modelarts=True"
# 设置 "file_name=retinanet"
# 设置 "file_format=MINDIR"
# 设置 "checkpoint_path=/cache/data/checkpoint/checkpoint file name"
# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。
# 在modelarts的界面上设置方法a所需要的参数
# 注意:路径参数不需要加引号
# (2)设置网络配置文件的路径 "_config_path=/The path of config in default_config.yaml/"
# (3) 在modelarts的界面上设置代码的路径 "/path/retinanet"。
# (4) 在modelarts的界面上设置模型的启动文件 "export.py" 。
# (5) 在modelarts的界面上设置模型的数据路径 ".../MindRecord_COCO"(选择MindRecord_COCO文件夹路径) ,
# MindIR的输出路径"Output file path" 和模型的日志路径 "Job log path" 。
用法
在推理之前需要在昇腾910环境上完成模型的导出。推理时要将iscrowd为true的图片排除掉。在ascend310_infer目录下保存了去排除后的图片id。
还需要修改config.py文件中的coco_root、val_data_type、instances_set配置项,值分别取coco数据集的目录,推理所用数据集的目录名称,推理完成后计算精度用的annotation文件,instances_set是用val_data_type拼接起来的,要保证文件正确并且存在。
# Ascend310 inference
bash run_infer_310.sh [MINDIR_PATH] [DATA_PATH] [ANN_FILE] [DEVICE_ID]
运行
bash run_infer_310.sh ./retinanet.mindir ./dataset/coco2017/val2017 ./image_id.txt 0
结果
推理的结果保存在当前目录下,在acc.log日志文件中可以找到类似以下的结果。
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.350
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.509
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.385
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.139
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.368
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.509
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.303
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.413
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.415
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.155
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.435
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.608
========================================
mAP: 0.3499478734634595
训练性能
参数 |
Ascend |
GPU |
模型名称 |
Retinanet |
Retinanet |
运行环境 |
Ascend 910;CPU 2.6GHz,192cores;Memory 755G;系统 Euler2.8 |
Rtx3090;Memory 512G |
上传时间 |
10/01/2021 |
17/02/2022 |
MindSpore 版本 |
1.2.0 |
1.5.0 |
数据集 |
123287 张图片 |
123287 张图片 |
Batch_size |
32 |
32 |
训练参数 |
src/config.py |
config/default_config_gpu.yaml |
优化器 |
Momentum |
Momentum |
损失函数 |
Focal loss |
Focal loss |
最终损失 |
0.582 |
0.57 |
精确度 (8p) |
mAP[0.3475] |
mAP[0.3499] |
训练总时间 (8p) |
23h16m54s |
51h39m6s |
脚本 |
链接 |
链接 |
推理性能
参数 |
Ascend |
GPU |
模型名称 |
Retinanet |
Retinanet |
运行环境 |
Ascend 910;CPU 2.6GHz,192cores;Memory 755G;系统 Euler2.8 |
Rtx3090;Memory 512G |
上传时间 |
10/01/2021 |
17/02/2022 |
MindSpore 版本 |
1.2.0 |
1.5.0 |
数据集 |
5k 张图片 |
5k 张图片 |
Batch_size |
32 |
32 |
精确度 |
mAP[0.3475] |
mAP[0.3499] |
总时间 |
10 mins and 50 seconds |
13 mins and 40 seconds |
在 dataset.py
脚本中, 我们在 create_dataset
函数中设置了随机种子. 我们在 train.py
脚本中也设置了随机种子.
请核对官方 主页.