掘金 人工智能 前天 11:28
8-1 图像增广
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了如何使用PyTorch中的torchvision库实现图像增广技术,以提升模型的泛化能力。文章首先阐述了数据增强的作用,并通过代码示例展示了左右翻转、随机裁剪、颜色抖动等多种增广方法的应用。随后,文章详细讲解了CIFAR-10数据集的加载、模型(ResNet)的定义、参数初始化(Xavier均匀分布)以及训练过程中的关键步骤,包括设置训练模式、计算损失、反向传播和参数更新。最后,通过训练函数展示了整个模型的训练流程,并重点解释了损失和准确率的计算方法,为读者提供了实践指导。

✨ 数据增强通过调节训练样本,能够有效增加模型的泛化能力,从而提升模型在未见过数据上的表现。文章介绍了torchvision.transforms中多种增广方法,如RandomHorizontalFlip、RandomVerticalFlip、RandomResizedCrop和ColorJitter,并展示了如何使用Compose将多个增广操作组合使用。

📦 文章详细展示了使用PyTorch加载CIFAR-10数据集的步骤,包括下载数据集、查看样本以及构建数据加载器。特别地,它强调了只对训练集进行数据增广,而测试集仅进行ToTensor转换,并解释了DataLoader分批次加载数据以避免内存溢出的原理。

🚀 模型训练部分采用了ResNet18模型,并使用Xavier均匀分布初始化权重,以促进模型收敛。在训练过程中,通过net.train()将模型设置为训练模式,激活Dropout和批量归一化等正则化技术,并通过Adam优化器进行参数更新,最终实现了模型在训练集和测试集上的准确率评估。

📊 训练过程的可视化使用了d2l库的Animator,能够直观地展示每个epoch的训练损失、训练准确率和测试准确率的变化趋势。同时,文章对训练过程中损失和准确率的计算逻辑进行了详细解释,包括平均损失的计算(总损失/总样本数)和训练准确率的计算(总正确预测数/总样本数),帮助理解模型性能的评估指标。

一. 作用

图像增广可以通过调节训练样本,从而增加模型的泛化能力。

二. 代码

通过torchvision.transforms 实现

作用函数
左右翻转RandomHorizontalFlip()
上下翻转RandomVerticalFlip()
随机裁剪RandomResizedCrop((width,height),scale=(0.1,1), ratio=())
改变颜色ColorJitter(brightness=0.5,contrast=0,saturation=0,hue=0)
多种结合Compose([ ])

注:

    scale 代表相对原始面积的缩放比例,示例中设置的 10%-100%ratio 代表宽高比,0.5-2brightness 代表亮度contrast 代表对比度saturation 代表饱和度hue 代表色调

三. 具体实现

3.1 数据预处理

数据集下载与查看

从torchvision的datasets中下载 CIFAR-10 数据集(10 分类,50000 张图片),并用 0.8 的比例查看前 32 个训练样本。

all_images = torchvision.datasets.CIFAR10(root='data/CIFAR',train=True,download=True)d2l.show_images([all_images[i][0] for i in range(32)],4,8,scale=0.8)

加载数据集

我们只针对训练样本进行增广,这里我们只使用最简单的随机左右翻转,并利用 ToTensor 实例将一批图像转换为深度学习框架所需要的格式,即形状为(批量大小,通道数,高度,宽度)的 32位浮点数,取值范围为 0-1。

train_augs = torchvision.transforms.Compose([    torchvision.transforms.RandomHorizontalFlip(),    torchvision.transforms.ToTensor(),])test_augs = torchvision.transforms.Compose([    torchvision.transforms.ToTensor(),])

封装加载数据函数,在读取数据阶段,进行数据的预处理(通过transform 设置参数),并加载相应批量的数据。

def load_cifar10(is_train,augs,batch_size):    dataset = torchvision.datasets.CIFAR10(root='data/CIFAR',train=is_train,download=True,transform=augs)    dataloader = torch.utils.data.DataLoader(dataset,batch_size=batch_size,shuffle=True,num_workers=d2l.get_dataloader_workers())    return dataloader

注意这里对于 dataloader 的理解:

对于 Dataloader 主要为了避免把过度数据加载到内存,而导致内存溢出,从而分批次的加载数据,也就是 batch_size, 同时利用len(train_iter)也可以查看批次的数量,比如对于 50000 的数据,如果 batch_size 等于 5000,那么 len(train_iter) 就等于 10

另外,也可以通过 enumerate 方法对于每个批次进行迭代, 如下图,每次返回的是10000 批次的数据,一共迭代 5 次。

3.2 模型定义与选择

这里采用resnet 模型(10 类,3 个通道),通过调用d2l 中对应的代码

3.3 模型初始化

设置每次批次的大小的 256,采用 gpu 和 resnet 模型

之后进行模型参数初始化,如果当前层是线性层(nn.Linear)或二维卷积层(nn.Conv2d),就使用 Xavier 均匀分布(xavier_uniform_)初始化该层的权重

Xavier 初始化的优点是可以让网络中信号的正向传播和反向传播时的方差尽可能一致,有助于加快模型收敛

batch_size, devices, net = 256,[ torch.device("gpu")], d2l.resnet18(10, 3)def init_weights(m):    if type(m) in [nn.Linear, nn.Conv2d]:        nn.init.xavier_uniform_(m.weight)net.apply(init_weights)

3.4 模型训练

单批量训练

1)设置为训练模式

通过net.train() 设置模型为训练模式,此时会激活 dropout,批量归一化

注:

    dropout 是一种常见的正则化技术,通过随机丢弃一些节点,限制模型复杂度,以及对于某个节点的过度依赖,导致模型过拟合。批量归一化通常用于卷积层或全连接层之后、激活函数之前,对层的输入进行归一化处理,为激活函数提供更稳定的输入分布,从而实现加速训练收敛
2)计算模型损失

初始化优化器的梯度,并计算 loss,并利用反向传播,更新模型参数,同时统计 loss 和 acc

def train_batch_ch13(net, X, y, loss, trainer, device):    if isinstance(X, list):        X = [x.to(cpu_device) for x in X]    else:        X = X.to(cpu_device)    y = y.to(cpu_device)    net.train()    trainer.zero_grad()    pred = net(X)    l = loss(pred, y)    # 自动计算损失 l 对模型所有可训练参数(w、b等)的梯度    l.sum().backward()    # 根据梯度更新参数    trainer.step()    train_loss_sum = l.sum()    train_acc_sum = d2l.accuracy(pred, y)    return train_loss_sum, train_acc_sum

数据集训练

设置相应的轮次,并显示不同轮次的总损失,以及训练集和测试集的准确率。

其中metric的意思是衡量标准,主要存储了训练损失,训练准确度,实例数以及特征数。

animator 是d2l 库中的可视化部分,同时设置按 1/5 间隔更新,既能反映训练趋势,又不会丢失关键信息。

def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices):    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'])    net = nn.DataParallel(net,device_ids=devices).to(devices[0])    for epoch in range(num_epochs):        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()            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))        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)}')

注意对于上述代码:

1. metric[0] / metric[2](计算平均损失)

2. metric[1] / metric[3](计算训练准确率)

3. test_acc(展示测试准确率)

下面的就是调用,同时定义数据和优化器,主要采用 Adam 进行优化。

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)    loss = nn.CrossEntropyLoss(reduction="none")    trainer = torch.optim.Adam(net.parameters(), lr=lr)    train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices)

开始训练数据:

train_with_data_aug(train_augs, test_augs, net)

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

PyTorch 数据增强 CIFAR-10 模型训练 深度学习
相关文章