当前位置: 首页 > news >正文

YOLO入门教程(番外):计算机视觉—图像增广

1、图像增广

大型数据集是成功应用深度神经网络的先决条件。

图像增广在对训练图像进行一系列的随机变化之后,生成相似但不同的训练样本,从而扩大了训练集的规模。

此外,应用图像增广的原因是,随机改变训练样本可以减少模型对某些属性的依赖,从而提高模型的泛化能力。

例如,我们可以以不同的方式裁剪图像,使感兴趣的对象出现在不同的位置,减少模型对于对象出现位置的依赖。 我们还可以调整亮度、颜色等因素来降低模型对颜色的敏感度。

可以说,图像增广技术对于AlexNet的成功是必不可少的。本节将讨论这项广泛应用于计算机视觉的技术。

# 这是Jupyter Notebook/JupyterLab的魔法命令,用于在Notebook中内嵌显示Matplotlib图形
# 在常规Python脚本中不需要此命令
%matplotlib inline# 导入PyTorch深度学习框架的核心库
# PyTorch提供了张量计算、自动求导和神经网络构建等功能
import torch# 导入TorchVision计算机视觉库
# 提供常用的数据集、模型架构和图像转换工具
import torchvision# 从PyTorch中导入神经网络模块(nn)
# 包含各种神经网络层、损失函数和模型容器
from torch import nn# 从d2l库中导入PyTorch相关的实用函数
# d2l是《动手学深度学习》教材的配套工具库,提供可视化、数据加载等辅助功能
from d2l import torch as d2l

1.1 常用的图像增广方法

在对常用图像增广方法的探索时,我们将使用下面这个尺寸为400 x 500 的图像作为示例:

# 设置Matplotlib图表输出的默认大小,使其在Jupyter Notebook中显示得更大、更清晰
# 这是一个d2l库提供的便利函数,避免了手动设置figure size的麻烦
d2l.set_figsize()# 使用d2l库封装的Image.open方法打开一张图片
# 注意:这里的路径'../img/cat1.jpg'是一个相对路径,表示上一级目录的img文件夹中的cat1.jpg文件
# d2l.Image实际上是PIL.Image的引用,这是一个强大的图像处理库
img = d2l.Image.open('../img/cat1.jpg')# 使用Matplotlib的imshow函数显示图像
# d2l.plt是matplotlib.pyplot的别名,由之前的from d2l import torch as d2l导入
# 行末的分号(;)用于抑制不必要的文本输出(如图像数组信息),只显示图像本身
d2l.plt.imshow(img);

大多数图像增广方法都具有一定的随机性。

为了便于观察图像增广的效果,我们下面定义辅助函数apply。 此函数在输入图像img上多次运行图像增广方法aug并显示所有结果。

【图片】

# 定义一个名为apply的函数,用于对输入图像应用多次数据增强并可视化结果
# 参数说明:
#   img: 输入的原始图像(通常是PIL图像对象或张量)
#   aug: 数据增强函数,该函数接收一个图像并返回增强后的图像
#   num_rows: 显示结果图像的行数,默认为2行
#   num_cols: 显示结果图像的列数,默认为4列
#   scale: 图像显示的缩放比例,默认为1.5倍
def apply(img, aug, num_rows=2, num_cols=4, scale=1.5):# 使用列表推导式生成多个增强后的图像# 对原始图像应用aug函数num_rows*num_cols次(默认为8次)# 每次应用都会产生一个随机增强版本的图像# 下划线_表示我们不需要循环变量的值,只需要执行指定次数的循环Y = [aug(img) for _ in range(num_rows * num_cols)]# 使用d2l库的show_images函数将所有增强后的图像显示在一个网格中# 参数说明:#   Y: 包含所有增强后图像的列表#   num_rows: 网格行数#   num_cols: 网格列数#   scale: 图像显示大小的缩放因子d2l.show_images(Y, num_rows, num_cols, scale=scale)

1.1.1. 翻转和裁剪

左右翻转图像通常不会改变对象的类别。

这是最早且最广泛使用的图像增广方法之一。

接下来,我们使用transforms模块来创建RandomFlipLeftRight实例,这样就各有50%的几率使图像向左或向右翻转。

# 调用之前定义的apply函数,对图像应用随机水平翻转增强
# 参数说明:
#   img: 之前加载的猫的图像
#   torchvision.transforms.RandomHorizontalFlip(): 创建随机水平翻转增强器
apply(img, torchvision.transforms.RandomHorizontalFlip())

【图片】

上下翻转图像不如左右图像翻转那样常用。

但是,至少对于这个示例图像,上下翻转不会妨碍识别。接下来,我们创建一个RandomFlipTopBottom实例,使图像各有50%的几率向上或向下翻转。

# 调用apply函数,对图像应用随机垂直翻转增强
# 参数说明:
#   img: 之前加载的猫的图像
#   torchvision.transforms.RandomVerticalFlip(): 创建随机垂直翻转增强器
apply(img, torchvision.transforms.RandomVerticalFlip())

图片

在我们使用的示例图像中,猫位于图像的中间,但并非所有图像都是这样。 在 6.5节中,我们解释了汇聚层可以降低卷积层对目标位置的敏感性。

另外,我们可以通过对图像进行随机裁剪,使物体以不同的比例出现在图像的不同位置。 这也可以降低模型对目标位置的敏感性。

下面的代码将随机裁剪一个面积为原始面积10%到100%的区域,该区域的宽高比从0.5~2之间随机取值。 然后,区域的宽度和高度都被缩放到200像素。 在本节中(除非另有说明),a
和 b 之间的随机数指的是在区间 [a, b]中通过均匀采样获得的连续值。

# 创建一个随机缩放裁剪的数据增强器
# 参数说明:
#   (200, 200): 输出图像的尺寸,所有增强后的图像都会被调整为200×200像素
#   scale=(0.1, 1): 随机裁剪面积比例范围,从原始图像的10%到100%
#   ratio=(0.5, 2): 随机宽高比范围,从1:2到2:1之间
shape_aug = torchvision.transforms.RandomResizedCrop((200, 200), scale=(0.1, 1), ratio=(0.5, 2))# 应用形状增强并可视化结果
apply(img, shape_aug)

1.1.2. 改变颜色

另一种增广方法是改变颜色。 我们可以改变图像颜色的四个方面:亮度、对比度、饱和度和色调。 在下面的示例中,我们随机更改图像的亮度,随机值为原始图像的50%(1-0.5)到150%(1+0.5)之间。

# 应用颜色增强,只调整图像亮度
# 使用torchvision.transforms.ColorJitter创建颜色抖动增强器
# 参数说明:
#   brightness=0.5: 亮度调整强度为0.5(最大亮度变化±50%)
#   contrast=0: 对比度不进行调整
#   saturation=0: 饱和度不进行调整  
#   hue=0: 色调不进行调整
apply(img, torchvision.transforms.ColorJitter(brightness=0.5, contrast=0, saturation=0, hue=0))

同样,我们可以随机更改图像的色调。

# 应用颜色增强,只调整图像色调
# 使用torchvision.transforms.ColorJitter创建颜色抖动增强器
# 参数说明:
#   brightness=0: 亮度不进行调整
#   contrast=0: 对比度不进行调整
#   saturation=0: 饱和度不进行调整  
#   hue=0.5: 色调调整强度为0.5(最大色调变化±0.5,但在实际中会被限制到合理范围)
apply(img, torchvision.transforms.ColorJitter(brightness=0, contrast=0, saturation=0, hue=0.5))

我们还可以创建一个RandomColorJitter实例,并设置如何同时随机更改图像的亮度(brightness)、对比度(contrast)、饱和度(saturation)和色调(hue)。

# 创建一个综合的颜色抖动增强器,同时调整亮度、对比度、饱和度和色调
# 参数说明:
#   brightness=0.5: 亮度调整强度为0.5(最大亮度变化±50%)
#   contrast=0.5: 对比度调整强度为0.5(最大对比度变化±50%)
#   saturation=0.5: 饱和度调整强度为0.5(最大饱和度变化±50%)
#   hue=0.5: 色调调整强度为0.5(最大色调变化±0.5)
color_aug = torchvision.transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)# 应用综合颜色增强并可视化结果
apply(img, color_aug)

1.1.3. 结合多种图像增广方法

在实践中,我们将结合多种图像增广方法。

比如,我们可以通过使用一个Compose实例来综合上面定义的不同的图像增广方法,并将它们应用到每个图像。

# 典型的训练数据增强管道
train_transforms = torchvision.transforms.Compose([torchvision.transforms.RandomResizedCrop(224),      # 随机裁剪torchvision.transforms.RandomHorizontalFlip(),       # 随机翻转torchvision.transforms.ColorJitter(0.4, 0.4, 0.4),  # 颜色增强torchvision.transforms.ToTensor(),                   # 转换为张量torchvision.transforms.Normalize(mean, std)         # 标准化
])# 验证/测试数据通常使用较简单的变换
val_transforms = torchvision.transforms.Compose([torchvision.transforms.Resize(256),                  # 调整大小torchvision.transforms.CenterCrop(224),             # 中心裁剪torchvision.transforms.ToTensor(),                  # 转换为张量torchvision.transforms.Normalize(mean, std)         # 标准化
])

1.2. 使用图像增广进行训练

让我们使用图像增广来训练模型。 这里,我们使用CIFAR-10数据集,而不是我们之前使用的Fashion-MNIST数据集。 这是因为Fashion-MNIST数据集中对象的位置和大小已被规范化,而CIFAR-10数据集中对象的颜色和大小差异更明显。 CIFAR-10数据集中的前32个训练图像如下所示。

# 加载CIFAR-10训练数据集
# 参数说明:
#   train=True: 加载训练集(如果为False则加载测试集)
#   root="../data": 指定数据集存储的根目录,这里为上级目录的data文件夹
#   download=True: 如果数据集不存在,则自动下载
all_images = torchvision.datasets.CIFAR10(train=True, root="../data",download=True)# 显示CIFAR-10数据集中的32张样本图像
# 参数说明:
#   [all_images[i][0] for i in range(32)]: 获取数据集中前32个样本的图像部分
#   4: 显示4行图像
#   8: 显示8列图像(4×8=32张图像)
#   scale=0.8: 图像显示缩放比例为0.8
d2l.show_images([all_images[i][0] for i in range(32)], 4, 8, scale=0.8)
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ../data/cifar-10-python.tar.gz0%|          | 0/170498071 [00:00<?, ?it/s]Extracting ../data/cifar-10-python.tar.gz to ../data

为了在预测过程中得到确切的结果,我们通常对训练样本只进行图像增广,且在预测过程中不使用随机操作的图像增广。

在这里,我们只使用最简单的随机左右翻转。 此外,我们使用ToTensor实例将一批图像转换为深度学习框架所要求的格式,即形状为(批量大小,通道数,高度,宽度)的32位浮点数,取值范围为0~1。

# 定义训练数据的数据增强和预处理管道
# 训练阶段通常使用数据增强来提高模型的泛化能力
train_augs = torchvision.transforms.Compose([# 随机水平翻转增强:以50%的概率水平翻转图像# 这是一种简单但有效的数据增强技术,增加训练数据的多样性torchvision.transforms.RandomHorizontalFlip(),# 将PIL图像或numpy数组转换为PyTorch张量# 同时会自动将像素值从[0, 255]范围缩放到[0.0, 1.0]范围# 这是必须的步骤,因为PyTorch模型需要张量作为输入torchvision.transforms.ToTensor()
])# 定义测试数据的预处理管道
# 测试阶段通常不使用数据增强,以保持数据的原始分布
test_augs = torchvision.transforms.Compose([# 只进行必要的转换:将图像转换为张量# 不包含任何随机增强,确保测试结果的可重复性和公平性torchvision.transforms.ToTensor()
])

接下来,我们定义一个辅助函数,以便于读取图像和应用图像增广。PyTorch数据集提供的transform参数应用图像增广来转化图像。

# 定义一个通用的CIFAR-10数据加载函数
# 参数说明:
#   is_train: 布尔值,True表示加载训练集,False表示加载测试集
#   augs: 数据增强和预处理管道,根据训练/测试阶段传入不同的预处理方式
#   batch_size: 批量大小,指定每个批次包含的样本数量
def load_cifar10(is_train, augs, batch_size):# 创建CIFAR-10数据集对象# 参数说明:#   root="../data": 数据集存储的根目录#   train=is_train: 根据is_train参数决定加载训练集还是测试集#   transform=augs: 应用传入的数据增强和预处理管道#   download=True: 如果数据集不存在则自动下载dataset = torchvision.datasets.CIFAR10(root="../data", train=is_train,transform=augs, download=True)# 创建数据加载器(DataLoader),用于批量加载数据# 参数说明:#   dataset: 上面创建的数据集对象#   batch_size=batch_size: 每个批次包含的样本数量#   shuffle=is_train: 仅在训练时打乱数据顺序(增强随机性)#   num_workers=d2l.get_dataloader_workers(): 使用d2l库提供的优化工作线程数dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size,shuffle=is_train, num_workers=d2l.get_dataloader_workers())# 返回创建好的数据加载器return dataloader

1.2.1. 多GPU训练

我们在CIFAR-10数据集上训练 ResNet-18模型。 回想一下 对多GPU训练的介绍。 接下来,我们定义一个函数,使用多GPU对模型进行训练和评估。

#@save  # 这是一个特殊的注释,表示这个函数应该被保存到d2l库中
def train_batch_ch13(net, X, y, loss, trainer, devices):"""用多GPU进行小批量训练"""# 处理输入数据X:如果X是列表(例如BERT需要多个输入),将每个元素移动到设备# 否则直接将整个X张量移动到设备if isinstance(X, list):# 微调BERT中所需(处理多个输入的情况)X = [x.to(devices[0]) for x in X]else:X = X.to(devices[0])# 将标签y移动到设备y = y.to(devices[0])# 设置模型为训练模式(启用dropout、batch norm等训练特定行为)net.train()# 清空优化器中的梯度(防止梯度累积)trainer.zero_grad()# 前向传播:计算模型预测pred = net(X)# 计算损失l = loss(pred, y)# 反向传播:计算梯度# 使用.sum()是因为在多GPU环境下,损失可能是分布计算的l.sum().backward()# 更新模型参数trainer.step()# 计算当前批次的损失总和和准确率train_loss_sum = l.sum()train_acc_sum = d2l.accuracy(pred, y)return train_loss_sum, train_acc_sum
#@save  # 这是一个特殊的注释,表示这个函数应该被保存到d2l库中
def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,devices=d2l.try_all_gpus()):"""用多GPU进行模型训练"""# 初始化计时器和批次计数器timer, num_batches = d2l.Timer(), len(train_iter)# 创建动画绘制器,用于可视化训练过程animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0, 1],legend=['train loss', 'train acc', 'test acc'])# 使用DataParallel将模型复制到多个GPU上# devices[0]是主设备,所有GPU的梯度会在这里聚合net = nn.DataParallel(net, device_ids=devices).to(devices[0])# 开始训练循环for epoch in range(num_epochs):# 创建累加器,用于累积4个指标:损失总和、准确率总和、样本数、预测数metric = d2l.Accumulator(4)# 遍历训练数据集的每个批次for i, (features, labels) in enumerate(train_iter):# 开始计时timer.start()# 训练一个批次l, acc = train_batch_ch13(net, features, labels, loss, trainer, devices)# 累积指标:损失、准确率、样本数量、元素总数metric.add(l, acc, labels.shape[0], labels.numel())# 停止计时timer.stop()# 每完成1/5的批次或最后一个批次时,更新可视化if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:animator.add(epoch + (i + 1) / num_batches,(metric[0] / metric[2], metric[1] / metric[3],None))# 在每个epoch结束后,计算测试集准确率test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)# 更新可视化,添加测试准确率animator.add(epoch + 1, (None, None, test_acc))# 打印最终结果print(f'loss {metric[0] / metric[2]:.3f}, train acc 'f'{metric[1] / metric[3]:.3f}, test acc {test_acc:.3f}')# 打印训练速度(每秒处理的样本数)print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec on 'f'{str(devices)}')

现在,我们可以定义train_with_data_aug函数,使用图像增广来训练模型。

该函数获取所有的GPU,并使用Adam作为训练的优化算法,将图像增广应用于训练集,最后调用刚刚定义的用于训练和评估模型的train_ch13函数。

# 设置训练的超参数和模型
# batch_size: 批量大小设置为256,这是一个适合多GPU训练的中等批量大小
# devices: 自动检测并尝试使用所有可用的GPU
# net: 创建一个ResNet-18模型,输出类别数为10(CIFAR-10的10个类别),输入通道数为3(RGB图像)
batch_size, devices, net = 256, d2l.try_all_gpus(), d2l.resnet18(10, 3)# 定义权重初始化函数
# 这个函数将应用于网络的每一层
def init_weights(m):# 检查当前模块是否为线性层或卷积层if type(m) in [nn.Linear, nn.Conv2d]:# 使用Xavier均匀初始化方法初始化权重# 这种方法可以根据输入输出维度自动调整初始化范围,有助于训练稳定性nn.init.xavier_uniform_(m.weight)# 将权重初始化函数应用到网络的所有层
net.apply(init_weights)# 定义完整的数据增强训练函数
# 参数说明:
#   train_augs: 训练数据的数据增强管道
#   test_augs: 测试数据的数据增强管道
#   net: 要训练的神经网络模型
#   lr: 学习率,默认为0.001
def train_with_data_aug(train_augs, test_augs, net, lr=0.001):# 加载训练数据,应用训练数据增强train_iter = load_cifar10(True, train_augs, batch_size)# 加载测试数据,应用测试数据预处理(通常不包含随机增强)test_iter = load_cifar10(False, test_augs, batch_size)# 定义损失函数:交叉熵损失# reduction="none"表示不自动求平均或求和,保留每个样本的损失# 这样可以在train_ch13中更灵活地处理损失loss = nn.CrossEntropyLoss(reduction="none")# 定义优化器:Adam优化器# Adam是常用的自适应学习率优化算法,通常不需要太多调参trainer = torch.optim.Adam(net.parameters(), lr=lr)# 调用之前定义的多GPU训练函数进行训练# 参数说明: 网络、训练迭代器、测试迭代器、损失函数、优化器、训练轮数、设备train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices)

让我们使用基于随机左右翻转的图像增广来训练模型。

# 启动数据增强训练流程
# 使用之前定义的:
# - train_augs: 训练数据增强管道(包含随机水平翻转和转换为张量)
# - test_augs: 测试数据预处理管道(仅转换为张量)
# - net: 已经初始化的ResNet-18模型
train_with_data_aug(train_augs, test_augs, net)
loss 0.173, train acc 0.941, test acc 0.854
4183.9 examples/sec on [device(type='cuda', index=0), device(type='cuda', index=1)]

1.3. 小结

  • 图像增广基于现有的训练数据生成随机图像,来提高模型的泛化能力。

  • 为了在预测过程中得到确切的结果,我们通常对训练样本只进行图像增广,而在预测过程中不使用带随机操作的图像增广。

  • 深度学习框架提供了许多不同的图像增广方法,这些方法可以被同时应用。

1.4. 练习

  • 在不使用图像增广的情况下训练模型:train_with_data_aug(no_aug, no_aug)。比较使用和不使用图像增广的训练结果和测试精度。这个对比实验能支持图像增广可以减轻过拟合的论点吗?为什么?
  1. 定义“不使用图像增广”的预处理管道

首先,我们需要定义一个不做任何随机增强的预处理管道。这通常只包括将图像转换为张量,有时还包括归一化(但为了公平对比,我们暂时不使用归一化)。

# 定义不使用任何数据增强的预处理管道
# 只进行最基本的转换:将PIL图像转换为PyTorch张量
no_aug = torchvision.transforms.Compose([torchvision.transforms.ToTensor()
])
  1. 执行对比实验

现在我们在完全相同的条件下运行两个实验,唯一变量是是否使用数据增强。

实验1:不使用图像增广

# 重新初始化网络权重,确保公平比较
net.apply(init_weights)
print("训练不使用图像增广的模型...")
train_with_data_aug(no_aug, no_aug, net)

实验2:使用图像增广(您之前已经运行的)

# 重新初始化网络权重
net.apply(init_weights)
print("训练使用图像增广的模型...")
train_with_data_aug(train_augs, test_augs, net)
  1. 预期结果分析

基于理论和实践经验,我们预期会观察到以下模式:

指标不使用图像增广使用图像增广说明
训练损失较低 (如0.05-0.15)较高 (如0.1-0.3)增广使训练任务变难
训练准确率较高 (如95%-99%)较低 (如90%-96%)增广防止模型过拟合训练集
测试准确率较低 (如80%-88%)较高 (如85%-92%)增广提高模型泛化能力
泛化差距
(训练acc-测试acc)
较大 (如10%-15%)较小 (如3%-8%)增广减小过拟合程度
  1. 这个对比实验能支持"图像增广可以减轻过拟合"的论点吗?

是的,完全支持。 原因如下:

理论机制:

  1. 增加数据多样性:图像增广通过随机变换(翻转、裁剪、颜色调整等)创建了"新"的训练样本,相当于扩大了训练集规模,使模型看到更多样的数据变体。

  2. 引入归纳偏置:增广技术编码了我们对视觉不变性的先验知识(如物体翻转后类别不变、颜色变化后类别不变等),引导模型学习更本质的特征。

  3. 正则化效应:随机增广相当于向训练过程注入噪声,起到正则化作用,防止模型过度依赖训练集中的特定像素模式。

预期实验证据:
如果观察到以下模式,就强有力地支持了图像增广减轻过拟合的论点:

  • 不使用增广:训练准确率很高但测试准确率相对较低,两者差距大 → 明显的过拟合
  • 使用增广:训练准确率可能略低但测试准确率更高,两者差距小 → 更好的泛化能力

为什么这种对比有效:

  1. 控制变量:两个实验使用相同的网络架构、初始化权重、超参数和训练轮数,唯一区别是是否使用增广。

  2. 直接测量过拟合:过拟合的本质是模型在训练集上表现很好但在未见数据上表现差。通过比较训练-测试性能差距,可以直接量化过拟合程度。

  3. 可重复的结论:这个模式在大量学术研究和实践中被反复验证,是计算机视觉中的基本共识。

  1. 实际项目中的意义

这个实验不仅验证了理论,还具有重要实践价值:

  1. 指导模型设计:当发现模型过拟合时(训练远好于测试),首先应该考虑增加数据增强。
  2. 超参数调优:可以通过调整增强强度来平衡拟合能力和泛化能力。
  3. 资源分配:相比于收集更多真实数据,数据增强是一种低成本、高效率的提高模型性能的方法。

通过这个对比实验,您可以直观地看到数据增强如何像"魔法"一样,通过创造性的方式利用现有数据,显著提升模型的泛化性能,这是深度学习实践中最重要的技术之一。

  • 在基于CIFAR-10数据集的模型训练中结合多种不同的图像增广方法。它能提高测试准确性吗?

在大多数情况下,精心选择和组合多种不同的图像增广方法,几乎总是能提高模型在CIFAR-10上的测试准确性。**

但这并非一个简单的“是”或“否”的问题,其有效性取决于如何组合以及组合的强度

核心结论:为什么组合增广能提高测试准确性?

根本原因在于减轻过拟合提高模型泛化能力

  1. CIFAR-10的本质:它是一个相对较小的数据集(50k训练图像),模型很容易记住训练集的特有噪声和细节,从而导致过拟合(训练精度高,测试精度低)。
  2. 组合增广的作用:通过组合多种增广方法(如裁剪+翻转+颜色抖动),你实际上为模型创造了近乎“无限”多样性的训练样本。模型无法再简单地记忆固定的训练图片,而是被迫学习更鲁棒、更本质的特征(例如,“猫”的概念,而不是“某一张在某个特定位置、有着特定亮度的猫图片”)。

有效的组合增广策略

一个经过实践检验的、用于CIFAR-10的标准组合增广策略通常包括:

# 一个强大的组合增广示例
train_augs = torchvision.transforms.Compose([torchvision.transforms.RandomResizedCrop(32, scale=(0.8, 1.0), ratio=(0.9, 1.1)), # 随机缩放裁剪torchvision.transforms.RandomHorizontalFlip(p=0.5), # 随机水平翻转torchvision.transforms.ColorJitter(brightness=0.2,  # 亮度抖动contrast=0.2,    # 对比度抖动saturation=0.2,  # 饱和度抖动hue=0.1          # 色调抖动(要很小)),torchvision.transforms.ToTensor(),# 通常还会加上数据标准化torchvision.transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],std=[0.2023, 0.1994, 0.2010])
])test_augs = torchvision.transforms.Compose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],std=[0.2023, 0.1994, 0.2010])
])

组合增广如何提升性能:一个假设性示例

让我们通过一个表格来对比不同策略的预期结果:

训练策略训练精度测试精度泛化差距说明
无任何增广非常高 (~98%)一般 (~86%)模型严重过拟合,记住了训练集噪声。
仅水平翻转高 (~96%)较好 (~88%)中等减轻了部分过拟合,但多样性仍不足。
组合增广
(裁剪+翻转+颜色)
稍低 (~93%)最高 (~92%)模型无法记忆,被迫学习鲁棒特征,泛化能力最强。

关键点:请注意,使用组合增广后,训练精度可能会下降,但这是好事!这说明模型不再能轻易地“作弊”和过拟合。它学习速度变慢了,但学到的知识更扎实,最终在未见过的测试数据上表现更好。测试精度的提升和泛化差距的缩小是支持增广有效性的最直接证据。

需要注意的方面(为什么有时可能无效)

虽然理论上总是有效,但在实践中如果使用不当,也可能看不到提升甚至导致性能下降:

  1. 增广强度过大:如果颜色抖动得太离谱,或者裁剪得只剩下一小块无关的背景,图像的根本语义信息会被破坏。模型无法从这些“损坏”的图片中学习到有用的特征。例如,把一只猫的图片色调调整到完全变成蓝色,可能会让模型困惑。
  2. 不适合任务的增广:对于一些任务,某些增广是不合理的。例如,在数字识别中,垂直翻转“6”会变成近似“9”,这会引入错误标签。但在CIFAR-10中,水平翻转动物、车辆等物体通常是安全的。
  3. 计算开销:更复杂的增广 pipeline 会增加每个epoch的训练时间。但通常,由此带来的精度提升远高于其成本。
  4. 需要微调超参数:在使用强增广后,最优的学习率、权重衰减等超参数可能会发生变化,可能需要进行轻微的重新调整。

结论

是的,在CIFAR-10上,合理地组合多种图像增广方法是提高测试准确性、提升模型泛化能力的最有效且成本最低的策略之一。

它通过以下方式工作:

  • 创造数据多样性:模拟了更多可能的输入变化。
  • 引入正则化:防止模型过度依赖训练集中的特定视觉模式(如物体位置、颜色、大小)。
  • 迫使模型学习更本质的特征:模型必须学会“猫”在各种变形下仍然是“猫”,从而学到其核心特征。

要获得最佳效果,建议从标准的、经过验证的组合开始(如上述代码示例),然后可以根据具体模型和任务进行微调。几乎所有在CIFAR-10上达到高精度的模型都广泛使用了组合数据增广技术。

  • 参阅深度学习框架的在线文档。它还提供了哪些其他的图像增广方法?

除了之前提到的 RandomHorizontalFlip, RandomResizedCrop, 和 ColorJitter,现代框架提供了丰富得多的工具库。

PyTorch (TorchVision) 中的其他增广方法

TorchVision 的 transforms 模块是功能最丰富的之一。以下是其提供的一些关键增广方法:

  1. 几何变换 (Geometric Transformations)
    | 方法 | 描述 | 用途 |
    | :— | :— | :— |
    | RandomRotation | 随机旋转图像一定角度(如 ±30°) | 增强旋转不变性,对纹理、数字等有效 |
    | RandomAffine | 随机仿射变换(旋转、平移、缩放、剪切) | 综合的几何形变,模拟视角变化 |
    | RandomPerspective | 随机透视变换 | 模拟3D视角的形变,更真实 |
    | ElasticTransform | 弹性变换(类似“橡皮筋”拉伸) | 模拟非刚性形变,对医学影像特别有用 |
  1. 颜色与色调变换 (Color & Tone Transformations)
    | 方法 | 描述 | 用途 |
    | :— | :— | :— |
    | Grayscale | 将图像转换为灰度图 | 减少模型对颜色的依赖,关注形状纹理 |
    | RandomGrayscale | 随机地以一定概率转换为灰度 | 更灵活,大部分图像保留颜色,偶尔丢弃 |
    | RandomAdjustSharpness | 随机调整锐度 | 模拟焦距变化,增强对模糊/清晰图像的鲁棒性 |
    | RandomAutocontrast | 自动调整对比度 | 优化图像对比度,模拟不同光照条件 |
    | RandomPosterize | 减少每个通道的位数(如8位->4位) | 模拟颜色深度低的设备,增强鲁棒性 |
    | RandomSolarize | 反转所有高于阈值的像素值 | 创造特殊视觉效果,有时能提升性能 |
    | RandomEqualize | 随机进行直方图均衡化 | 增强图像对比度 |
  1. 模糊与滤波器 (Blur & Filters)
    | 方法 | 描述 | 用途 |
    | :— | :— | :— |
    | GaussianBlur | 应用高斯模糊 | 模拟图像失焦或远距离拍摄,防止模型过度关注细节 |
    | RandomInvert | 随机反转像素颜色 | 创造负片效果,是一种强增广 |
  1. 自动增广 (Auto-Augmentation)
    这是最强大的功能之一,它基于学习到的策略自动应用一系列增广。
    | 方法 | 描述 |
    | :— | :— |
    | AutoAugment | 应用在ImageNet上学习到的最佳增广策略 |
    | RandAugment | 更简单的自动增广,超参数更少,效果通常更好 |
    | TrivialAugmentWide | 另一种自动增广,计算成本低且性能优异 |
  1. 组合与随机选择
    | 方法 | 描述 |
    | :— | :— |
    | RandomApply | 随机地以给定概率应用一个变换列表中的某个变换 |
    | RandomChoice | 从一系列变换中随机选择一种应用 |

TensorFlow / Keras 中的增广方法

Keras 的 tf.keras.layers 提供了一些内置层,可以直接嵌入到模型中,在GPU上进行加速。

方法 (Layer)描述
RandomRotation随机旋转
RandomZoom随机缩放(可能伴随裁剪)
RandomTranslation随机平移
RandomContrast随机调整对比度
RandomCrop随机裁剪(注意:与ResizedCrop不同,它不缩放回原大小)

一个强大的组合增广示例代码 (PyTorch)

from torchvision import transforms# 一个更复杂、更强大的组合增广策略
advanced_aug = transforms.Compose([transforms.RandomResizedCrop(224, scale=(0.8, 1.0)),  # 随机缩放裁剪transforms.RandomHorizontalFlip(p=0.5),               # 随机水平翻转transforms.RandomVerticalFlip(p=0.05),                # 偶尔随机垂直翻转(慎用)transforms.RandomRotation(degrees=15),                # 随机旋转 ±15度transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.1), # 颜色抖动transforms.RandomApply([transforms.GaussianBlur(kernel_size=(5, 5), sigma=(0.1, 2.0))], p=0.2), # 20%概率模糊transforms.RandomGrayscale(p=0.1),                    # 10%概率转灰度transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])# 或者直接使用研究证明有效的自动增广策略
auto_aug = transforms.Compose([transforms.AutoAugment(transforms.AutoAugmentPolicy.IMAGENET), # 或 CIFAR10, SVHNtransforms.ToTensor(),transforms.Normalize(...)
])

总结:如何选择?

  1. 从简单开始:对于新任务,先从 RandomHorizontalFlip + RandomResizedCrop + ColorJitter 开始。
  2. 引入几何变换:如果任务需要旋转不变性(如卫星图像、医学影像),加入 RandomRotation
  3. 防止过拟合:如果模型开始过拟合,加入 GaussianBlurRandomGrayscale 来“破坏”细节。
  4. 使用“大招”:当你想进一步提升模型性能时,不要手动调参,直接尝试 RandAugmentAutoAugment。这些自动增广策略是在大量数据上学习出来的最优组合,通常比手动设计的更有效。

始终记住:增广的最终目的是让训练数据分布更接近真实、不可见的测试数据分布。选择哪种增广方法,很大程度上取决于你的数据集和任务本身的特点。

http://www.dtcms.com/a/428446.html

相关文章:

  • 学院网站建设项目的活动分解沟通交流类网站有哪些
  • 吕梁建站公司大连网站制作公司
  • 吉安网站推广软文营销定义
  • web前端团队开发code review方案最佳实践
  • 张槎网站建设企业网站建设与管理作业
  • 网站找什么公司做网站开发的难点
  • Android Studio | 设置国内代理(SDK 设置国内代理(阿里云镜像))
  • 怎么注销建设银行网站用户名设计网站费用多少
  • 【更新至2024年】1999-2024年上市公司数字化转型程度数据(含原始数据+计算代码+结果)
  • 优化网站建设哪家专业wordpress tag 别名
  • Android 常见界面布局详解
  • 4-创建索引和约束
  • 百度竞价网站永久免费网站虚拟主机
  • 做商城网站的广州站电话
  • 中小企业网站制作方法建网页和网站的区别
  • 【星海出品】cache和程序性能
  • 国外设计网站建站之星怎么收费
  • 网站建设的服务怎么样做网站必须要购买域名
  • 【武大杨景媛事件全过程】免费分享
  • 江苏001
  • 5分钟掌握现代C++多执行策略:基于DAG的任务调度系统
  • UFrame:面向规模化 Unity 项目的工程化框架
  • 西安网站优化招聘网普陀网站建设推广
  • 安卓门户网站开发wordpress 短链接插件
  • 【APK安全】组件安全核心风险与防御指南
  • 乌市网站建设为做论坛推广的网站
  • 【第五章:计算机视觉-项目实战之图像分割实战】2.图像分割实战:人像抠图-(5)模型训练与测试
  • 南昌网站建设公司特色网站开发需要看哪些书
  • 网站建设的建议高端自适应网站建设
  • petalinux 安装Armadillo