3.5 mnist简单数据识别-使用L2正则化抵抗过拟合
# 不使用Dropout,改用更复杂的网络结构
# 使用L2正则化来抵抗过拟合
# 即增加带参项,降低参数的影响,使参数趋近于0,使模型更加平滑
# 手写数字
import numpy as np
from torch import nn,optim
from torch.autograd import Variable
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import torch
# 训练集
train_dataset=datasets.MNIST(root='./',train=True,transform=transforms.ToTensor(),download=True)
# 测试集
test_dataset=datasets.MNIST(root='./',train=False,transform=transforms.ToTensor(),download=True)
# 批次大小
batch_size =64
# 装载训练集
train_loader= DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
# 装载测试集
test_loader= DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=True)
for i,data in enumerate(train_loader):
inputs,labels=data
print(inputs.shape)
print(labels.shape)
break
## torch.Size([64, 1, 28, 28])
## torch.Size([64])
# 定义网络结构
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
# 定义较为复杂的带有两个隐藏层的3层神经网络,并混合Dropout封装起来 p=0 Dropout不起作用
self.layer1=nn.Sequential(nn.Linear(784,500),nn.Dropout(p=0),nn.Tanh())
self.layer2=nn.Sequential(nn.Linear(500,300),nn.Dropout(p=0),nn.Tanh())
self.layer3=nn.Sequential(nn.Linear(300,10),nn.Softmax(dim=1))
def forward(self,x):
#([64, 1, 28, 28])->(64,784) -1表示自动匹配
x=x.view(x.size()[0],-1)
x=self.layer1(x)
x=self.layer2(x)
x=self.layer3(x)
return x
LR=0.5
# 定义模型
model=Net()
# 定义代价函数
mse_loss=nn.CrossEntropyLoss()
# 定义优化器,设置L2正则化
optimizer=optim.SGD(model.parameters(),LR,weight_decay=0.001)
# 模型训练
def train():
# 模型的训练状态,Dropout起作用
model.train()
for i,data in enumerate(train_loader):
# 获得一个批次的数据和标签
inputs,labels=data
# 获得模型预测值
out=model(inputs)
# 交叉熵代价函数,不需要shape一致,它会自动独热编码
loss=mse_loss(out,labels)
# 梯度清0
optimizer.zero_grad()
# 梯度计算
loss.backward()
# 修改权值
optimizer.step()
# 模型测试
def test():
# 模型的测试状态,Dropout不起作用,所有神经元均参与计算
model.eval()
correct=0
# 计算训练集上的准确率
for i,data in enumerate(train_loader):
# 获得一个批次的数据和标签
inputs,labels=data
# 获得模型预测值
out=model(inputs)
# 获得最大值(忽略),以及最大值所在的位置
_,predicted=torch.max(out,1)
# 计算正确的个数
correct+=(predicted==labels).sum()
# 输出正确率
print("Train acc:{0}".format(correct.item()/len(train_dataset)))
correct=0
# 计算测试集上的准确率
for i,data in enumerate(test_loader):
# 获得一个批次的数据和标签
inputs,labels=data
# 获得模型预测值
out=model(inputs)
# 获得最大值(忽略),以及最大值所在的位置
_,predicted=torch.max(out,1)
# 计算正确的个数
correct+=(predicted==labels).sum()
# 输出正确率
print("Test acc:{0}".format(correct.item()/len(test_dataset)))
# 效果变好了主要是因为神经网络变复杂了
# 用了正则化效果是变差了一些,但是可以起到过拟合的作用,训练集和测试集准确率非常接近。在模型复杂的时候使用较好。
for epoch in range(20):
print('epoch:',epoch)
train()
test()
## epoch: 0
## Train acc:0.8887333333333334
## Test acc:0.8909
## epoch: 1
## Train acc:0.9219166666666667
## Test acc:0.9216
## epoch: 2
## Train acc:0.92545
## Test acc:0.9264
## epoch: 3
## Train acc:0.9308666666666666
## Test acc:0.9304
## epoch: 4
## Train acc:0.93825
## Test acc:0.9378
## epoch: 5
## Train acc:0.94185
## Test acc:0.9405
## epoch: 6
## Train acc:0.9449166666666666
## Test acc:0.9415
## epoch: 7
## Train acc:0.9478
## Test acc:0.9463
## epoch: 8
## Train acc:0.9519666666666666
## Test acc:0.9489
## epoch: 9
## Train acc:0.9487666666666666
## Test acc:0.9452
## epoch: 10
## Train acc:0.9546666666666667
## Test acc:0.9521
## epoch: 11
## Train acc:0.9563166666666667
## Test acc:0.9538
## epoch: 12
## Train acc:0.9582166666666667
## Test acc:0.9545
## epoch: 13
## Train acc:0.9578833333333333
## Test acc:0.9537
## epoch: 14
## Train acc:0.9563666666666667
## Test acc:0.9521
## epoch: 15
## Train acc:0.9396166666666667
## Test acc:0.9381
## epoch: 16
## Train acc:0.9619166666666666
## Test acc:0.9564
## epoch: 17
## Train acc:0.9567666666666667
## Test acc:0.9547
## epoch: 18
## Train acc:0.9589166666666666
## Test acc:0.9559
## epoch: 19
## Train acc:0.9610333333333333
## Test acc:0.9601
Comments NOTHING