RoI Align
解决RoI Pooling中两次量化造成的区域不匹配问题。
RoI Pooling的问题:RoI Pooling用来使生成的候选框region proposal映射产生固定大小的feature map,共有三步操作,
- 根据输入image,将ROI映射到feature map对应位置
- 将映射后的区域划分为相同大小的sections(sections数量与输出的维度相同)
- 对每个sections进行max pooling操作
这一操作存在两次量化(取整操作)的过程:
- 将候选框边界量化为整数点坐标值
- 将量化后的边界区域平均分割成 k × k k\times k k×k个单元,对每一个单元的边界进行量化
两次量化后,被舍去的小数部分对应到原图里就是偏差,对于大目标偏差不明显,但是对于小目标偏差的影响就比较大。
RoI Align的解决方法:
不进行量化,对浮点数向上取整,把整数框都作为范围(引入背景噪声),然后通过双线性插值来解决获取像素值。
- 遍历每一个候选区域,保持浮点数边界不做量化
- 将候选区域分割成 k × k k\times k k×k个单元,每个单元的边界也不做量化
- 在每个单元中计算固定四个坐标位置,用双线性插值的方法计算出这四个位置的值,然后进行最大池化操作
和RoI Pooling对比,解决了区域不匹配(mis-alignment)问题。
参考:
【ROI-Align 原理理解】
【一文读懂 RoIPooling、RoIAlign 和 RoIWarp】
SE模块
SE模块简单有效,它的核心是:
Sequeeze 对C×H×W 进行global average pooling,得到 1×1×C 大小的特征图,这个特征图可以理解为具有全局感受野。
Excitation :使用一个全连接神经网络,对Sequeeze之后的结果做一个非线性变换。
特征重标定:使用Excitation 得到的结果作为权重,乘到输入特征上。
SE模块为什么有效:提取channel级的全局特征,学习各个channel间的关系,提升了模型对channel特征的敏感性
mmdetection的使用
先说一下踩到的坑:
- 不要在config文件夹里改东西,新建一个文件夹,把要改的网络复制过去,然后再修改
- 对于自制数据集,设置好路径后,直接把路径和处理数据集的文件加到新改的网络里
以我搭建的为例子:
我要用faster_rcnn_r50_fpn_giou_1x_coco.py在自制数据集上训练:
首先把新建一个文件夹cloth,把faster_rcnn_r50_fpn_giou_1x_coco.py和其继承的faster_rcnn_r50_fpn_1x_coco.py都复制过去
faster_rcnn_r50_fpn_giou_1x_coco.py的内容:
_base_ = './faster_rcnn_r50_fpn_1x_coco.py'
model = dict(
roi_head=dict(
bbox_head=dict(
reg_decoded_bbox=True,
loss_bbox=dict(type='GIoULoss', loss_weight=10.0))))
对其进行修改,要严格按照原始模型配置的模式(从configs\ _base_\models里的faster_rcnn_r50_fpn.py复制配置内容并修改),num_classes需要改为20.
_base_ = './faster_rcnn_r50_fpn_1x_coco.py'
model = dict(
roi_head=dict(
bbox_head=dict(
type='Shared2FCBBoxHead',
in_channels=256,
fc_out_channels=1024,
roi_feat_size=7,
num_classes=20,
reg_decoded_bbox=True,
bbox_coder=dict(
type='DeltaXYWHBBoxCoder',
target_means=[0., 0., 0., 0.],
target_stds=[0.1, 0.1, 0.2, 0.2]),
reg_class_agnostic=False,
loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
loss_bbox=dict(type='GIoULoss', loss_weight=10.0))))
classes = ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
'11', '12', '13', '14', '15', '16', '17', '18', '19', '20')
把configs\_base_\datasets\coco_detection.py里的内容复制过来,修改data_root,ann_file,img_prefix为自己的路径,添加一个有20个类的class元组
dataset_type = 'CocoDataset'
data_root = 'data/r1/coco/'
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True, with_mask=True),
dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1333, 800),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
data = dict(
samples_per_gpu=2,
workers_per_gpu=2,
train=dict(
type=dataset_type,
ann_file=data_root + 'instance_train_cloth.json',
img_prefix='data/r1/defect_Images', #defect_image
pipeline=train_pipeline,
classes=(
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20')
),
val=dict(
type=dataset_type,
ann_file=data_root + 'instance_val_cloth.json',
img_prefix='data/r1/defect_Images',
pipeline=test_pipeline,
classes=('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20')
),
test=dict(
type=dataset_type,
ann_file=data_root + 'instance_val_cloth.json',
img_prefix='data/r1/defect_Images',
pipeline=test_pipeline),
classes=('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20')
)
然后python tools/train.py configs/cloth/faster_rcnn_r50_fpn_giou_1x_coco.py
,可以成功进行训练。