cifar10分类Java_Mxnet (31): 使用图像增强训练CIFAR-10数据集

本文介绍了如何使用Java MXNet进行CIFAR-10图像分类,重点展示了图像增强技术,如翻转、剪切、颜色调整等,以提升模型的泛化能力。通过实例演示了不同增强方法对图像的影响,并提供了训练模型的代码示例。
摘要由CSDN通过智能技术生成

图像增强技术通过对训练图像进行一系列随机更改以生成相似但不同的训练示例来扩展训练数据集的规模。并且随机更改一些示例可以有效的减小模型对某些属性的依赖,提高模型的泛化能力:

通过不同的方式裁剪图像,可以使刚兴趣的对象出现在不同位置,减小模型对位置的依赖

通过对图片颜色的调节,降低模型对颜色的敏感度。

from d2l import mxnet as d2l

from mxnet import autograd, init, np, npx, gluon, image

from mxnet.gluon import nn

from plotly import express as px, graph_objs as go

from IPython.display import Image

import plotly.io as pio

pio.kaleido.scope.default_format = "svg"

npx.set_np()

使用形状为400×500的猫咪图片作为例子。

img = image.imread('img/cat1.jpg')

fig = px.imshow(img.asnumpy())

img_bytes = fig.to_image(format="png", engine="kaleido")

Image(img_bytes)

a7f6ba2dc52e0f87d6373ad8f4ce3b2a.png

多数图像增强的方法具有一定的随机性,编写一个方法用于展示,一个功能对图片处理多次的变化情况

from plotly.subplots import make_subplots

def show_imgs(imgs, num_rows=2, num_cols=4, scale=0.8) :

fig = make_subplots(num_rows, num_cols)

for i in range(num_rows):

for j in range(num_cols):

fig.add_trace(go.Image(z=imgs[num_rows*i+j].asnumpy()),i+1,j+1)

fig.update_xaxes(visible=False, row=i+1, col=j+1)

fig.update_yaxes(visible=False, row=i+1, col=j+1)

img_bytes = fig.to_image(format="png", scale=scale, engine="kaleido")

return Image(img_bytes)

def apply(img, aug, num_rows=2, num_cols=4, scale=0.8) :

Y = [aug(img) for _ in range(num_rows * num_cols)]

return show_imgs(Y, num_rows, num_cols, scale=scale)

1. 翻转和剪切

左右翻转图像通常不会更改对象的类别。这是最早且使用最广泛的图像增强方法之一。通过transforms模块的RandomFlipLeftRight方法以50%的概率将图片左右翻转。

apply(img, gluon.data.vision.transforms.RandomFlipLeftRight())

f8529981b3598c10ade31c565952e312.png

使用RandomFlipTopBottom方法对图像进行上下翻转,同样时50%的概率。

apply(img, gluon.data.vision.transforms.RandomFlipTopBottom())

3abd2b16a4dcfb933db50dee0a83aca3.png

通过随机剪切图像可以使对象以不同的比例出现在图像的不同位置。可以降低模型对目标对象位置的依赖,从而提高泛化能力。下面使用RandomResizedCrop方法,获取图片某一区域:

size: 剪切之后图像大小

scale:随机裁剪一个面积为原图面积的范围,默认为 ( 0.08 , 1.0 ) (0.08 ,1.0)(0.08,1.0)

ratio:随机的宽高比范围,默认$( 3/4 , 4/3)

shape_aug = gluon.data.vision.transforms.RandomResizedCrop(size=(200, 200), scale=(0.1, 1), ratio=(0.5, 2))

apply(img, shape_aug)

001ede3fc15929489af6a9166b4d4dcc.png

2. 改变图片颜色

另一中增强方式是通过颜色增强。可以通过一下四个方面更改图片的颜色:

亮度

对比度

饱和度

色相

通过RandomBrightness随机更改图片的亮度,这里的brightness参数决定亮度的随机范围:[ m a x ( 0 , 1 − b r i g h t n e s s ) , 1 + b r i g h t n e s s ] [max(0, 1 - brightness), 1 + brightness][max(0,1−brightness),1+brightness]

apply(img, gluon.data.vision.transforms.RandomBrightness(0.5))

c8e47a381284c9cdaf20c556b45e3322.png

可以通过RandomHue随机更改色调。

apply(img, gluon.data.vision.transforms.RandomHue(0.5))

103f87958218e3f15a0fa4084a7da5b1.png

可以通过RandomColorJitter,同时更改亮度,对比度,饱和度和色调。

color_aug = gluon.data.vision.transforms.RandomColorJitter(

brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)

apply(img, color_aug)

fb76d6164625c82c0054bbf9915099a6.png

3. 多种增强方式同时使用

在实践中,可以将多种的图像增强方式叠加使用。可以通过Compose将这些方法叠加在一起。

augs = gluon.data.vision.transforms.Compose([

gluon.data.vision.transforms.RandomFlipLeftRight(), color_aug, shape_aug])

apply(img, augs)

e0fbae720108b51c0fa31060c70af4e4.png

4. 使用图像增强训练模型

这里,我们使用CIFAR-10数据集,与Fashion-MNIST数据集相比,CIFAR-10数据集中的对象的颜色和大小的差异更加明显。展示数据集的前32个图像。

show_imgs(gluon.data.vision.CIFAR10(train=True)[0:32][0], 4, 8, scale=0.8)

17ff461911cc8f6263e7a053cdc9c726.png

为了在预测期间获得确定的结果,我们通常使用图片增强用于训练过程,在测试期间不使用。对于这个数据集,通过最简单的左右翻转方法处理,以及使用ToTensor转化为MXnet使用的格式,float32,其形状为(批量大小,通道数,高度,宽度),值的范围为0到1之间。通过DataLoader将数据根据batch_size包装成为迭代器。

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()])

def get_workers(num):

# windows系统不能使用多线程转换

return 0 if __import__('sys').platform.startswith('win') else num

def load_cifar10(is_train, augs, batch_size):

return gluon.data.DataLoader(gluon.data.vision.CIFAR10(train=is_train).transform_first(augs),

batch_size=batch_size, shuffle=is_train, num_workers=get_workers(6))

5.训练模型

使用ResNet-18模型训练,并使用GPU进行训练。首先定义每个batch的训练方法:

def accuracy(y_hat, y):

if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:

y_hat = y_hat.argmax(axis=1)

cmp = y_hat.astype(y.dtype) == y

return float(cmp.sum())

def train_batch(net, features, labels, loss, trainer, devices, split_f=d2l.split_batch):

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()

# ignore_stale_grad代表可以使用就得梯度参数

trainer.step(labels.shape[0], ignore_stale_grad=True)

train_loss_sum = sum([float(l.sum()) for l in ls])

train_acc_sum = sum(accuracy(pred_shard, y_shard)

for pred_shard, y_shard in zip(pred_shards, y_shards))

return train_loss_sum, train_acc_sum

def train(net, train_iter, test_iter, loss, trainer, num_epochs,

devices=d2l.try_all_gpus(), split_f=d2l.split_batch):

num_batches, timer = len(train_iter), d2l.Timer()

epochs_lst, loss_lst, train_acc_lst, test_acc_lst = [],[],[],[]

for epoch in range(num_epochs):

# Store training_loss, training_accuracy, num_examples, num_features

metric = d2l.Accumulator(4)

for i, (features, labels) in enumerate(train_iter):

timer.start()

l, acc = train_batch(

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:

epochs_lst.append(epoch + i / num_batches)

loss_lst.append(metric[0] / metric[2])

train_acc_lst.append(metric[1] / metric[3])

test_acc_lst.append(d2l.evaluate_accuracy_gpus(net, test_iter, split_f))

print(f"[epock {epoch+1}] train loss: {metric[0] / metric[2]:.3f} train acc: {metric[1] / metric[3]:.3f}",

f" test_loss: {test_acc_lst[-1]:.3f}")

print(f'loss {metric[0] / metric[2]:.3f}, train acc '

f'{metric[1] / metric[3]:.3f}, test acc {test_acc_lst[-1]:.3f}')

print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec on '

f'{str(devices)}')

fig = go.Figure()

fig.add_trace(go.Scatter(x=epochs_lst, y=loss_lst, name='train loss'))

fig.add_trace(go.Scatter(x=epochs_lst, y=train_acc_lst, name='train acc'))

fig.add_trace(go.Scatter(x=list(range(1,len(test_acc_lst)+1)), y=test_acc_lst, name='test acc'))

fig.update_layout(width=800, height=480, xaxis_title='epoch', yaxis_range=[0, 1])

fig.show()

定义一个函数来实现训练模型。并使用Adam用作优化函数进行训练。

batch_size, devices, net = 128, d2l.try_all_gpus(), d2l.resnet18(10)

net.initialize(init=init.Xavier(), ctx=devices)

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 = gluon.loss.SoftmaxCrossEntropyLoss()

trainer = gluon.Trainer(net.collect_params(), 'adam', {'learning_rate': lr})

train(net, train_iter, test_iter, loss, trainer, 10, devices)

train_with_data_aug(train_augs, test_augs, net)

1df9c99d524b3c5e689f8f16e5bcf40c.png

54ddbaadf98f7d328353732e2c736191.png

6. 参考

https://d2l.ai/chapter_computer-vision/image-augmentation.html

7.代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值