赞
踩
文章内容来自我的《深度学习》课程作业实验报告。
手写数字识别属于图像分类问题,通过对图像进行识别,将图像分为0-9的十个类别。
LeNet-5是一个经典的深度卷积神经网络,由Yann LeCun在1998年提出,旨在解决手写数字识别问题,被认为是卷积神经网络的开创性工作之一[2]。该网络是第一个被广泛应用于数字图像识别的神经网络之一,也是深度学习领域的里程碑之一。
LeNet-5模型结构如下:
使用交叉熵损失作为损失函数,计算公式如下:
使用精确度作为评价指标,计算公式如下:
其中:TP为真正例,TN为真负例,FP为假正例,FN为假负例。
Visual Studio Code
PyTorch 1.13
MNIST 数据集
获取数据集,这里Normalize()转换使用的值0.1307和0.3081是MNIST数据集的全局平均值和标准偏差。
- # 获取数据集
- data_path = '.\mnistdata'
- data_tf = torchvision.transforms.Compose(
- [
- torchvision.transforms.ToTensor(),
- torchvision.transforms.Normalize([0.1307],[0.3081])
- ]
- )
- train_data = mnist.MNIST(data_path,train=True,transform=data_tf,download=True)
- test_data = mnist.MNIST(data_path,train=False,transform=data_tf,download=True)
- train_loader = data.DataLoader(train_data,batch_size=batch_size,shuffle=True,pin_memory=False)
- test_loader = data.DataLoader(test_data,batch_size=batch_size)
定义LeNet-5模型网络结构
- class LeNet5(torch.nn.Module):
- def __init__(self):
- super(LeNet5,self).__init__()
- self.features = torch.nn.Sequential(
- torch.nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2, bias=True),
- torch.nn.MaxPool2d(kernel_size=2),
-
- torch.nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5,stride=1,padding=0,bias=True),
- torch.nn.MaxPool2d(kernel_size=2),
-
- torch.nn.Flatten()
- )
- self.classification = torch.nn.Sequential(
- torch.nn.Linear(16*5*5, 120),
- torch.nn.ReLU(inplace=True),
- torch.nn.Linear(120, 84),
- torch.nn.Linear(84, 10),
-
- )
-
- def forward(self, input):
- x=self.features(input)
- output=self.classification(x)
- return output
定义优化器与损失函数
- lr=0.005 #学习率
- momentum=0.8
- device=torch.device("cuda" if torch.cuda.is_available() else "cpu" )
- model=LeNet5().to(device)
- print(model)
- optimizer=torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum)
- closs=torch.nn.CrossEntropyLoss()
定义两个函数进行模型训练与测试。设置训练的epoch=9,batch=128,因为数据量比较大,iteration数量比较多,所以每50个iteration进行一次采样,将交叉熵误差和准确度进行打印输出,并进行最终的可视化分析制图。每一个epoch后,使用测试集数据进行测试,并输出交叉熵误差和准确度结果。
- # 网络训练
- def train(model,device,train_loader,optimizer,epoch,losses,accuracies):
-
- for idx,(t_data,t_target) in enumerate(train_loader):
- t_data,t_target=t_data.to(device),t_target.to(device)
- pred=model(t_data)#batch_size*10
- predictions = torch.argmax(pred, dim = 1)
- accuracy = torch.sum(predictions == t_target)/t_target.shape[0]
- loss=closs(pred,t_target)
-
- #SGD
- optimizer.zero_grad()#将上一步的梯度清0
- loss.backward()#重新计算梯度
- optimizer.step()#更新参数
- if idx%50==0:
- print("epoch:{},iteration:{},loss:{},accuracy:{}".format(epoch,idx,loss.item(),accuracy))
- losses.append(loss.item()) #每50批数据采样一次loss,记录下来,用来画图可视化分析。
- accuracies.append(accuracy.item())
-
- # 网络测试
- def test(model,valid_loader,criterion,valid_loss,valid_acc):
- model.eval()
- correct=0#预测对了几个。
- loss=0
- with torch.no_grad():
- for idx,(t_data,t_target) in enumerate(test_loader):
- t_data,t_target=t_data.to(device),t_target.to(device)
- pred=model(t_data)#batch_size*10
- pred_class=pred.argmax(dim=1)#batch_size*10->batch_size*1
-
- correct+=pred_class.eq(t_target.view_as(pred_class)).sum().item()
- loss+=closs(pred,t_target).item()
-
- acc_mean=correct/len(test_data)
- loss_mean=loss/len(test_loader)
- valid_loss.append(loss_mean)
- valid_acc.append(acc_mean)
- print("loss:{},accuracy:{},".format(loss_mean,acc_mean))
- model.train()
'运行
迭代过程中,交叉熵损失与精确度变化情况如上图所示。训练过程设置了epoch=9。在图中可以看出,在第5个epoch后,模型逐渐趋于稳定,并且没有出现明显的过拟合或欠拟合现象。迭代完成后,交叉熵损失为0.04,准确率为98.68%。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。