几点说明:
- 6 epochs 是一个太少的数字,即使您使用预训练的网络,网络也无法收敛。尤其是像 resnet50 这样大的一个。我认为您至少需要 50 个 epoch。在预训练的 resnet18 上,我在 30 个 epoch 后开始获得良好的结果,resnet34 需要 +10-20 个 epoch,而你的 resnet50 + 40k 个训练集图像 - 肯定需要比 6 个更多的 epoch;
- 一定要使用预训练的网络;
- 根据我的经验,我未能通过 SGD 获得我喜欢的结果。我开始使用 AdamW + ReduceLROnPlateau 调度程序。网络收敛速度非常快,例如 7-8 时期的 50-60% AP,但随后在 50-60 时期后使用非常小的改进从时期到时期达到 80-85,前提是 LR 足够小。您必须熟悉梯度下降的概念。我曾经认为它好像你有更多的增强,你的“山”被你必须能够绕过的“巨石”覆盖,这只有在你控制 LR 时才有可能。此外,AdamW 有助于解决过拟合问题。
这就是我的做法。对于具有更高输入分辨率的网络(您输入的图像由网络本身根据输入进行缩放),我使用更高的 lr。
init_lr = 0.00005
weight_decay = init_lr * 100
optimizer = torch.optim.AdamW(params, lr=init_lr, weight_decay=weight_decay)
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, verbose=True, patience=3, factor=0.75)
for epoch in range(epochs):
# train for one epoch, printing every 10 iterations
metric_logger = train_one_epoch(model, optimizer, train_loader, scaler, device,
epoch, print_freq=10)
scheduler.step(metric_logger.loss.global_avg)
optimizer.param_groups[0]["weight_decay"] = optimizer.param_groups[0]["lr"] * 100
# scheduler.step()
# evaluate on the test dataset
evaluate(model, test_loader, device=device)
print("[INFO] serializing model to '{}' ...".format(args["model"]))
save_and_print_size_of_model(model, args["model"], script=False)
找到这样一个 lr 和权重衰减,使得训练在训练结束时将 lr 消耗到一个非常小的值,例如初始 lr 的 1/10。如果您经常遇到平台期,调度程序会迅速将其设置为非常小的值,并且网络将在其余的所有时期内一无所获。
您的图表表明您的 LR 在训练的某个时间点太高,网络停止训练,然后 AP 下降。您需要不断改进,即使是很小的改进。网络训练的越多,它对你的领域了解的细节就越多,学习率就越小。恕我直言,恒定的 LR 不允许这样做。
-
锚生成器设置。这是我初始化网络的方式。
def get_maskrcnn_resnet_model(name, num_classes, pretrained, res='normal'):
print('Using maskrcnn with {} backbone...'.format(name))
backbone = resnet_fpn_backbone(name, pretrained=pretrained, trainable_layers=5)
sizes = ((4,), (8,), (16,), (32,), (64,))
aspect_ratios = ((0.25, 0.5, 1.0, 2.0, 4.0),) * len(sizes)
anchor_generator = AnchorGenerator(
sizes=sizes, aspect_ratios=aspect_ratios
)
roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=['0', '1', '2', '3'],
output_size=7, sampling_ratio=2)
default_min_size = 800
default_max_size = 1333
if res == 'low':
min_size = int(default_min_size / 1.25)
max_size = int(default_max_size / 1.25)
elif res == 'normal':
min_size = default_min_size
max_size = default_max_size
elif res == 'high':
min_size = int(default_min_size * 1.25)
max_size = int(default_max_size * 1.25)
else:
raise ValueError('Invalid res={} param'.format(res))
model = MaskRCNN(backbone, min_size=min_size, max_size=max_size, num_classes=num_classes,
rpn_anchor_generator=anchor_generator, box_roi_pool=roi_pooler)
model.roi_heads.detections_per_img = 512
return model
我需要在这里找到小对象为什么我使用这样的锚参数。
- 类平衡问题。如果你只有你的对象和背景 - 没问题。如果您有更多课程,请确保您的训练分配(80% 用于训练,20% 用于测试)或多或少精确地应用于您的特定训练中使用的所有课程。
祝你好运!