如有错误,恳请指出。
多尺度训练对全卷积网络有效,一般设置几种不同尺度的图片,训练时每隔一定iterations随机选取一种尺度训练。这样训练出来的模型鲁棒性强,其可以接受任意大小的图片作为输入,使用尺度小的图片测试速度会快些,但准确度低,用尺度大的图片测试速度慢,但是准确度高。
训练时,预先定义几个固定的尺度,每个epoch随机选择一个尺度进行训练(实际中还是单个尺度的训练)。
YOLOv3-SPP代码:
def train_one_epoch(model, optimizer, data_loader, device, epoch,
print_freq, accumulate, img_size,
grid_min, grid_max, gs,
multi_scale=False, warmup=False, scaler=None):
...
# Multi-Scale
if multi_scale:
# accumulate=16 batch_size=4
# 每训练accumulate个batch(batch_size*accumulate张图片),就随机修改一次输入图片大小
# 由于label已转为相对坐标,故缩放图片不影响label的值
if ni % accumulate == 0: # ni=batch总个数
# 在给定最大最小输入尺寸范围内随机选取一个size(size为32的整数倍)
img_size = random.randrange(grid_min, grid_max + 1) * gs # img_size = 320~736
sf = img_size / max(imgs.shape[2:]) # scale factor
# 如果图片最大边长不等于img_size, 则缩放一个batch图片,并将长和宽调整到32的整数倍
if sf != 1:
# gs: (pixels) grid size
ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to 32-multiple)
# 核心代码: 对图像进行双线性插值来缩放
imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False)
...
pred = model(imgs)
def train(hyp):
...
# 图像要设置成32的倍数
gs = 32 # (pixels) grid size
assert math.fmod(imgsz_test, gs) == 0, "--img-size %g must be a %g-multiple" % (imgsz_test, gs)
grid_min, grid_max = imgsz_test // gs, imgsz_test // gs
if multi_scale:
imgsz_min = opt.img_size // 1.5
imgsz_max = opt.img_size // 0.667
# 将给定的最大,最小输入尺寸向下调整到32的整数倍
grid_min, grid_max = imgsz_min // gs, imgsz_max // gs
imgsz_min, imgsz_max = int(grid_min * gs), int(grid_max * gs)
imgsz_train = imgsz_max # initialize with max size
print("Using multi_scale training, image range[{}, {}]".format(imgsz_min, imgsz_max))
...
# 多尺度训练
for epoch in range(start_epoch, epochs):
mloss, lr = train_util.train_one_epoch(model, optimizer, train_dataloader,
device, epoch,
accumulate=accumulate, # 迭代多少batch才训练完64张图片
img_size=imgsz_train, # 输入图像的大小
multi_scale=multi_scale,
grid_min=grid_min, # grid的最小尺寸
grid_max=grid_max, # grid的最大尺寸
gs=gs, # grid step: 32
print_freq=50, # 每训练多少个step打印一次信息
warmup=True,
scaler=scaler)
...
简要分析:
从代码上来看,其实Multi-scale Training的理念很简单,就是每次epoch的随机在一个范围内选择一个图像尺度进行训练。
测试时,生成几个不同尺度的feature map,对每个Region Proposal,在不同的feature map上也有不同的尺度,我们选择最接近某一固定尺寸(即检测头部的输入尺寸)的Region Proposal作为后续的输入。
常见的FPN结构,就是使用了多尺度特征层来预测,这里不再介绍。用兴趣的可以看一下之前的关于FPN的笔记:FPN(特征金字塔)结构笔记
参考资料:
https://blog.csdn.net/qq_40992227/article/details/115980500