kinggerui 2019-12-07
在这篇文章中,我们将了解图像增强的概念以及有什么不同的图像增强技术。我们还将使用PyTorch实现这些图像增强技术来构建一个图像分类深度学习模型。
深度学习模型通常需要大量的数据来进行训练。通常,数据越多,模型的性能越好。但是获取海量数据面临着自身的挑战。并非每个人都拥有大公司的财力。
深度学习模型通常需要大量的训练数据。一般来说,数据越多,模型的性能越好。但获取大量数据本身也存在挑战。
缺乏数据的问题是,我们的深度学习模型可能无法从数据中学习模式或功能,因此它可能无法在不可见的数据上提供良好的性能。
在这种情况下我们能怎么做呢?我们可以利用图像增强技术来降低数据收集难度。
图像旋转
图像旋转是最常用的增强技术之一。它可以帮助我们的模型对对象方向的变化变得健壮。即使我们旋转图像,图像的信息也保持不变。即从不同的角度看汽车,汽车也还是汽车:
我们可以使用此技术通过从原始图像创建旋转图像来增加数据大小。让我们看看如何旋转图像:
让我们导入图像并首先对其进行可视化:
这是原始图像。现在让我们看看如何旋转它。我将使用skimage库的rotate函数旋转图像:
图像平移
在某些情况下,图像中的对象未完全对准中心。在这些情况下,可以使用图像平移为图像添加平移不变性。
通过移动图像,我们可以更改对象在图像中的位置,从而使模型更具多样性。最终将导致更通用的模型。
图像平移是一种几何变换,可将图像中每个对象的位置映射到最终输出图像中的新位置。
平移操作之后,输入图像中位置(x,y)上存在的对象将移位到新位置(X,Y):
此处,dx和dy是沿不同尺寸的相应位移。让我们看看如何将平移应用于图像:
平移超参数定义图像应移动的像素数。在这里,我将图像移动了(25,25)像素。我再次使用了“wrap”,用图像的其余像素填充输入边界外的点。
翻转图像
翻转是旋转的延伸。它使我们可以在左右以及上下方向上翻转图像。让我们看看如何实现翻转:
在这里,我使用了NumPy的fliplr函数来将图像从左到右翻转。它翻转每行的像素值。同样,我们可以上下翻转图像:
给图像添加噪声
图像降噪是重要的增强步骤,可让我们的深度学习模型学习如何将图像中的信号与噪声分离。
我们将使用skimage库的random_noise函数为原始图像添加一些随机噪声。我将要添加的噪声的标准偏差设为0.155(您也可以更改此值)。
图像模糊
由于图像来自不同的源,因此,图像的质量将不一样。有些图片可能是高质量的,而另一些可能是很差的。
在这种情况下,我们可以模糊图像。这有什么用呢?这有助于使我们的深度学习模型更健壮。
Sigma是标准偏差。sigma值越高,模糊效果越多。将“ Multichannel”设置为true可确保分别过滤图像的每个通道。
在根据您要解决的问题确定增强技术时,有一些准则很重要。
该项目的目的是将车辆图像分类为non-emergency 或emergency 。这是图像分类问题。您可以从此处下载数据集。
加载机器学习数据集
我们将应用图像增强技术,最后建立卷积神经网络(CNN)模型。让我们导入所需的Python库:
# importing the libraries 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文件:
# loading dataset data = pd.read_csv('emergency_vs_non-emergency_dataset/emergency_train.csv') data.head()
这里的0表示该车辆为non-emergency 车辆,1表示其为emergency 车辆。现在,让我们从机器学习数据集中导入有图像:
# loading images 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
机器学习数据集中共有1,646张图像。让我们将这些数据分为训练集和验证集。我们将使用验证集来评估深度学习模型在看不见的数据上的表现:
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%的数据将用于训练模型。我们在训练集中有1,481张图像,这不足以训练深度学习模型。
因此,接下来,我们将增强这些训练图像,以增强训练集,这可以改善深度学习模型的性能。
图像增强
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])
我们为训练集中的1,481张图像中的每张图像生成了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 libraries and modules 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格式:
# converting training images into torch format final_train = final_train.reshape(7405, 3, 224, 224) final_train = torch.from_numpy(final_train) final_train = final_train.float() # converting the target into torch format final_target_train = final_target_train.astype(int) final_target_train = torch.from_numpy(final_target_train)
同样,我们将转换验证集:
# converting validation images into torch format val_x = val_x.reshape(165, 3, 224, 224) val_x = torch.from_numpy(val_x) val_x = val_x.float() # converting the target into torch format val_y = val_y.astype(int) val_y = torch.from_numpy(val_y)
模型架构
接下来,我们将定义深度学习模型的体系结构。该体系结构包含4个卷积块,然后是4个全连接的dense层:
torch.manual_seed(0) class Net(Module): def __init__(self): super(Net, self).__init__() self.cnn_layers = Sequential( # Defining a 2D convolution layer Conv2d(3, 32, kernel_size=3, stride=1, padding=1), ReLU(inplace=True), # adding batch normalization BatchNorm2d(32), MaxPool2d(kernel_size=2, stride=2), # adding dropout Dropout(p=0.25), # Defining another 2D convolution layer Conv2d(32, 64, kernel_size=3, stride=1, padding=1), ReLU(inplace=True), # adding batch normalization BatchNorm2d(64), MaxPool2d(kernel_size=2, stride=2), # adding dropout Dropout(p=0.25), # Defining another 2D convolution layer Conv2d(64, 128, kernel_size=3, stride=1, padding=1), ReLU(inplace=True), # adding batch normalization BatchNorm2d(128), MaxPool2d(kernel_size=2, stride=2), # adding dropout Dropout(p=0.25), # Defining another 2D convolution layer Conv2d(128, 128, kernel_size=3, stride=1, padding=1), ReLU(inplace=True), # adding batch normalization BatchNorm2d(128), MaxPool2d(kernel_size=2, stride=2), # adding 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) ) # Defining the forward pass 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个epochs:
torch.manual_seed(0) # batch size of the model batch_size = 64 # number of epochs to train the model 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)
您会注意到,随着时间的增加,训练损失会减少。让我们保存经过训练的深度学习模型的权重:
torch.save(model, 'model.pt')
加载这个深度学习模型的Python代码:
the_model = torch.load('model.pt')
检查模型的性能
最后,让我们对训练和验证集进行预测,并检查各自的准确性:
torch.manual_seed(0) # prediction for training set 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) # training accuracy accuracy = [] for i in range(len(prediction)): accuracy.append(accuracy_score(target[i].cpu(),prediction[i])) print('training accuracy: \t', np.average(accuracy))
我们在训练集上的准确性超过91%!我们需要对验证集进行相同的检查:
# checking the performance on validation set 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)
在本文中,我们介绍了大多数常用的图像增强技术。您可以在任何图像分类问题上尝试这些图像增强技术,然后比较有无增强时的性能。