之前使用了BatchNorm方案进行正则化,效果尚不是很好。是不是我们的网络没有提升空间了呢?我们换一个角度对我们之前的网络架构进行审视。之前的架构,每次卷积层的padding都为0,从某个层面上来说我们并没有充分利用好图像的边缘信息,于是我们对网络的架构进行了再次的调整。将部卷积层的padding置为1,并使用大卷积核,与此同时在末尾增加了池化层。改良后的网络架构如下:
Layer (type) Output Shape Param #
Conv2d-1 3*3 [-1, 4, 8, 8] 40
BatchNorm2d-2 [-1, 4, 8, 8] 8
Conv2d-3 3*3 [-1, 8, 8, 8] 296
BatchNorm2d-4 [-1, 8, 8, 8] 16
ReLU-5 [-1, 8, 8, 8] 0
MaxPool2d-6 [-1, 8, 4, 4] 0
Conv2d-7 3*3 [-1, 16, 4, 4] 1,168
BatchNorm2d-8 [-1, 16, 4, 4] 32
ReLU-9 [-1, 16, 4, 4] 0
MaxPool2d-10 [-1, 16, 2, 2] 0
Linear-11 [-1, 10] 650
Total params: 2,210
Trainable params: 2,210
Non-trainable params: 0
训练结果如下:
果然,训练效果相比之前的架构又有所提升,最好的测试集准确率超过了99%,说明我们之前的判断是准确的。
附网络架构改变以后的代码:
import torch
import torch.nn as nn
import torch.utils.data as Data
import torchvision
from sklearn.datasets import load_digits
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
import torch as t
import torch.nn as nn
import torch.utils.data as Data
import torchvision
import matplotlib.pyplot as plt
from graphviz import Digraph
import torch
from torch.autograd import Variable
from torchsummary import summary
class train_mini_mnist(t.utils.data.Dataset):
def __init__(self):
self.X,self.y=load_digits(return_X_y=True)
self.X_train,self.X_test,self.y_train,self.y_test=train_test_split(self.X,self.y,random_state=0)
def __getitem__(self, index):
return t.tensor(self.X_train[index].reshape(1,8,8),dtype=torch.float32),self.y_train[index]
def __len__(self):
return len(self.y_train)
class test_mini_mnist(t.utils.data.Dataset):
def __init__(self):
self.X,self.y=load_digits(return_X_y=True)
self.X_train,self.X_test,self.y_train,self.y_test=train_test_split(self.X,self.y,random_state=0)
def __getitem__(self, index):
return t.tensor(self.X_test[index].reshape(1,8,8),dtype=torch.float32),self.y_test[index]
def __len__(self):
return len(self.y_test)
BATCH_SIZE=4
LEARNING_RATE=3e-3
EPOCHES=100
train_data=train_mini_mnist()
test_data=test_mini_mnist()
train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
test_loader = Data.DataLoader(dataset=test_data, batch_size=BATCH_SIZE, shuffle=True)
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.conv1 = nn.Sequential(#(1, 8, 8)
nn.Conv2d(in_channels=1, out_channels=4, kernel_size=3, stride=1, padding=1),#(4, 8, 8)
nn.BatchNorm2d(4),
nn.Conv2d(in_channels=4, out_channels=8, kernel_size=3, stride=1, padding=1),#(8, 8, 8)
nn.BatchNorm2d(8),
nn.ReLU(),#(8,8,8)
nn.MaxPool2d(kernel_size=2)#(8,4,4)
)
self.conv2 = nn.Sequential(
nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3, stride=1, padding=1),#(16, 4, 4)
nn.BatchNorm2d(16),
nn.ReLU(),#(16,2,2)
nn.MaxPool2d(kernel_size=2)#(16,2,2)
)
self.fc = nn.Linear(16*2*2, 10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1)#相当于Flatten
x = self.fc(x)
return x
def eval_on_dataloader(name,loader,len):
acc = 0.0
with torch.no_grad():
for data in loader:
images, labels = data
outputs = net(images)
predict_y = torch.max(outputs, dim=1)[1]#torch.max返回两个数值,一个是最大值,一个是最大值的下标
acc += (predict_y == labels).sum().item()
accurate = acc / len
return accurate
def plot_train_and_test_result(train_accs,test_accs):
epoches=np.arange(1,len(train_accs)+1,dtype=np.int32)
plt.plot(epoches,train_accs,label="train_accuracy")
plt.plot(epoches,test_accs,label="test_accuracy")
plt.xlabel('epoches')
plt.ylabel('accuracy')
plt.legend()
net = SimpleNet()
summary(net, (1, 8, 8))
loss_fn = nn.CrossEntropyLoss()
optim = torch.optim.Adam(net.parameters(), lr = LEARNING_RATE)
for name,parameters in net.named_parameters():
print(name,":",parameters.size())
best_acc = 0.0
train_accs,test_accs=[],[]
for epoch in range(EPOCHES):
net.train()#切换到训练模式
for step, data in enumerate(train_loader, start=0):
images, labels = data
optim.zero_grad()#将优化器的梯度清零
logits = net(images)#网络推断的输出
loss = loss_fn(logits, labels.long())#计算损失函数
loss.backward()#反向传播求梯度
optim.step()#优化器进一步优化
rate = (step+1)/len(train_loader)
a = "*" * int(rate * 50)
b = "." * int((1 - rate) * 50)
print("\rtrain loss: {:^3.0f}%[{}->{}]{:.4f}".format(int(rate*100), a, b, loss), end="")
print()
net.eval()#切换到测试模式
train_acc=eval_on_dataloader("train",train_loader,train_data.__len__())
test_acc=eval_on_dataloader("test",test_loader,test_data.__len__())
train_accs.append(train_acc)
test_accs.append(test_acc)
print("epoch:",epoch,"train_acc:",train_acc," test_acc:",test_acc)
print('Finished Training')
plot_train_and_test_result(train_accs,test_accs)
plt.show()