在之前,我们看到了模型准确性的显著增加。我们的模型被有效地训练以对训练数据进行分类。然而,它在验证数据上的泛化效果不好,存在过拟合的问题。现在,让我们讨论另一种改进模型训练过程的技术,即数据增强。这是一种通过在训练过程中为模型创建新数据的方法。

这是通过对现有数据集进行转换或更改图像以创建新图像的有用方式来完成的。

04-1.png

应用变换后,新创建的图像被称为增强图像,因为它们本质上允许我们通过向其添加新数据来增强数据集。数据增强技术很有用,因为它允许我们的模型从许多不同的角度查看数据集中的每个图像。这使得我们的模型能够更准确地提取相关特征,并从每个训练图像中获取更多的特征相关数据。

现在,我们最大的问题是如何使用增强来减少过拟合。过拟合发生在模型过于拟合训练集时。

我们无需开始收集新图像并将其添加到我们的数据集中。我们可以使用数据增强,对现有数据集进行轻微的更改,如加深阴影、翻转、缩放、旋转或平移。我们的模型将将它们解释为不同的图像。这不仅可以减少过拟合,还可以防止网络学习无关模式,并提高整体性能。我们有以下步骤来执行数据增强:

步骤 1:

要对训练数据集执行数据增强,我们必须创建一个单独的变换语句。对于验证数据集,变换将保持不变。首先,我们复制我们的 transform1 语句,并将其视为 transform_train

transform_train=transforms.Compose([transforms.Resize((32,32)),transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,))])  

步骤 2:

现在,我们将在我们的 transform_train 语句中添加变换。变换将包括 RandomHorizontalFlip、用于对图像进行旋转的 RandomRotation(传递一个角度作为参数):

transform_train=transforms.Compose([transforms.Resize((32,32)),  
        transform.RandomHorizontalFlip(),  
        transform.RandomRotation(),  
        transforms.ToTensor(),  
        transforms.Normalize((0.5,),(0.5,))])  

为了对数据集添加更多的变化,我们将使用一种细型的变换。细型变换表示保留物体上的直线和平面的简单变换。缩放、平移、剪切和缩放是属于这个类别的变换。

transform_train=transforms.Compose([transforms.Resize((32,32)),  
        transform.RandomHorizontalFlip(),  
        transform.RandomRotation(),  
        transform.RandomAffine(0,shear=10,scale=(0.8,1.2)),  
        transforms.ToTensor(),  
        transforms.Normalize((0.5,),(0.5,))])  

RandomAffine() 中,第一个参数是旋转,我们将其设置为零以禁用旋转,第二个参数是剪切变换,最后一个参数是缩放变换,使用一个元组定义缩放的范围,我们将范围定义为 0.8 到 1.2,将图像缩放到其大小的 80% 到 120%。

步骤 3:

现在,我们继续下一个增强,以创建新的带有随机亮度、对比度和饱和度变化的增强图像。我们将添加另一个变换,即 ColorJitter

transform_train=transforms.Compose([transforms.Resize((32,32)),  
        transform.RandomHorizontalFlip(),  
        transform.RandomRotation(10),  
        transform.RandomAffine(0,shear=10,scale=(0.8,1.2)),  
        transform.ColorJitter(brightness=0.2,contrast=0.2,saturation=0.2)  
        transforms.ToTensor(),  
        transforms.Normalize((0.5,),(0.5,))])  

步骤 4:

在执行我们的代码之前,我们必须更改 training_dataset 语句,因为现在我们为训练数据集有了另一个变换。因此:

training_dataset=datasets.CIFAR10(root='./data',train=True,download=True,transform=transform_train)  

现在,我们将执行我们的代码,执行后,它将为我们提供带有正确预测的预期输出。

04-2.png

04-3.png

完整代码:

import torch  
import matplotlib.pyplot as plt  
import numpy as np  
import torch.nn.functional as func  
import PIL.ImageOps  
from torch import nn  
from torchvision import datasets,transforms   
import requests  
from PIL import Image  
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")  
transform_train=transforms.Compose([transforms.Resize((32,32)),  
                               transforms.RandomHorizontalFlip(),  
                               transforms.RandomRotation(10),  
                               transforms.RandomAffine(0,shear=10,scale=(0.8,1.2)),  
                               transforms.ColorJitter(brightness=0.2,contrast=0.2,saturation=0.2),  
                               transforms.ToTensor(),  
                               transforms.Normalize((0.5,),(0.5,))])  
transform1=transforms.Compose([transforms.Resize((32,32)),transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,))])  
training_dataset=datasets.CIFAR10(root='./data',train=True,download=True,transform=transform_train)  
validation_dataset=datasets.CIFAR10(root='./data',train=False,download=True,transform=transform1)  
training_loader=torch.utils.data.DataLoader(dataset=training_dataset,batch_size=100,shuffle=True)  
validation_loader=torch.utils.data.DataLoader(dataset=validation_dataset,batch_size=100,shuffle=False)  
def im_convert(tensor):  
    image=tensor.cpu().clone().detach().numpy()  
    image=image.transpose(1,2,0)  
    print(image.shape)  
    image=image*(np.array((0.5,0.5,0.5))+np.array((0.5,0.5,0.5)))  
    image=image.clip(0,1)  
    return image  
classes=('plane','car','bird','cat','dear','dog','frog','horse','ship','truck')  
dataiter=iter(training_loader)  
images,labels=dataiter.next()  
fig=plt.figure(figsize=(25,4))  
for idx in np.arange(20):  
  
    ax=fig.add_subplot(2,10,idx+1)  
    plt.imshow(im_convert(images[idx]))  
    ax.set_title(classes[labels[idx].item()])  
class LeNet(nn.Module):  
        def __init__(self):  
            super().__init__()  
            self.conv1=nn.Conv2d(3,16,3,1, padding=1)  
            self.conv2=nn.Conv2d(16,32,3,1, padding=1)  
            self.conv3=nn.Conv2d(32,64,3,1, padding=1)     
            self.fully1=nn.Linear(4*4*64,500)  
            self.dropout1=nn.Dropout(0.5)   
            self.fully2=nn.Linear(500,10)  
        def forward(self,x):  
            x=func.relu(self.conv1(x))  
            x=func.max_pool2d(x,2,2)  
            x=func.relu(self.conv2(x))  
            x=func.max_pool2d(x,2,2)  
            x=func.relu(self.conv3(x))  
            x=func.max_pool2d(x,2,2)  
            x=x.view(-1,4*4*64) #Reshaping the output into desired shape  
            x=func.relu(self.fully1(x)) #Applying relu activation function to our first fully connected layer  
            x=self.dropout1(x)  
            x=self.fully2(x)    #We will not apply activation function here because we are dealing with multiclass dataset  
            return x      
model=LeNet().to(device)  
criteron=nn.CrossEntropyLoss()  
optimizer=torch.optim.Adam(model.parameters(),lr=0.001)  
epochs=12  
loss_history=[]  
correct_history=[]  
val_loss_history=[]  
val_correct_history=[]  
for e in range(epochs):  
    loss=0.0  
    correct=0.0  
    val_loss=0.0  
    val_correct=0.0  
    for input,labels in training_loader:  
        input=input.to(device)  
        labels=labels.to(device)  
        outputs=model(input)  
        loss1=criteron(outputs,labels)  
        optimizer.zero_grad()  
        loss1.backward()  
        optimizer.step()  
        _,preds=torch.max(outputs,1)  
        loss+=loss1.item()  
        correct+=torch.sum(preds==labels.data)  
    else:  
        with torch.no_grad():  
            for val_input,val_labels in validation_loader:  
                val_input=val_input.to(device)  
                val_labels=val_labels.to(device)  
                val_outputs=model(val_input)  
                val_loss1=criteron(val_outputs,val_labels)   
                _,val_preds=torch.max(val_outputs,1)  
                val_loss+=val_loss1.item()  
                val_correct+=torch.sum(val_preds==val_labels.data)  
        epoch_loss=loss/len(training_loader)  
        epoch_acc=correct.float()/len(training_loader)  
        loss_history.append(epoch_loss)  
        correct_history.append(epoch_acc)  
        val_epoch_loss=val_loss/len(validation_loader)  
        val_epoch_acc=val_correct.float()/len(validation_loader)  
        val_loss_history.append(val_epoch_loss)  
        val_correct_history.append(val_epoch_acc)  
        print('training_loss:{:.4f},{:.4f}'.format(epoch_loss,epoch_acc.item()))  
        print('validation_loss:{:.4f},{:.4f}'.format(val_epoch_loss,val_epoch_acc.item()))  
  
url='https://akm-img-a-in.tosshub.com/indiatoday/images/story/201810/white_stork.jpeg?B2LINO47jclcIb3QCW.Bj9nto934Lox4'  
response=requests.get(url,stream=True)  
img=Image.open(response.raw)  
img=transform1(img)     
image1=img.to(device).unsqueeze(0)  
output=model(image1)  
_,pred=torch.max(output,1)  
print(classes[pred.item()])  
  
dataiter=iter(validation_loader)    
images,labels=dataiter.next()    
images_=images.to(device)    
labels=labels.to(device)    
output=model(images_)    
_,preds=torch.max(output,1)    
fig=plt.figure(figsize=(25,4))    
for idx in np.arange(20):    
      ax=fig.add_subplot(2,10,idx+1,xticks=[],yticks=[])     
      plt.imshow(im_convert(images[idx]))      
ax.set_title("{}({})".format(str(classes[preds[idx].item()]),str(classes[labels[idx].item()]),color=("green" if classes[preds[idx]]==classes[labels[idx]] else "red")))  
plt.show()  

04-4.png

04-5.png

标签: Pytorch, Pytorch教程, Pytorch安装, Pytorch入门, Pytorch下载, Pytorch指南, Pytorch编程, Pytorch入门教程, Pytorch初级教程, Pytorch进阶, Pytorch高级教程, Pytorch学习, Pytorch库