几周前,TorchVision v0.11 发布,其中包含许多新的原语、模型和训练配方改进,这些改进使得能够获得最先进 (SOTA) 的结果。该项目被称为“包含电池的 TorchVision”,旨在对我们的库进行现代化改造。我们希望通过使用通用构建块,使研究人员能够更轻松地重现论文和进行研究。此外,我们渴望为应用 ML 从业人员提供必要的工具,让他们能够使用与研究中相同的 SOTA 技术在自己的数据上训练模型。最后,我们希望更新我们的预训练权重,并为我们的用户提供更好的开箱即用模型,希望他们能够构建更好的应用程序。
尽管仍有许多工作要做,但我们想与大家分享上述工作中的一些令人振奋的结果。我们将展示如何使用 TorchVision 中包含的新工具,在 ResNet50 等高度竞争且经过充分研究的架构上获得最先进的结果[1]。我们将分享用于将基线改进 4.7 个以上精度点的精确配方,以达到 80.9% 的最终 top-1 精度,并分享推导出新训练过程的过程。此外,我们将证明这种配方可以很好地推广到其他模型变体和系列。我们希望上述内容会影响未来开发更强大的可泛化训练方法的研究,并激励社区采用并为我们的努力做出贡献。
结果
使用我们在 ResNet50 上找到的新训练配方,我们更新了以下模型的预训练权重
模型 | 精度@1 | 精度@5 |
---|---|---|
ResNet50 | 80.858 | 95.434 |
ResNet101 | 81.886 | 95.780 |
ResNet152 | 82.284 | 96.002 |
ResNeXt50-32x4d | 81.198 | 95.340 |
请注意,除 RetNet50 外,所有模型的精度都可以通过稍微调整其训练参数来进一步提高,但我们的重点是拥有一个对所有模型都能良好执行的单一稳健配方。
**更新:**我们已经更新了 TorchVision 中大多数流行的分类模型,您可以在 这篇博文中找到详细信息。
目前有两种方法可以使用模型的最新权重。
使用多预训练权重 API
我们目前正在研究一种新的原型机制,它将扩展 TorchVision 的模型构建器方法以支持多个权重。除了权重,我们还存储有用的元数据(例如标签、精度、配方链接等)以及使用模型所需的预处理转换。示例
from PIL import Image
from torchvision import prototype as P
img = Image.open("test/assets/encode_jpeg/grace_hopper_517x606.jpg")
# Initialize model
weights = P.models.ResNet50_Weights.IMAGENET1K_V2
model = P.models.resnet50(weights=weights)
model.eval()
# Initialize inference transforms
preprocess = weights.transforms()
# Apply inference preprocessing transforms
batch = preprocess(img).unsqueeze(0)
prediction = model(batch).squeeze(0).softmax(0)
# Make predictions
label = prediction.argmax().item()
score = prediction[label].item()
# Use meta to get the labels
category_name = weights.meta['categories'][label]
print(f"{category_name}: {100 * score}%")
使用传统 API
那些不想使用原型 API 的用户可以选择使用以下方法通过传统 API 访问新权重
from torchvision.models import resnet
# Overwrite the URL of the previous weights
resnet.model_urls["resnet50"] = "https://download.pytorch.org/models/resnet50-11ad3fa6.pth"
# Initialize the model using the legacy API
model = resnet.resnet50(pretrained=True)
# TODO: Apply preprocessing + call the model
# ...
训练配方
我们的目标是使用 TorchVision 中新引入的原语来推导出一个新的强大的训练配方,该配方在从头开始在 ImageNet 上进行训练时,对 vanilla ResNet50 架构获得最先进的结果,无需任何额外的外部数据。虽然通过使用特定于架构的技巧[2]可以进一步提高精度,但我们决定不包括它们,以便该配方可以用于其他架构。我们的配方很大程度上侧重于简洁性,并建立在 FAIR 的工作基础上[3]、[4]、[5]、[6]、[7]。我们的发现与 Wightman 等人的平行研究一致[7],他们也报告了通过关注训练配方而获得的重大精度改进。
事不宜迟,以下是我们的配方的主要参数
# Optimizer & LR scheme
ngpus=8,
batch_size=128, # per GPU
epochs=600,
opt='sgd',
momentum=0.9,
lr=0.5,
lr_scheduler='cosineannealinglr',
lr_warmup_epochs=5,
lr_warmup_method='linear',
lr_warmup_decay=0.01,
# Regularization and Augmentation
weight_decay=2e-05,
norm_weight_decay=0.0,
label_smoothing=0.1,
mixup_alpha=0.2,
cutmix_alpha=1.0,
auto_augment='ta_wide',
random_erase=0.1,
ra_sampler=True,
ra_reps=4,
# EMA configuration
model_ema=True,
model_ema_steps=32,
model_ema_decay=0.99998,
# Resizing
interpolation='bilinear',
val_resize_size=232,
val_crop_size=224,
train_crop_size=176,
使用我们的标准训练参考脚本,我们可以使用以下命令训练 ResNet50
torchrun --nproc_per_node=8 train.py --model resnet50 --batch-size 128 --lr 0.5 \
--lr-scheduler cosineannealinglr --lr-warmup-epochs 5 --lr-warmup-method linear \
--auto-augment ta_wide --epochs 600 --random-erase 0.1 --weight-decay 0.00002 \
--norm-weight-decay 0.0 --label-smoothing 0.1 --mixup-alpha 0.2 --cutmix-alpha 1.0 \
--train-crop-size 176 --model-ema --val-resize-size 232 --ra-sampler --ra-reps 4
方法
在我们的探索过程中,我们牢记以下几个原则
- 训练是一个随机过程,我们试图优化的验证指标是一个随机变量。这是由于采用的随机权重初始化方案以及训练过程中存在随机效应。这意味着我们无法通过一次运行来评估配方更改的效果。标准做法是进行多次运行(通常为 3 到 5 次),并研究汇总统计数据(如平均值、标准差、中位数、最大值等)。
- 不同参数之间通常存在显着的交互作用,尤其是对于侧重于正则化和减少过拟合的技术而言。因此,更改一个参数的值可能会影响其他参数的最佳配置。为了解决这个问题,可以采用贪婪搜索方法(这通常会导致次优结果,但实验易于处理)或应用网格搜索(这会导致更好的结果,但计算量很大)。在这项工作中,我们使用了两种方法的混合。
- 非确定性或引入噪声的技术通常需要更长的训练周期来提高模型性能。为了保持实验的可处理性,我们最初使用较短的训练周期(较少的训练次数)来确定哪些路径可以提前消除,哪些路径应该使用更长的训练进行探索。
- 由于重复实验,存在过度拟合验证数据集的风险[8]。为了降低一些风险,我们仅应用提供显着精度改进的训练优化,并使用 K 折交叉验证来验证对验证集进行的优化。此外,我们还确认我们的配方成分可以很好地推广到我们没有对其进行超参数优化的其他模型。
主要精度改进的细分
如之前的博文所述,训练模型并非一个单调递增精度的过程,该过程涉及大量的回溯。为了量化每项优化的效果,我们试图以下面所示的理想线性过程来展示推导出最终配方的过程,该过程从 TorchVision 的原始配方开始。我们想澄清,这是一个对我们遵循的实际路径的过度简化,因此应谨慎对待。
在下表中,我们提供了在基线之上堆叠的增量改进的性能摘要。除非另有说明,否则我们报告的是 3 次运行中 Acc@1 最佳的模型
精度@1 | 精度@5 | 增量差值 | 绝对差值 | |
---|---|---|---|---|
ResNet50 基线 | 76.130 | 92.862 | 0.000 | 0.000 |
+ LR 优化 | 76.494 | 93.198 | 0.364 | 0.364 |
+ TrivialAugment | 76.806 | 93.272 | 0.312 | 0.676 |
+ 长训练 | 78.606 | 94.052 | 1.800 | 2.476 |
+ 随机擦除 | 78.796 | 94.094 | 0.190 | 2.666 |
+ 标签平滑 | 79.114 | 94.374 | 0.318 | 2.984 |
+ Mixup | 79.232 | 94.536 | 0.118 | 3.102 |
+ Cutmix | 79.510 | 94.642 | 0.278 | 3.380 |
+ 权重衰减调整 | 80.036 | 94.746 | 0.526 | 3.906 |
+ FixRes 缓解措施 | 80.196 | 94.672 | 0.160 | 4.066 |
+ EMA | 80.450 | 94.908 | 0.254 | 4.320 |
+ 推理大小调整* | 80.674 | 95.166 | 0.224 | 4.544 |
+ 重复增强** | 80.858 | 95.434 | 0.184 | 4.728 |
* 推理大小调整是在最后一个模型的基础上进行的。有关详细信息,请参见下文。
** 文章发布后,社区做出的贡献。有关详细信息,请参见下文。
基线
我们的基线是之前发布的 TorchVision 的 ResNet50 模型。它是使用以下配方训练的
# Optimizer & LR scheme
ngpus=8,
batch_size=32, # per GPU
epochs=90,
opt='sgd',
momentum=0.9,
lr=0.1,
lr_scheduler='steplr',
lr_step_size=30,
lr_gamma=0.1,
# Regularization
weight_decay=1e-4,
# Resizing
interpolation='bilinear',
val_resize_size=256,
val_crop_size=224,
train_crop_size=224,
上述大多数参数是我们的训练脚本中的默认值。我们将从这个基线开始,通过引入优化来构建,直到我们逐步获得最终配方。
LR 优化
我们可以应用一些参数更新来提高训练的精度和速度。这可以通过增加批次大小和调整 LR 来实现。另一种常见方法是应用预热,并逐渐提高我们的学习率。这在使用非常高的学习率时特别有用,有助于在早期训练中保持训练的稳定性。最后,另一种优化方法是应用余弦调度来调整我们每个训练次数中的 LR。余弦调度的一个很大的优点是,它没有超参数需要优化,从而减少了我们的搜索空间。
以下是针对基准方案的额外优化。请注意,我们已经进行了多个实验来确定参数的最佳配置。
batch_size=128, # per GPU
lr=0.5,
lr_scheduler='cosineannealinglr',
lr_warmup_epochs=5,
lr_warmup_method='linear',
lr_warmup_decay=0.01,
上述优化使我们的 top-1 准确率比基准提高了 0.364 个点。请注意,为了结合不同的 LR 策略,我们使用了新引入的 SequentialLR 调度器。
TrivialAugment
原始模型使用基本增强变换进行训练,例如随机调整大小的裁剪和水平翻转。提高准确率的一种简单方法是应用更复杂的“自动增强”技术。对我们来说表现最好的技术是 TrivialAugment [9],它非常简单,可以认为是“无参数”的,这意味着它可以帮助我们进一步缩小搜索空间。
以下是针对上一步的更新。
auto_augment='ta_wide',
使用 TrivialAugment 使我们的 top-1 准确率比上一步提高了 0.312 个点。
长时间训练
当我们的方案包含行为随机的成分时,更长的训练周期是有益的。更具体地说,随着我们开始添加越来越多的引入噪声的技术,增加 epochs 数变得至关重要。请注意,在我们探索的早期阶段,我们使用了大约 200 个 epochs 的相对较短的周期,后来随着我们开始缩小大多数参数范围,将其增加到 400 个 epochs,最后在方案的最终版本中增加到 600 个 epochs。
下面我们看到针对之前步骤的更新。
epochs=600,
这使我们的 top-1 准确率在上一步骤的基础上进一步提高了 1.8 个点。这是在这个迭代过程中我们将观察到的最大提高。值得注意的是,这种单一优化的效果被夸大了,并且在某种程度上具有误导性。仅仅在旧的基准上增加 epochs 数不会产生如此显著的改进。然而,将 LR 优化与强大的增强策略相结合,可以帮助模型从更长的周期中获益。还需要提一下的是,我们在过程的早期阶段引入长训练周期的原因是,在接下来的步骤中,我们将引入需要更多 epochs 才能提供良好结果的技术。
随机擦除
另一种已知有助于分类准确率的数据增强技术是随机擦除 [10],[11]。它通常与自动增强方法配对使用,由于其正则化效果,通常可以提高准确率。在我们的实验中,我们只通过网格搜索调整了应用该方法的概率,发现将其概率保持在较低水平(通常在 10% 左右)是有益的。
以下是针对上一步的额外参数。
random_erase=0.1,
应用随机擦除使我们的 Acc@1 进一步提高了 0.190 个点。
标签平滑
减少过度拟合的一种好方法是阻止模型变得过于自信。这可以通过使用标签平滑 [12] 来软化真实标签来实现。有一个参数可以控制平滑程度(越高越强),我们需要指定它。虽然可以通过网格搜索对其进行优化,但我们发现大约 0.05-0.15 的值会产生类似的结果,因此为了避免过度拟合,我们使用了与引入它的论文中相同的值。
下面我们可以找到此步骤添加的额外配置。
label_smoothing=0.1,
我们使用 PyTorch 新引入的 CrossEntropyLoss label_smoothing 参数,这使我们的准确率额外提高了 0.318 个点。
Mixup 和 Cutmix
两种常用于产生 SOTA 结果的数据增强技术是 Mixup 和 Cutmix [13],[14]。它们都通过软化标签和图像来提供强大的正则化效果。在我们的设置中,我们发现随机应用其中一个并以相等的概率进行应用是有益的。每个都用超参数 alpha 参数化,它控制从其中采样平滑概率的 Beta 分布的形状。我们进行了非常有限的网格搜索,主要集中在论文中提出的通用值上。
下面您将找到两种技术的 alpha 参数的最佳值。
mixup_alpha=0.2,
cutmix_alpha=1.0,
应用 mixup 使我们的准确率提高了 0.118 个点,与 cutmix 相结合使准确率提高了额外的 0.278 个点。
权重衰减调整
我们的标准方案使用 L2 正则化来减少过度拟合。权重衰减参数控制正则化的程度(越大越强),默认情况下它被普遍应用于模型的所有学习参数。在本方案中,我们对标准方法应用了两种优化。首先,我们执行网格搜索来调整权重衰减的参数,其次,我们禁用归一化层的参数的权重衰减。
下面您可以找到我们方案的权重衰减的最佳配置。
weight_decay=2e-05,
norm_weight_decay=0.0,
上述更新使我们的准确率进一步提高了 0.526 个点,提供了额外的实验证据,证明了一个已知的事实,即调整权重衰减对模型的性能有重大影响。我们分离归一化参数与其他参数的方法受到 ClassyVision 方法的启发。
FixRes 缓解措施
在我们实验早期发现的一个重要特性是,如果验证期间使用的分辨率从训练的 224x224 提高,则模型的性能会显著提高。FixRes 论文 [5] 对此进行了详细研究,并提出了两种缓解措施:a) 可以尝试降低训练分辨率,以便在验证分辨率上最大化准确率,或者 b) 可以对模型进行两阶段训练,使其在目标分辨率上进行调整。由于我们不想引入两阶段训练,因此我们选择了选项 a)。这意味着我们将训练裁剪大小从 224 减小,并使用网格搜索找到最大化 224x224 分辨率的验证的值。
下面您可以看到我们方案中使用的最佳值。
val_crop_size=224,
train_crop_size=176,
上述优化使我们的准确率额外提高了 0.160 个点,并将我们的训练速度提高了 10%。
值得注意的是,FixRes 效果仍然存在,这意味着当我们提高分辨率时,模型在验证时会继续表现得更好。此外,进一步降低训练裁剪大小实际上会损害准确率。从直觉上讲,这是有道理的,因为你只能降低分辨率到一定程度,然后关键细节就会开始从图像中消失。最后,我们应该注意,上述 FixRes 缓解措施似乎有利于深度与 ResNet50 类似的模型。具有更大感受野的更深层的变体似乎受到轻微的负面影响(通常为 0.1-0.2 个点)。因此,我们将此方案的一部分视为可选。下面,我们可视化了使用 176 和 224 分辨率训练的模型的最佳可用检查点(使用完整方案)的性能。
指数移动平均 (EMA)
EMA 是一种技术,它允许在不增加模型复杂度或推理时间的情况下提高模型的准确率。它对模型权重执行指数移动平均,这会导致更高的准确率和更稳定的模型。平均值每隔几个迭代计算一次,其衰减参数通过网格搜索进行调整。
下面您可以看到我们方案的最佳值。
model_ema=True,
model_ema_steps=32,
model_ema_decay=0.99998,
使用 EMA 使我们的准确率比上一步提高了 0.254 个点。请注意,TorchVision 的 EMA 实现 是建立在 PyTorch 的 AveragedModel 类之上的,主要区别在于它不仅对模型参数进行平均,还对它的缓冲区进行平均。此外,我们已经采用了来自 Pycls 的技巧,这些技巧使我们能够以不依赖 epochs 数的方式参数化衰减。
推理调整大小
与该过程中所有其他步骤(涉及使用不同参数训练模型)不同,此优化是在最终模型的基础上完成的。在推理期间,图像将调整到特定分辨率,然后从中截取一个 224x224 的中央裁剪。原始方案使用 256 的调整大小,这导致了与 FixRes 论文 [5] 中描述的类似差异。通过使此调整大小值更接近目标推理分辨率,可以提高准确率。为了选择该值,我们在 [224, 256] 的区间内以 8 为步长运行短网格搜索。为了避免过度拟合,该值是使用一半的验证集选择的,并使用另一半验证集确认。
下面您可以看到我们方案中使用的最佳值。
val_resize_size=232,
上述优化使我们的准确率提高了 0.224 个点。值得注意的是,ResNet50 的最佳值也是 ResNet101、ResNet152 和 ResNeXt50 的最佳值,这表明它在模型之间具有通用性。
[更新] 重复增强
重复增强 [15],[16] 是另一种可以提高整体准确率的技术,已被其他强大的方案(如 [6],[7] 中的方案)使用。社区贡献者 Tal Ben-Nun 在 进一步改进 我们原始方案的基础上,建议用 4 次重复训练模型。他的贡献是在本文发布之后做出的。
下面您可以看到我们方案中使用的最佳值。
ra_sampler=True,
ra_reps=4,
上述是最终优化,使我们的准确率提高了 0.184 个点。
经过测试但未被采用的优化
在我们研究的早期阶段,我们尝试了其他技术、配置和优化。由于我们的目标是保持方案尽可能简单,因此我们决定不包含任何没有提供显著改进的方案。以下是我们尝试过但没有进入最终方案的一些方法。
- 优化器:使用更复杂的优化器(如 Adam、RMSProp 或带 Nesterov 动量的 SGD)没有比带动量的普通 SGD 提供显著更好的结果。
- LR 调度器:我们尝试了不同的 LR 调度器方案,例如 StepLR 和 Exponential。虽然后者往往与 EMA 配合得更好,但它通常需要额外的超参数(如定义最小 LR 才能正常工作)。相反,我们只使用余弦退火,将 LR 衰减到零,并选择具有最高准确率的检查点。
- 自动增强:我们尝试了不同的增强策略,例如 AutoAugment 和 RandAugment。这些都没有超过更简单的无参数 TrivialAugment。
- 插值:使用双三次或最近邻插值没有比双线性插值提供显著更好的结果。
- 归一化层:使用同步批处理归一化没有比使用常规批处理归一化产生显著更好的结果。
致谢
我们要感谢 Piotr Dollar、Mannat Singh 和 Hugo Touvron 在方案开发期间提供他们的见解和反馈,以及他们之前基于此方案进行的研究工作。他们的支持对于取得上述成果至关重要。此外,我们要感谢 Prabhat Roy、Kai Zhang、Yiwen Song、Joel Schlosser、Ilqar Ramazanli、Francisco Massa、Mannat Singh、Xiaoliang Dai、Samuel Gabriel、Allen Goodman 和 Tal Ben-Nun 对“Batteries Included”项目的贡献。
参考文献
- 何恺明,张祥雨,任少卿,孙剑. “深度残差学习用于图像识别”.
- 何桐,张志,张航,张仲月,谢俊远,李沐. “卷积神经网络图像分类的技巧集锦”
- Piotr Dollár,Mannat Singh,Ross Girshick. “快速且准确的模型缩放”
- Tete Xiao,Mannat Singh,Eric Mintun,Trevor Darrell,Piotr Dollár,Ross Girshick. “早期卷积帮助Transformer更好地识别”
- Hugo Touvron,Andrea Vedaldi,Matthijs Douze,Hervé Jégou. “修复训练-测试分辨率差异”
- Hugo Touvron,Matthieu Cord,Matthijs Douze,Francisco Massa,Alexandre Sablayrolles,Hervé Jégou. “通过注意力训练数据高效的图像Transformer & 蒸馏”
- Ross Wightman,Hugo Touvron,Hervé Jégou. “ResNet卷土重来:timm中改进的训练过程”
- Benjamin Recht,Rebecca Roelofs,Ludwig Schmidt,Vaishaal Shankar. “ImageNet分类器是否能泛化到ImageNet?”
- Samuel G. Müller,Frank Hutter. “TrivialAugment:无调参的最新数据增强方法”
- 钟准,郑良,康国良,李少滋,杨易. “随机擦除数据增强”
- Terrance DeVries,Graham W. Taylor. “用Cutout改进卷积神经网络的正则化”
- Christian Szegedy,Vincent Vanhoucke,Sergey Ioffe,Jon Shlens,Zbigniew Wojna. “重新思考用于计算机视觉的Inception架构”
- 张弘毅,Moustapha Cisse,Yann N. Dauphin,David Lopez-Paz. “mixup:超越经验风险最小化”
- Sangdoo Yun,Dongyoon Han,Seong Joon Oh,Sanghyuk Chun,Junsuk Choe,Youngjoon Yoo. “CutMix:使用可定位特征训练强分类器的正则化策略”
- Elad Hoffer,Tal Ben-Nun,Itay Hubara,Niv Giladi,Torsten Hoefler,Daniel Soudry. “增强你的批次:使用更大批次进行更好的训练”
- Maxim Berman,Hervé Jégou,Andrea Vedaldi,Iasonas Kokkinos,Matthijs Douze. “Multigrain:统一的图像嵌入,用于类别和实例”