手學(xué)深度學(xué)習(xí)》圖像增廣(Image Augmentation)全解析:常用方法、CIFAR-10 實(shí)戰(zhàn)與多 GPU 訓(xùn)練)
人工智能深度學(xué)習(xí)機(jī)器學(xué)習(xí)教程【免費(fèi)下載鏈接】d2l-zh《動(dòng)手學(xué)深度學(xué)習(xí)》面向中文讀者、能運(yùn)行、可討論。中英文版被70多個(gè)國(guó)家的500多所大學(xué)用于教學(xué)。項(xiàng)目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh點(diǎn)擊查看免費(fèi)下載圖像增廣Image Augmentation是深度學(xué)習(xí)計(jì)算機(jī)視覺(jué)訓(xùn)練中提升泛化能力、緩解過(guò)擬合的核心手段它通過(guò)對(duì)訓(xùn)練圖像施加一系列隨機(jī)變換生成相似但不同的新樣本既擴(kuò)大了訓(xùn)練集的規(guī)模又降低了模型對(duì)目標(biāo)位置、顏色等屬性的依賴(lài)。本文以《動(dòng)手學(xué)深度學(xué)習(xí)》第 13 章 圖像增廣章節(jié) 為骨架結(jié)合倉(cāng)庫(kù) d2l 工具庫(kù) 的源碼實(shí)現(xiàn)系統(tǒng)講解左右/上下翻轉(zhuǎn)、隨機(jī)裁剪、顏色抖動(dòng)亮度/對(duì)比度/飽和度/色調(diào)以及Compose組合等常用方法并完整演示如何在 CIFAR-10 數(shù)據(jù)集上配合 ResNet-18 與多 GPU 訓(xùn)練流程讓讀者獲得一套可直接復(fù)制運(yùn)行的圖像增廣實(shí)戰(zhàn)方案。為什么要做圖像增廣概念與動(dòng)機(jī)在 AlexNet 章節(jié) 中已經(jīng)強(qiáng)調(diào)大型數(shù)據(jù)集是成功應(yīng)用深度神經(jīng)網(wǎng)絡(luò)的先決條件。圖像增廣正是無(wú)中生有地?cái)U(kuò)充訓(xùn)練數(shù)據(jù)的關(guān)鍵手段它在對(duì)訓(xùn)練圖像進(jìn)行一系列隨機(jī)變化之后生成相似但不同的訓(xùn)練樣本從而擴(kuò)大訓(xùn)練集規(guī)模。除了擴(kuò)充數(shù)據(jù)量圖像增廣還有一個(gè)更深層的作用——降低模型對(duì)某些屬性的依賴(lài)提高泛化能力以不同方式裁剪圖像可以讓感興趣的對(duì)象出現(xiàn)在不同位置從而減少模型對(duì)對(duì)象出現(xiàn)位置的依賴(lài)調(diào)整亮度、顏色等因素可以降低模型對(duì)顏色的敏感度。從歷史上看圖像增廣技術(shù)對(duì) AlexNet 的成功幾乎是必不可少的——它讓深度卷積網(wǎng)絡(luò)在有限的數(shù)據(jù)上獲得了足夠強(qiáng)的魯棒性??梢哉J(rèn)為本節(jié)討論的技術(shù)是整個(gè)計(jì)算機(jī)視覺(jué)CV領(lǐng)域被使用最廣泛的數(shù)據(jù)處理手段之一。實(shí)驗(yàn)環(huán)境準(zhǔn)備三種深度學(xué)習(xí)框架的導(dǎo)入方式本書(shū)的代碼以#tab標(biāo)簽區(qū)分不同深度學(xué)習(xí)框架分別使用 MXNet/Gluon、PyTorch 與飛槳 Paddle 實(shí)現(xiàn)同一套功能。本節(jié)示例均通過(guò)d2l工具包倉(cāng)庫(kù)中對(duì)應(yīng) d2l/torch.py、d2l/mxnet.py、d2l/paddle.py提供統(tǒng)一的高層封裝。# MXNet / Gluon %matplotlib inline from d2l import mxnet as d2l from mxnet import autograd, gluon, image, init, np, npx from mxnet.gluon import nn npx.set_np()# PyTorch %matplotlib inline from d2l import torch as d2l import torch import torchvision from torch import nn# Paddle %matplotlib inline from d2l import paddle as d2l import warnings warnings.filterwarnings(ignore) import paddle import paddle.vision as paddlevision from paddle import nn接下來(lái)使用一張尺寸為 400×500 的圖像即倉(cāng)庫(kù)中的 img/cat1.jpg作為演示原圖# MXNet d2l.set_figsize() img image.imread(../img/cat1.jpg) d2l.plt.imshow(img.asnumpy());# PyTorch / Paddle d2l.set_figsize() img d2l.Image.open(../img/cat1.jpg) d2l.plt.imshow(img);可視化輔助函數(shù)apply一次查看多次增廣結(jié)果大多數(shù)圖像增廣方法都具有一定的隨機(jī)性。為了便于觀察增廣效果本章定義了一個(gè)輔助函數(shù)apply它會(huì)在輸入圖像img上多次運(yùn)行同一個(gè)圖像增廣方法aug并將所有結(jié)果以網(wǎng)格形式展示出來(lái)。num_rows × num_cols決定了展示的總張數(shù)scale控制每張子圖的顯示比例#tab all def apply(img, aug, num_rows2, num_cols4, scale1.5): Y [aug(img) for _ in range(num_rows * num_cols)] d2l.show_images(Y, num_rows, num_cols, scalescale)這里的d2l.show_images在 d2l/torch.py 中實(shí)現(xiàn)負(fù)責(zé)將圖像列表排版為num_rows × num_cols的子圖網(wǎng)格并隱藏坐標(biāo)軸。常用圖像增廣方法一翻轉(zhuǎn)與裁剪左右翻轉(zhuǎn)最經(jīng)典的位置增廣左右翻轉(zhuǎn)圖像通常不會(huì)改變對(duì)象的類(lèi)別因此是最早且使用最廣泛的增廣方法之一。下面是三框架中各 50% 概率向左或向右翻轉(zhuǎn)的寫(xiě)法# MXNet apply(img, gluon.data.vision.transforms.RandomFlipLeftRight())# PyTorch apply(img, torchvision.transforms.RandomHorizontalFlip())# Paddle apply(img, paddlevision.transforms.RandomHorizontalFlip())上下翻轉(zhuǎn)需謹(jǐn)慎使用上下翻轉(zhuǎn)不如左右翻轉(zhuǎn)常用但對(duì)于某些類(lèi)別例如示例中的貓上下翻轉(zhuǎn)同樣不會(huì)妨礙識(shí)別。三框架對(duì)應(yīng)的實(shí)現(xiàn)為# MXNet apply(img, gluon.data.vision.transforms.RandomFlipTopBottom())# PyTorch apply(img, torchvision.transforms.RandomVerticalFlip())# Paddle apply(img, paddlevision.transforms.RandomVerticalFlip())隨機(jī)裁剪打破目標(biāo)位置的敏感性示例圖像中貓位于畫(huà)面中間但真實(shí)數(shù)據(jù)并非總是如此。在 匯聚層章節(jié) 中我們了解到匯聚層可以降低卷積層對(duì)目標(biāo)位置的敏感性而隨機(jī)裁剪則是另一種降低位置敏感性的手段——它讓物體以不同的比例出現(xiàn)在圖像的不同位置。下面的代碼隨機(jī)裁剪一個(gè)面積為原始面積 10% 到 100% 的區(qū)域區(qū)域的寬高比在 0.52 之間隨機(jī)取值隨后將裁剪區(qū)域的寬度和高度都縮放為 200 像素# MXNet shape_aug gluon.data.vision.transforms.RandomResizedCrop( (200, 200), scale(0.1, 1), ratio(0.5, 2)) apply(img, shape_aug)# PyTorch shape_aug torchvision.transforms.RandomResizedCrop( (200, 200), scale(0.1, 1), ratio(0.5, 2)) apply(img, shape_aug)# Paddle shape_aug paddlevision.transforms.RandomResizedCrop( (200, 200), scale(0.1, 1), ratio(0.5, 2)) apply(img, shape_aug)參數(shù)說(shuō)明scale(0.1, 1)隨機(jī)裁剪區(qū)域面積占原圖面積的比例范圍10%100%在該區(qū)間內(nèi)均勻采樣ratio(0.5, 2)裁剪區(qū)域的寬高比范圍同樣均勻采樣(200, 200)裁剪后統(tǒng)一縮放到的輸出尺寸。本書(shū)約定除非另有說(shuō)明$a$ 和 $b$ 之間的隨機(jī)數(shù)指的是在區(qū)間 $[a, b]$ 中通過(guò)均勻采樣獲得的連續(xù)值。常用圖像增廣方法二改變顏色顏色增廣可以改變圖像的四個(gè)方面亮度brightness、對(duì)比度contrast、飽和度saturation和色調(diào)hue。隨機(jī)改變亮度下面的示例將亮度在原始值的 50%$1-0.5$到 150%$10.5$之間隨機(jī)調(diào)整# MXNet apply(img, gluon.data.vision.transforms.RandomBrightness(0.5))# PyTorch apply(img, torchvision.transforms.ColorJitter( brightness0.5, contrast0, saturation0, hue0))# Paddle apply(img, paddlevision.transforms.ColorJitter( brightness0.5, contrast0, saturation0, hue0))隨機(jī)改變色調(diào)類(lèi)似地可以單獨(dú)隨機(jī)更改色調(diào)參數(shù)hue0.5表示色調(diào)偏移量為 50%# MXNet apply(img, gluon.data.vision.transforms.RandomHue(0.5))# PyTorch apply(img, torchvision.transforms.ColorJitter( brightness0, contrast0, saturation0, hue0.5))# Paddle apply(img, paddlevision.transforms.ColorJitter( brightness0, contrast0, saturation0, hue0.5))同時(shí)改變四個(gè)方面創(chuàng)建一個(gè)RandomColorJitter/ColorJitter實(shí)例可以同時(shí)隨機(jī)更改亮度、對(duì)比度、飽和度和色調(diào)。這里四個(gè)參數(shù)全部取 0.5即各自在 50%150%或?qū)?yīng)幅度范圍內(nèi)隨機(jī)擾動(dòng)# MXNet color_aug gluon.data.vision.transforms.RandomColorJitter( brightness0.5, contrast0.5, saturation0.5, hue0.5) apply(img, color_aug)# PyTorch color_aug torchvision.transforms.ColorJitter( brightness0.5, contrast0.5, saturation0.5, hue0.5) apply(img, color_aug)# Paddle color_aug paddlevision.transforms.ColorJitter( brightness0.5, contrast0.5, saturation0.5, hue0.5) apply(img, color_aug)結(jié)合多種圖像增廣方法Compose 流水線(xiàn)實(shí)踐中我們幾乎總是組合多種增廣方法使用。三框架均通過(guò)Compose將一組變換按順序串聯(lián)依次作用于每一張圖像。下面將前面定義的隨機(jī)左右翻轉(zhuǎn)、顏色抖動(dòng)color_aug與隨機(jī)裁剪shape_aug組合起來(lái)# MXNet augs gluon.data.vision.transforms.Compose([ gluon.data.vision.transforms.RandomFlipLeftRight(), color_aug, shape_aug]) apply(img, augs)# PyTorch augs torchvision.transforms.Compose([ torchvision.transforms.RandomHorizontalFlip(), color_aug, shape_aug]) apply(img, augs)# Paddle augs paddlevision.transforms.Compose([ paddle.vision.transforms.RandomHorizontalFlip(), color_aug, shape_aug]) apply(img, augs)Compose中的變換按書(shū)寫(xiě)順序依次執(zhí)行前一個(gè)變換的輸出作為后一個(gè)變換的輸入。合理編排順序例如先隨機(jī)裁剪再改顏色可以組合出更豐富的樣本分布。使用圖像增廣進(jìn)行訓(xùn)練CIFAR-10 實(shí)戰(zhàn)為什么選擇 CIFAR-10 而不是 Fashion-MNIST本節(jié)訓(xùn)練實(shí)驗(yàn)選用CIFAR-10數(shù)據(jù)集而非之前章節(jié)反復(fù)使用的 Fashion-MNIST。原因在于Fashion-MNIST 中對(duì)象的位置和大小已被規(guī)范化而 CIFAR-10 中對(duì)象的顏色和大小差異更明顯因而更能體現(xiàn)圖像增廣的收益。先查看 CIFAR-10 訓(xùn)練集中前 32 張圖像# MXNet d2l.show_images(gluon.data.vision.CIFAR10( trainTrue)[0:32][0], 4, 8, scale0.8);# PyTorch all_images torchvision.datasets.CIFAR10(trainTrue, root../data, downloadTrue) d2l.show_images([all_images[i][0] for i in range(32)], 4, 8, scale0.8);# Paddle all_images paddlevision.datasets.Cifar10(modetrain , downloadTrue) print(len(all_images)) d2l.show_images([all_images[i][0] for i in range(32)], 4, 8, scale0.8);訓(xùn)練集與測(cè)試集使用不同的增廣策略一個(gè)關(guān)鍵原則是為了在預(yù)測(cè)時(shí)獲得確切、可復(fù)現(xiàn)的結(jié)果通常只對(duì)訓(xùn)練樣本做圖像增廣預(yù)測(cè)測(cè)試階段不使用帶隨機(jī)操作的增廣。這里訓(xùn)練集只使用最簡(jiǎn)單的隨機(jī)左右翻轉(zhuǎn)測(cè)試集不做任何增廣兩類(lèi)流水線(xiàn)末尾都追加ToTensor將一批圖像轉(zhuǎn)換為深度學(xué)習(xí)框架要求的格式——形狀為批量大小通道數(shù)高度寬度的 32 位浮點(diǎn)數(shù)取值 01# MXNet train_augs gluon.data.vision.transforms.Compose([ gluon.data.vision.transforms.RandomFlipLeftRight(), gluon.data.vision.transforms.ToTensor()]) test_augs gluon.data.vision.transforms.Compose([ gluon.data.vision.transforms.ToTensor()])# PyTorch train_augs torchvision.transforms.Compose([ torchvision.transforms.RandomHorizontalFlip(), torchvision.transforms.ToTensor()]) test_augs torchvision.transforms.Compose([ torchvision.transforms.ToTensor()])# Paddle train_augs paddlevision.transforms.Compose([ paddlevision.transforms.RandomHorizontalFlip(), paddlevision.transforms.ToTensor()]) test_augs paddlevision.transforms.Compose([ paddlevision.transforms.ToTensor()])數(shù)據(jù)加載函數(shù)load_cifar10接下來(lái)定義輔助函數(shù)將圖像讀取與增廣管線(xiàn)綁定到數(shù)據(jù)集上并返回配置好批量大小、打亂策略與并行讀取進(jìn)程數(shù)的DataLoaderMXNettransform_first將增廣應(yīng)用于每個(gè)訓(xùn)練樣本的第一個(gè)元素即圖像并行讀取進(jìn)程數(shù)由d2l.get_dataloader_workers()提供在 d2l/mxnet.py 中實(shí)現(xiàn)默認(rèn)使用 4 個(gè)進(jìn)程PyTorch通過(guò)數(shù)據(jù)集的transform參數(shù)應(yīng)用增廣Paddle同樣通過(guò)transform參數(shù)應(yīng)用增廣。# MXNet def load_cifar10(is_train, augs, batch_size): return gluon.data.DataLoader( gluon.data.vision.CIFAR10(trainis_train).transform_first(augs), batch_sizebatch_size, shuffleis_train, num_workersd2l.get_dataloader_workers())# PyTorch def load_cifar10(is_train, augs, batch_size): dataset torchvision.datasets.CIFAR10(root../data, trainis_train, transformaugs, downloadTrue) dataloader torch.utils.data.DataLoader(dataset, batch_sizebatch_size, shuffleis_train, num_workersd2l.get_dataloader_workers()) return dataloader# Paddle def load_cifar10(is_train, augs, batch_size): dataset paddlevision.datasets.Cifar10(modetrain, transformaugs, downloadTrue) dataloader paddle.io.DataLoader(dataset, batch_sizebatch_size, num_workersd2l.get_dataloader_workers(), shuffleis_train) return dataloaderd2l.get_dataloader_workers()在 d2l/torch.py 中固定返回 4 個(gè)進(jìn)程用于數(shù)據(jù)并行讀取。多 GPU 小批量訓(xùn)練train_batch_ch13本章在 CIFAR-10 上訓(xùn)練 ResNet 章節(jié) 中的ResNet-18模型并復(fù)用 多 GPU 訓(xùn)練章節(jié) 的多 GPU 訓(xùn)練范式。下面定義多 GPU 小批量訓(xùn)練函數(shù)這些函數(shù)以#save標(biāo)記保存后續(xù)章節(jié)會(huì)繼續(xù)復(fù)用MXNet 版本將批量按設(shè)備切分split_fd2l.split_batch在多個(gè)設(shè)備上分別前向傳播、分別反向傳播并使用ignore_stale_gradTrue允許使用過(guò)時(shí)梯度這在微調(diào) BERT 等場(chǎng)景中很有用#save def train_batch_ch13(net, features, labels, loss, trainer, devices, split_fd2l.split_batch): 用多GPU進(jìn)行小批量訓(xùn)練 X_shards, y_shards split_f(features, labels, devices) with autograd.record(): pred_shards [net(X_shard) for X_shard in X_shards] ls [loss(pred_shard, y_shard) for pred_shard, y_shard in zip(pred_shards, y_shards)] for l in ls: l.backward() # True標(biāo)志允許使用過(guò)時(shí)的梯度這很有用例如在微調(diào)BERT中 trainer.step(labels.shape[0], ignore_stale_gradTrue) train_loss_sum sum([float(l.sum()) for l in ls]) train_acc_sum sum(d2l.accuracy(pred_shard, y_shard) for pred_shard, y_shard in zip(pred_shards, y_shards)) return train_loss_sum, train_acc_sumPyTorch 版本將數(shù)據(jù)統(tǒng)一放到devices[0]上借助nn.DataParallel自動(dòng)并行前向與反向#save def train_batch_ch13(net, X, y, loss, trainer, devices): 用多GPU進(jìn)行小批量訓(xùn)練 if isinstance(X, list): # 微調(diào)BERT中所需 X [x.to(devices[0]) for x in X] else: X X.to(devices[0]) y y.to(devices[0]) net.train() trainer.zero_grad() pred net(X) l loss(pred, y) l.sum().backward() trainer.step() train_loss_sum l.sum() train_acc_sum d2l.accuracy(pred, y) return train_loss_sum, train_acc_sumPaddle 版本同樣將數(shù)據(jù)放到devices[0]對(duì)應(yīng)的設(shè)備上飛槳暫不支持在 notebook 上進(jìn)行多 GPU 訓(xùn)練#save def train_batch_ch13(net, X, y, loss, trainer, devices): 用多GPU進(jìn)行小批量訓(xùn)練 飛槳不支持在notebook上進(jìn)行多GPU訓(xùn)練 Defined in :numref:sec_image_augmentation if isinstance(X, list): # 微調(diào)BERT中所需稍后討論 X [paddle.to_tensor(x, placedevices[0]) for x in X] else: X paddle.to_tensor(X, placedevices[0]) y paddle.to_tensor(y, placedevices[0]) net.train() trainer.clear_grad() pred net(X) l loss(pred, y) l.sum().backward() trainer.step() train_loss_sum l.sum() train_acc_sum d2l.accuracy(pred, y) return train_loss_sum, train_acc_sum完整訓(xùn)練循環(huán)train_ch13train_ch13負(fù)責(zé)多 GPU 下的完整訓(xùn)練流程維護(hù)訓(xùn)練損失、訓(xùn)練準(zhǔn)確度、實(shí)例數(shù)、樣本數(shù)四維累加器d2l.Accumulator(4)每個(gè) epoch 內(nèi)周期性更新動(dòng)畫(huà)曲線(xiàn)并在每個(gè) epoch 結(jié)束時(shí)用 GPU 評(píng)估測(cè)試準(zhǔn)確率最后打印平均損失、訓(xùn)練/測(cè)試準(zhǔn)確率與吞吐量examples/sec#save def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devicesd2l.try_all_gpus(), split_fd2l.split_batch): 用多GPU進(jìn)行模型訓(xùn)練 timer, num_batches d2l.Timer(), len(train_iter) animator d2l.Animator(xlabelepoch, xlim[1, num_epochs], ylim[0, 1], legend[train loss, train acc, test acc]) for epoch in range(num_epochs): # 4個(gè)維度儲(chǔ)存訓(xùn)練損失訓(xùn)練準(zhǔn)確度實(shí)例數(shù)特點(diǎn)數(shù) 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, split_f) metric.add(l, acc, labels.shape[0], labels.size) 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_gpus(net, test_iter, split_f) animator.add(epoch 1, (None, None, test_acc)) print(floss {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)})PyTorch 版本將網(wǎng)絡(luò)包裝為nn.DataParallel(net, device_idsdevices)以利用全部 GPU并用d2l.evaluate_accuracy_gpu在 GPU 上評(píng)估該函數(shù)在 d2l/torch.py 中實(shí)現(xiàn)評(píng)估前會(huì)自動(dòng)切換到net.eval()模式Paddle 版本使用paddle.DataParallel(net)#save def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devicesd2l.try_all_gpus()): 用多GPU進(jìn)行模型訓(xùn)練 timer, num_batches d2l.Timer(), len(train_iter) animator d2l.Animator(xlabelepoch, xlim[1, num_epochs], ylim[0, 1], legend[train loss, train acc, test acc]) net nn.DataParallel(net, device_idsdevices).to(devices[0]) for epoch in range(num_epochs): # 4個(gè)維度儲(chǔ)存訓(xùn)練損失訓(xùn)練準(zhǔn)確度實(shí)例數(shù)特點(diǎn)數(shù) 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(floss {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)})組裝訓(xùn)練train_with_data_aug最后定義train_with_data_aug函數(shù)獲取所有可用 GPUd2l.try_all_gpus()在 d2l/torch.py 中實(shí)現(xiàn)無(wú) GPU 時(shí)回退到 CPU構(gòu)建 ResNet-18 并用 Xavier 初始化權(quán)重使用Adam優(yōu)化器學(xué)習(xí)率 0.001將圖像增廣作用于訓(xùn)練集訓(xùn)練 10 個(gè) epoch# MXNet batch_size, devices, net 256, d2l.try_all_gpus(), d2l.resnet18(10) net.initialize(initinit.Xavier(), ctxdevices) def train_with_data_aug(train_augs, test_augs, net, lr0.001): train_iter load_cifar10(True, train_augs, batch_size) test_iter load_cifar10(False, test_augs, batch_size) loss gluon.loss.SoftmaxCrossEntropyLoss() trainer gluon.Trainer(net.collect_params(), adam, {learning_rate: lr}) train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices)# PyTorch 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]: nn.init.xavier_uniform_(m.weight) net.apply(init_weights) def train_with_data_aug(train_augs, test_augs, net, lr0.001): train_iter load_cifar10(True, train_augs, batch_size) test_iter load_cifar10(False, test_augs, batch_size) loss nn.CrossEntropyLoss(reductionnone) trainer torch.optim.Adam(net.parameters(), lrlr) train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices)# Paddle 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]: nn.initializer.XavierUniform(m.weight) net.apply(init_weights) def train_with_data_aug(train_augs, test_augs, net, lr0.001): train_iter load_cifar10(True, train_augs, batch_size) test_iter load_cifar10(False, test_augs, batch_size) loss nn.CrossEntropyLoss(reductionnone) trainer paddle.optimizer.Adam(learning_ratelr, parametersnet.parameters()) train_ch13(net, train_iter, test_iter, loss, trainer, 10, devices[:1])幾點(diǎn)說(shuō)明倉(cāng)庫(kù)中的d2l.resnet18是稍加修改的 ResNet-18見(jiàn) d2l/torch.py使用了更小的卷積核3×3步長(zhǎng) 1填充 1、刪除了最大匯聚層輸入通道數(shù)通過(guò)參數(shù)in_channels指定PyTorch/Paddle 版本傳入3以匹配彩色圖像輸出類(lèi)別數(shù)為 10對(duì)應(yīng) CIFAR-10 的 10 個(gè)類(lèi)別批量大小為 256數(shù)據(jù)讀取采用 4 個(gè)并行進(jìn)程d2l.get_dataloader_workersPaddle 版本訓(xùn)練時(shí)僅使用devices[:1]的單個(gè)設(shè)備。最后使用前面定義的隨機(jī)左右翻轉(zhuǎn)增廣管線(xiàn)train_augs/test_augs直接啟動(dòng)訓(xùn)練#tab all train_with_data_aug(train_augs, test_augs, net)訓(xùn)練結(jié)束后會(huì)輸出類(lèi)似loss X.XXX, train acc X.XXX, test acc X.XXX以及X.X examples/sec on [...]的結(jié)果用于與不使用增廣的基線(xiàn)對(duì)比。小結(jié)圖像增廣基于現(xiàn)有的訓(xùn)練數(shù)據(jù)生成隨機(jī)圖像從而提高模型的泛化能力為了在預(yù)測(cè)過(guò)程中得到確切的結(jié)果通常只對(duì)訓(xùn)練樣本進(jìn)行圖像增廣預(yù)測(cè)階段不使用帶隨機(jī)操作的增廣深度學(xué)習(xí)框架MXNet/Gluon、PyTorch、Paddle提供了大量不同的圖像增廣方法這些方法可以通過(guò)Compose被同時(shí)應(yīng)用。練習(xí)與延伸思考驗(yàn)證增廣的收益在不使用圖像增廣的情況下訓(xùn)練模型即執(zhí)行train_with_data_aug(no_aug, no_aug)并與使用增廣的訓(xùn)練結(jié)果、測(cè)試精度對(duì)比。這個(gè)對(duì)比實(shí)驗(yàn)?zāi)芊裰С謭D像增廣可以減輕過(guò)擬合的論點(diǎn)為什么組合多種增廣在基于 CIFAR-10 的模型訓(xùn)練中同時(shí)組合多種不同的圖像增廣方法翻轉(zhuǎn)、隨機(jī)裁剪、顏色抖動(dòng)等能否進(jìn)一步提高測(cè)試準(zhǔn)確率可嘗試調(diào)整scale、ratio、抖動(dòng)幅度等超參數(shù)觀察變化。探索更多方法查閱你所使用深度學(xué)習(xí)框架torchvision.transforms 對(duì)應(yīng)的 PyTorch 生態(tài)、飛槳paddlevision.transforms、Gluongluon.data.vision.transforms的在線(xiàn)文檔了解它還提供了哪些其他圖像增廣方法例如旋轉(zhuǎn)、縮放、仿射變換、灰度化、高斯模糊、隨機(jī)擦除等并思考它們適用于哪些場(chǎng)景。附相關(guān)章節(jié)與倉(cāng)庫(kù)資源索引本文所屬章節(jié)chapter_computer-vision/image-augmentation.md圖像增廣的多 GPU 訓(xùn)練基礎(chǔ)多 GPU 訓(xùn)練簡(jiǎn)潔實(shí)現(xiàn)ResNet-18 模型定義ResNet 章節(jié)及倉(cāng)庫(kù)源碼 d2l/torch.py、d2l/mxnet.py、d2l/paddle.py工具函數(shù)實(shí)現(xiàn)show_imagesd2l/torch.py、try_all_gpusd2l/torch.py、evaluate_accuracy_gpud2l/torch.py示例原圖img/cat1.jpg贊分享人工智能深度學(xué)習(xí)機(jī)器學(xué)習(xí)教程【免費(fèi)下載鏈接】d2l-zh《動(dòng)手學(xué)深度學(xué)習(xí)》面向中文讀者、能運(yùn)行、可討論。中英文版被70多個(gè)國(guó)家的500多所大學(xué)用于教學(xué)。項(xiàng)目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh點(diǎn)擊查看免費(fèi)下載相關(guān)推薦《動(dòng)手學(xué)深度學(xué)習(xí)》實(shí)戰(zhàn)Kaggle 圖像分類(lèi)競(jìng)賽 CIFAR-10 全流程指南《動(dòng)手學(xué)深度學(xué)習(xí)》實(shí)戰(zhàn)Kaggle 圖像分類(lèi)競(jìng)賽 CIFAR 10 全流程指南 本指南基于《動(dòng)手學(xué)深度學(xué)習(xí)》d2l zh倉(cāng)庫(kù)中的 kaggle cifar人工智能深度學(xué)習(xí)機(jī)器學(xué)習(xí)教程PaddlePaddle深度學(xué)習(xí)實(shí)戰(zhàn)Kaggle CIFAR-10圖像分類(lèi)競(jìng)賽全流程解析PaddlePaddle深度學(xué)習(xí)實(shí)戰(zhàn)Kaggle CIFAR 10圖像分類(lèi)競(jìng)賽全流程解析 引言 計(jì)算機(jī)視覺(jué)是深度學(xué)習(xí)最重要的應(yīng)用領(lǐng)域之一而圖像分類(lèi)作為計(jì)算機(jī)文檔教程人工智能深度學(xué)習(xí)從提示詞到 PPTX 只要 10 分鐘Presenton 本地 AI 演示文稿生成器上手指南從提示詞到 PPTX 只要 10 分鐘Presenton 本地 AI 演示文稿生成器上手指南 周五晚上還在改 PPT 字體或者臨時(shí)被拉去分享手里卻沒(méi)有現(xiàn)成人工智能深度學(xué)習(xí)機(jī)器學(xué)習(xí)教程上一篇NASA ICER算法從論文到代碼icer_compression實(shí)現(xiàn)原理深度解讀下一篇MaterialScrollBar核心組件探秘AlphabetIndicator與DateAndTimeIndicator使用指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考