话不多说直接上论文标题和代码:
论文题目:FCOS: Fully Convolutional One-Stage Object Detection
论文链接:https://arxiv.org/abs/1904.01355.
代码链接:https://github.com/tianzhi0549/FCOS
我自己详细注释的代码链接:https://github.com/StiphyJay/FCOS_annotation_in_detail
论文核心思想:
该文章基于FCN实现了anchor-free的物体检测任务,并且方式更加简介,此外引入了中心度(centerness)的概念,可以有效降低一部分低质量的检测框的权重,实现更高精度的检测.
文章摘要:
本文提出一种基于像素级预测一阶全卷积目标检测(FCOS)来解决目标检测问题,类似于语音分割。目前大多数先进的目标检测模型,例如RetinaNet、SSD、YOLOv3、Faster R-CNN都依赖于预先定义的锚框。相比之下,本文提出的FCOS是anchor box free,而且也是proposal free,就是不依赖预先定义的锚框或者提议区域。通过去除预先定义的锚框,FCOS完全的避免了关于锚框的复杂运算,例如训练过程中计算重叠度,而且节省了训练过程中的内存占用。更重要的是,本文避免了和锚框有关且对最终检测结果非常敏感的所有超参数。由于后处理只采用非极大值抑制(NMS),所以本文提出的FCOS比以往基于锚框的一阶检测器具有更加简单的优点。
anchor-based方法
anchor-based的方法首先在Faster-RCNN里面被提出和应用,具体的内容我会在专栏得其他博客进行讲解。
anchor-based方法的缺点
1. 检测器的性能对于锚框的尺寸,长款比例以及数量非常敏感,因此锚框相关的超参数都需要非常仔细的调节。
2. 即使在小心的设计之后,因为锚框的尺寸和长宽比是固定的,检测器在处理形变较大的候选对象时比较困难,尤其是对于小目标。预先定义的锚框还限制了检测器的泛化能力,它们需要针对不同对象大小或长宽比进行设计。
3. 为了提高召回率,anchor-based检测器需要去在输入图像上稠密的放置anchor boxes,而大部分anchor boxes在训练期间被标记为负样本,造成了政府样本的不平衡.
4. 采用anchor boxes会引入和真值边框计算交并比(IOU),引入大量的计算,增加了计算量和内存占用.
FCOS方法的优点
1.FCOS的检测方法与许多其他基于FCN的任务(比如语义分割)是一样的,可以使得它更容易重用这些人物的思想。
2.检测不需要proposal和anchor,大大减少了设计参数的数量。而设计参数通常需要启发式调优,并且涉及到许多技巧,以便获得好的性能。 因此,我们的新检测框架使得检测器,特别是其训练,更加简单。
3. 通过消除anchor,检测器可以完全避免于锚框相关的复杂计算(例如锚框和真值框之间的IOU计算和匹配),可以更快的训练和测试,并且占用更少的内存。
4. FCOS在所有one-stage方法中实现了sota的性能,并且FCOS可以作为two-stage检测器的区域建议网络(RPN),实现优于基于锚点的RPN算法的性能。因此,锚框对于物件检测是否必要还需要重新思考。
5. FCOS还可以在轻微的修改后立即扩展到其他的视觉任务中,包括实例分割和关键点检测。
相关工作
基于锚框(two-stage)的检测器:Fast-RCNN, Faster-RCNN,SSD, YOLOv2。
无锚框(one-stage)的检测器:YOVOv1,CornerNet.
算法实现:
该方法一共有三部分组成,一个基础的特征提取网络(backbone),一个特征金字塔网络,一个head部分的得分与回归分支,来生成边界框和类别信息。
在此我们以一张800*1024大小的图片为例,介绍经过特征提取和特征金字塔之后每一层的特征维度,以及他们最后生成预测信息的特征维度。并介绍监督网络训练的真值是如何生成的。
代码解析:
github上面给出的训练模型的命令行指令如下:
python -m torch.distributed.launch \
--nproc_per_node=8 \
--master_port=$((RANDOM + 10000)) \
tools/train_net.py \
--config-file configs/fcos/fcos_imprv_R_50_FPN_1x.yaml \
DATALOADER.NUM_WORKERS 2 \
OUTPUT_DIR training_dir/fcos_imprv_R_50_FPN_1x
运行时首先进入到FCOS文件的目录下,再运行上述命令行.
运行后进入到tools/train_net.py文件下,文件中main函数代码如下:
# 解析命令行参数,例如--config-file
parser = argparse.ArgumentParser(description="PyTorch Object Detection Training")
parser.add_argument(
"--config-file", #配置文件
default="",
metavar="FILE",
help="path to config file",
type=str,
)
#此参数是通过torch.distributed.launch传递过来的,我们设置位置参数来接受
# local_rank代表当前程序进程使用的GPU标号
parser.add_argument("--local_rank", type=int, default=0)
parser.add_argument(
"--skip-test",
dest="skip_test",
help="Do not test the final model",
action="store_true",
)
parser.add_argument(
"opts",
help="Modify config options using the command-line",
default=None,
nargs=argparse.REMAINDER, #所有剩余的命令行参数都被收集到一个列表中
)
args = parser.parse_args()
#判断机器上gpu的数量,大于1时自动使用分布式训练
#world_size是由torch.distributed.launch.py产生
# 具体数值为 nproc_per_node*node(node就是主机数)
num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 #判断当前系统环境变量中是否有"WORLD_SIZE" 如果没有num_gpus=1
args.distributed = num_gpus > 1 #False
if args.distributed: #False
torch.cuda.set_device(args.local_rank)
torch.distributed.init_process_group\
(
backend="nccl", init_method="env://"
)
synchronize()
#yacs的具体用法 可以参考印象笔记
#参数默认在fcos_core/config_defaults.py中 其余参数由config_file opts覆盖
cfg.merge_from_file(args.config_file) #从yaml文件中读取参数 即configs/fcos/fcos_R_50_FPN_1x.yaml
cfg.merge_from_list(args.opts) #也可以从命令行进行参数重写
cfg.freeze() #冻结参数 防止不小心被更改 cfg被传入train()
output_dir = cfg.OUTPUT_DIR #输出模型路径 存放一些日志信息
if output_dir:
mkdi