PyTorch 教程-卷积神经网络模型的验证
在训练部分,我们在MNIST数据集上训练了我们的CNN模型(无限数据集),并且似乎达到了合理的损失和准确性。如果模型能够将其所学到的内容推广到新数据,那么这将是其性能的真正证明。这将与我们在先前主题中所做的方式相同。
步骤1:
我们将使用我们在训练部分创建的训练数据集来创建验证集。这一次,我们将设置train=False:
validation_dataset=datasets.MNIST(root='./data',train=False,download=True,transform=transform1)
步骤2:
validation_loader=torch.utils.data.DataLoader(dataset=validation_dataset,batch_size=100,shuffle=False)
步骤3:
val_loss_history=[]
val_correct_history=[]
步骤4:
在接下来的步骤中,我们将验证模型。该模型将在相同的epoch中验证。在我们完成通过整个训练集进行迭代以训练数据之后,我们现在将通过验证集进行迭代以测试数据。
val_loss=0.0
val_correct=0.0
步骤5:
for val_input,val_labels in validation_loader:
步骤6:
我们正在处理卷积神经网络,将输入首先传递给它们。我们将专注于这些图像的四个维度。因此,无需将它们展平。
input=input.to(device)
labels=input.to(device)
val_outputs=model(val_inputs)
步骤7:
val_loss1=criteron(val_outputs,val_labels)
with torch.no_grad():
它将临时将所有requires_grad标志设置为False。
步骤8:
_,val_preds=torch.max(val_outputs,1)
val_loss+=val_loss1.item()
val_correct+=torch.sum(val_preds==val_labels.data)
步骤9:
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)
步骤10:
print('validation_loss:{:.4f},{:.4f}'.format(val_epoch_loss,val_epoch_acc.item()))
步骤11:
plt.plot(loss_history,label='Training Loss')
plt.plot(val_loss_history,label='Validation Loss')
plt.legend()
plt.show()
plt.plot(correct_history,label='Training accuracy')
plt.plot(val_correct_history,label='Validation accuracy')
plt.legend()
plt.show()
从上面的图表中可以清楚地看出,在CNN中发生了过拟合。为了减少这种过拟合,我们将介绍另一种名为Dropout Layer的快速技术。
步骤12:
在下一步中,我们将转到我们的LeNet类,并添加一种称为Dropout层的特定层类型,该层类型将减少我们数据的过拟合。该层类型称为Dropout层。此层本质上通过在训练过程中随机将输入单元的分数比例设置为0来工作,每次更新。
上图显示了标准神经网络,以及在应用了dropout后相同神经网络的情况。我们可以看到,有些节点已被关闭,并且不再沿着网络与信息通信。
我们将使用不止一个dropout层,这将在给定网络中用于获得所需的性能。我们将这些dropout层放在卷积层之间和全连接层之间。在完全连接的层之间,我们将dropout层放置在这些高参数层之间,因为这些高参数层更有可能过度拟合和记忆训练数据。因此,我们将在完全连接的层之间设置我们的dropout层。
self.dropout1=nn.dropout(0.5)
步骤13:
x=self.dropout1(x)
现在,我们将运行我们的程序,它将为我们提供更准确的结果:
完整代码
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
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
transform1=transforms.Compose([transforms.Resize((28,28)),transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,))])
training_dataset=datasets.MNIST(root='./data',train=True,download=True,transform=transform1)
validation_dataset=datasets.MNIST(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)
class LeNet(nn.Module):
def __init__(self):
super().__init__()
self.conv1=nn.Conv2d(1,20,5,1)
self.conv2=nn.Conv2d(20,50,5,1)
self.fully1=nn.Linear(4*4*50,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=x.view(-1,4*4*50) #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.00001)
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()))
plt.plot(loss_history,label='Training Loss')
plt.plot(val_loss_history,label='Validation Loss')
plt.legend()
plt.show()
plt.plot(correct_history,label='Training accuracy')
plt.plot(val_correct_history,label='Validation accuracy')
plt.legend()
plt.show()