关于人工智能:基于PyTorch图像特征工程的深度学习图像增强

37次阅读

共计 10093 个字符,预计需要花费 26 分钟才能阅读完成。

介绍

在深度学习黑客比赛中表现出色的技巧(或者坦率地说,是任何数据迷信黑客比赛)通常归结为特色工程。当您取得的数据不足以建设一个胜利的深度学习模型时,你能施展多少创造力?

我是依据本人加入屡次深度学习黑客比赛的教训而谈的,在这次深度黑客比赛中,咱们取得了蕴含数百张图像的数据集——基本不足以博得甚至实现排行榜的顶级排名。那咱们怎么解决这个问题呢?

答案?好吧,那要看数据科学家的技能了!这就是咱们的好奇心和创造力怀才不遇的中央。这就是特色工程背地的理念——在现有特色的状况下,咱们能多好地提出新特色。当咱们解决图像数据时,同样的想法也实用。

这就是图像增强的次要作用。这一概念不仅仅局限于黑客比赛——咱们在工业和事实世界中深度学习模型我的项目中都应用了它!


图像增强性能帮忙我裁减现有数据集,而无需费时费力。而且我置信您会发现这项技术对您本人的我的项目十分有帮忙。

因而,在本文中,咱们将理解图像增强的概念,为何有用以及哪些不同的图像增强技术。咱们还将实现这些图像增强技术,以应用 PyTorch 构建图像分类模型。

目录

  1. 为什么须要图像增强?
  2. 不同的图像增强技术
  3. 抉择正确的加强技术的基本准则
  4. 案例钻研:应用图像增强解决图像分类问题

为什么须要图像增强?

深度学习模型通常须要大量的数据来进行训练。通常,数据越多,模型的性能越好。然而获取海量数据面临着本身的挑战。不是每个人都有大公司的雄厚财力。

短少数据使得咱们的深度学习模型可能无奈从数据中学习模式或性能,因而在未见过的数据上可能无奈提供良好的性能。

那么在那种状况下咱们该怎么办?咱们能够应用 图像增强技术,而无需破费几天的工夫手动收集数据。

图像增强是生成新图像以训练咱们的深度学习模型的过程。这些新图像是应用现有的训练图像生成的,因而咱们不用手动收集它们。


有多种图像增强技术,咱们将在下一节探讨一些常见的和应用最宽泛的技术。

不同的图像增强技术

图像旋转

图像旋转是最罕用的加强技术之一。它能够帮忙咱们的模型对对象方向的变动变得强壮。即便咱们旋转图像,图像的信息也放弃不变。汽车就是一辆汽车,即便咱们从不同的角度看它:

因而,咱们能够应用此技术,通过从原始图像创立旋转图像来减少数据量。让咱们看看如何旋转图像:

# 导入所有必须的库
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import skimage.io as io
from skimage.transform import rotate, AffineTransform, warp
from skimage.util import random_noise
from skimage.filters import gaussian
import matplotlib.pyplot as plt
% matplotlib inline

我将应用此图像演示不同的图像增强技术。你也能够依据本人的要求尝试其余图片。

咱们先导入图像并将其可视化:

# reading the image using its path
image = io.imread('emergency_vs_non-emergency_dataset/images/0.jpg')


# shape of the image
print(image.shape)


# displaying the image
io.imshow(image)

这是原始图像。当初让咱们看看如何旋转它。我将应用skimage 库的旋转性能来旋转图像:

print('Rotated Image')
#rotating the image by 45 degrees
rotated = rotate(image, angle=45, mode = 'wrap')
#plot the rotated image
io.imshow(rotated)

很好!将模式设置为“wrap”,用图像的残余像素填充输出边界之外的点。

平移图像

可能会呈现图像中的对象没有齐全居中对齐的状况。在这些状况下,能够应用图像平移为图像增加平移不变性。

通过挪动图像,咱们能够更改对象在图像中的地位,从而使模型更具多样性。最终将生成更通用的模型。

图像平移是一种几何变换,它将图像中每个对象的地位映射到最终输入图像中的新地位。

在移位操作之后,输出图像中的地位(x,y)处的对象被移位到新地位(X,Y):

  • X = x + dx
  • Y = y + dy

其中,dx 和 dy 别离是沿不同维度的位移。让咱们看看如何将 shift 利用于图像:

# 利用平移操作
transform = AffineTransform(translation=(25,25))
wrapShift = warp(image,transform,mode='wrap')
plt.imshow(wrapShift)
plt.title('Wrap Shift')

translation 超参数定义图像应挪动的像素数。这里,我把图像移了(25,25)个像素。您能够随便设置此超参数的值。

我再次应用“wrap”模式,它用图像的残余像素填充输出边界之外的点。在下面的输入中,您能够看到图像的高度和宽度都挪动了 25 像素。

翻转图像

翻转是旋转的延长。它使咱们能够在左右以及高低方向上翻转图像。让咱们看看如何实现翻转:

#flip image left-to-right
flipLR = np.fliplr(image)


plt.imshow(flipLR)
plt.title('Left to Right Flipped')

在这里,我应用了 NumPy 的fliplr 函数从左向右翻转图像。它翻转每一行的像素值,并且输入确认雷同。相似地,咱们能够沿高低方向翻转图像:

# 高低翻转图像
flipUD = np.flipud(image)


plt.imshow(flipUD)
plt.title('Up Down Flipped')

这就是咱们能够翻转图像并制作更通用的模型的办法,该模型将学习到原始图像以及翻转后的图像。向图像增加随机噪声也是图像增强技术。让咱们通过一个例子来了解它。

给图像增加噪点

图像噪声是一个重要的加强步骤,使咱们的模型可能学习如何拆散图像中的信号和噪声。这也使得模型对输出的变动更加强壮。

咱们将应用“skipage”库的“random_noise”函数为原始图像增加一些随机噪声

我将噪声的标准差取为 0.155(您也能够更改此值)。请记住,减少此值将为图像增加更多噪声,反之亦然:

# 要增加到图像中的噪声的标准差
sigma=0.155
# 向图像增加随机噪声
noisyRandom = random_noise(image,var=sigma**2)


plt.imshow(noisyRandom)
plt.title('Random Noise')

咱们能够看到随机噪声已增加到原始图像中。试一下不同的标准偏差的值,看看失去的不同后果。

含糊图像

所有摄影爱好者都会立刻了解这个想法。

图像有不同的起源。因而,每个起源的图像品质都将不同。有些图像的品质可能很高,而另一些则可能很差劲。

在这种状况下,咱们能够使图像含糊。那将有什么帮忙?好吧,这有助于使咱们的深度学习模型更弱小。

让咱们看看咱们如何做到这一点。咱们将应用高斯滤波器来含糊图像:

# 含糊图像
blurred = gaussian(image,sigma=1,multichannel=True)


plt.imshow(blurred)
plt.title('Blurred Image')

Sigma 是高斯滤波器的标准差。我将其视为 1。sigma 值越高,含糊成果越强。将 * Multichannel * 设置为 true 可确保别离过滤图像的每个通道。

同样,您能够尝试应用不同的 sigma 值来更改含糊度。

这些是一些图像增强技术,有助于使咱们的深度学习模型强壮且可推广。这也有助于减少训练集的大小。

咱们行将实现本教程的实现局部。在此之前,让咱们看看一些根本的准则,以决定正确的图像增强技术。

抉择正确的加强技术的基本准则

我认为在依据您试图解决的问题来决定加强技术时,有一些准则是很重要的。以下是这些准则的简要概述:

  1. 任何模型构建过程的第一步都是确保输出的大小与模型所冀望的大小相匹配。咱们还必须确保所有图像的大小应该类似。为此,咱们能够调整咱们的图像到适当的大小。
  2. 假如您正在解决一个分类问题,并且样本数据量绝对较少。在这种状况下,能够应用不同的加强技术,如图像旋转、图像噪声、翻转、移位等。请记住,所有这些操作都实用于对图像中对象地位无关紧要的分类问题。
  3. 如果您正在解决一个对象检测工作,其中对象的地位是咱们要检测的,这些技术可能不适合。
  4. 图像像素值的标准化是保障模型更好更快收敛的一个很好的策略。如果模型有特定的要求,咱们必须依据模型的要求对图像进行预处理。

当初,不必再等了,让咱们持续到模型构建局部。咱们将利用本文探讨的加强技术生成图像,而后应用这些图像来训练模型。

咱们将钻研紧急车辆与非紧急车辆的分类问题。如果你看过我以前的 PyTorch 文章,你应该相熟问题的形容。

该项目标指标是将车辆图像分为紧急和非紧急两类。你猜对了,这是一个图像分类问题。您能够 从这里下载数据集

加载数据集

咱们开始吧!咱们先把数据装入 notebook。而后,咱们将利用图像增强技术,最初,建设一个卷积神经网络 (CNN) 模型。

让咱们导入所需的库:

# 导入库
from torchsummary import summary
import pandas as pd
import numpy as np
from skimage.io import imread, imsave
from tqdm import tqdm
import matplotlib.pyplot as plt
%matplotlib inline


from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


from skimage.transform import rotate
from skimage.util import random_noise
from skimage.filters import gaussian
from scipy import ndimage

当初,咱们将读取蕴含图像名称及其相应标签的 CSV 文件:

# 加载数据集
data = pd.read_csv('emergency_vs_non-emergency_dataset/emergency_train.csv')
data.head()

0 示意该车为非紧急车辆,1 示意该车为紧急车辆。当初让咱们从数据集中加载所有图像:

# 加载图像
train_img = []
for img_name in tqdm(data['image_names']):
    image_path = 'emergency_vs_non-emergency_dataset/images/' + img_name
    img = imread(image_path)
    img = img/255
    train_img.append(img)


train_x = np.array(train_img)
train_y = data['emergency_or_not'].values
train_x.shape, train_y.shape

数据集中共有 1646 幅图像。让咱们把这些数据分成训练和验证集。咱们将应用验证集来评估模型在未见过的数据上的性能:

train_x, val_x, train_y, val_y = train_test_split(train_x, train_y, test_size = 0.1, random_state = 13, stratify=train_y)
(train_x.shape, train_y.shape), (val_x.shape, val_y.shape)

我将“test_size”放弃为 0.1,因而 10% 的数据将随机抉择作为验证集,剩下的 90% 将用于训练模型。训练集有 1481 个图像,这对于训练深度学习模型来说是相当少的。

因而,接下来,咱们将减少这些训练图像,以减少训练集,并可能进步模型的性能。

加强图像

咱们将应用后面探讨过的图像增强技术:

final_train_data = []
final_target_train = []
for i in tqdm(range(train_x.shape[0])):
    final_train_data.append(train_x[i])
    final_train_data.append(rotate(train_x[i], angle=45, mode = 'wrap'))
    final_train_data.append(np.fliplr(train_x[i]))
    final_train_data.append(np.flipud(train_x[i]))
    final_train_data.append(random_noise(train_x[i],var=0.2**2))
    for j in range(5):
        final_target_train.append(train_y[i])

咱们为训练集中的 1481 张图像中的每一张生成了 4 张加强图像。让咱们以数组的模式转换图像并验证数据集的大小:

len(final_target_train), len(final_train_data)
final_train = np.array(final_train_data)
final_target_train = np.array(final_target_train)

这证实了咱们曾经加强了图像并减少了训练集的大小。让咱们将这些加强图像进行可视化:

fig,ax = plt.subplots(nrows=1,ncols=5,figsize=(20,20))
for i in range(5):
    ax[i].imshow(final_train[i+30])
    ax[i].axis('off')

这里的第一个图像是来自数据集的原始图像。其余四幅图像别离应用不同的图像增强技术(旋转、从左向右翻转、高低翻转和增加随机噪声)生成的。

咱们的数据集当初曾经筹备好了。是时候定义咱们的深度学习模型的构造,而后在加强过的训练集上对其进行训练了。咱们先从 PyTorch 中导入所有函数:

# PyTorch 库和模块
import torch
from torch.autograd import Variable
from torch.nn import Linear, ReLU, CrossEntropyLoss, Sequential, Conv2d, MaxPool2d, Module, Softmax, BatchNorm2d, Dropout
from torch.optim import Adam, SGD

咱们必须将训练集和验证集转换为 PyTorch 格局:

# 将训练图像转换为 torch 格局
final_train = final_train.reshape(7405, 3, 224, 224)
final_train  = torch.from_numpy(final_train)
final_train = final_train.float()


# 将 target 转换为 torch 格局
final_target_train = final_target_train.astype(int)
final_target_train = torch.from_numpy(final_target_train)

同样,咱们将转换验证集:

# 将验证图像转换为 torch 格局
val_x = val_x.reshape(165, 3, 224, 224)
val_x  = torch.from_numpy(val_x)
val_x = val_x.float()


# 将 target 转换为 torch 格局
val_y = val_y.astype(int)
val_y = torch.from_numpy(val_y)

模型构造

接下来,咱们将定义模型的构造。这有点简单,因为模型构造蕴含 4 个卷积块,而后是 4 个全连贯层:

torch.manual_seed(0)


class Net(Module):   
    def __init__(self):
        super(Net, self).__init__()


        self.cnn_layers = Sequential(
            # 定义 2D convolution 层
            Conv2d(3, 32, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # 增加 batch normalization 层
            BatchNorm2d(32),
            MaxPool2d(kernel_size=2, stride=2),
            # 增加 dropout
            Dropout(p=0.25),
            # 定义另一个 2D convolution 层
            Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # 增加 batch normalization 层
            BatchNorm2d(64),
            MaxPool2d(kernel_size=2, stride=2),
            # 增加 dropout
            Dropout(p=0.25),
            # 定义另一个 2D convolution 层
            Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # 增加 batch normalization 层
            BatchNorm2d(128),
            MaxPool2d(kernel_size=2, stride=2),
            # 增加 dropout
            Dropout(p=0.25),
            # 定义另一个 2D convolution 层
            Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
            ReLU(inplace=True),
            # 增加 batch normalization 层
            BatchNorm2d(128),
            MaxPool2d(kernel_size=2, stride=2),
            # 增加 dropout
            Dropout(p=0.25),
        )


        self.linear_layers = Sequential(Linear(128 * 14 * 14, 512),
            ReLU(inplace=True),
            Dropout(),
            Linear(512, 256),
            ReLU(inplace=True),
            Dropout(),
            Linear(256,10),
            ReLU(inplace=True),
            Dropout(),
            Linear(10,2)
        )


    # 定义前向过程    
    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

让咱们定义模型的其余超参数,包含优化器、学习率和损失函数:

# defining the model
model = Net()
# defining the optimizer
optimizer = Adam(model.parameters(), lr=0.000075)
# defining the loss function
criterion = CrossEntropyLoss()
# checking if GPU is available
if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()


print(model)

训练模型

为咱们的深度学习模型训练 20 个 epoch:

torch.manual_seed(0)


# 模型的 batch size
batch_size = 64


# 训练模型的 epoch 数
n_epochs = 20


for epoch in range(1, n_epochs+1):


    train_loss = 0.0
        
    permutation = torch.randperm(final_train.size()[0])


    training_loss = []
    for i in tqdm(range(0,final_train.size()[0], batch_size)):


        indices = permutation[i:i+batch_size]
        batch_x, batch_y = final_train[indices], final_target_train[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        outputs = model(batch_x)
        loss = criterion(outputs,batch_y)


        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

这是训练阶段的 summary。你会留神到,随着 epoch 的减少,训练 loss 会缩小。让咱们保留已训练的模型的权重,以便未来在不从新训练模型的状况下应用它们:

torch.save(model, 'model.pt')

如果您不想在您的终端训练模型,您能够应用此链接下载已训练了 20 个 epoch 的模型的权重。

接下来,让咱们加载这个模型:

the_model = torch.load('model.pt')

测试咱们模型的性能

最初,让咱们对训练集和验证集进行预测,并查看各自的准确度:

torch.manual_seed(0)
# 预测训练集
prediction = []
target = []
permutation = torch.randperm(final_train.size()[0])
for i in tqdm(range(0,final_train.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = final_train[indices], final_target_train[indices]


    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()


    with torch.no_grad():
        output = model(batch_x.cuda())


    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练准确度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i].cpu(),prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

训练集的准确率超过 91%!很有心愿。然而,让咱们刮目相待吧。咱们须要对验证集进行雷同的查看:

# 预测验证集
torch.manual_seed(0)
output = model(val_x.cuda())
softmax = torch.exp(output).cpu()
prob = list(softmax.detach().numpy())
predictions = np.argmax(prob, axis=1)
accuracy_score(val_y, predictions)


验证准确性约为 78%。很好!

尾注

当咱们开始取得的训练数据较少时,咱们能够应用图像增强技术。

在本文中,咱们介绍了大多数罕用的图像增强技术。咱们学习了如何旋转,挪动和翻转图像。咱们还学习了如何为图像增加随机噪声或使其含糊。而后,咱们探讨了抉择正确的加强技术的基本准则。

您能够在任何图像分类问题上尝试应用这些图像增强技术,而后比拟应用加强和不应用加强的性能。随时在上面的评论局部中分享您的后果。

而且,如果您不相熟深度学习,计算机视觉和图像数据,那么建议您实现以下课程:

  • 应用深度学习 2.0 的计算机视觉

原文链接:https://www.analyticsvidhya.c…

欢送关注磐创 AI 博客站:
http://panchuang.net/

sklearn 机器学习中文官网文档:
http://sklearn123.com/

欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/

正文完
 0