1 问题
在学习深度学习的过程中,欲探究优化器的学习率对精度和损失的影响。
2 方法
测试不同学习率下网络的性能。
控制其余变量:
Beach_size=256
optimizer = torch.optim.SGD
网络为三层全连接网络(784->512->10)
训练周期=100
测试代码如下
from torchvision import datasets from torchvision.transforms import ToTensor from torch import nn import torch from torch.utils.data import DataLoader import matplotlib.pyplot as plt import numpy as np from collections import defaultdict 任务:
# (5)定义三层全连接网络 # (5.1)创建一个新的类继承nn.Module class MyNet(nn.Module): # (5.2) 定义网络有哪些层,这些层都作为成员变量 def __init__(self) -> None: super().__init__() self.flatten = nn.Flatten() # 将28*28的图像拉伸为784维向量 # 第一层,第一个全连接层Full Connection(FC) # in_features表示该层的前面一层神经元个数 # out_features表示当前这的一层神经元个数 # 对应图里面layer2 self.fc1 = nn.Linear(in_features=784, out_features=512) # in_features就是这一层的输入是多少纬的向量, # 对应layer3 也是就输出层 self.fc2 = nn.Linear(in_features=512, out_features=10) # feature特征 # (5.3) 定义数据在网络中的流动 x就表示输入 # x - 28*28的图像 def forward(self, x): x = self.flatten(x) # 输出:784, 对应图中的layer1 # print(x) x = self.fc1(x) # 输出:512,Layer 2 # print(x) out = self.fc2(x) # 输出:10,Layer 3 return out #(7)训练网络 #loss_list:记录每一个周期的平均loss数据 def train(dataloader,net,loss_fn,optimizer): size=len(dataloader.dataset) epoch_loss=0.0 batch_num=len(dataloader)#有多少个batch net.train() #精度=预测正确的数量/总数量 correct=0 #一个batch一个batch的训练网络 s=0 for X,y in dataloader: X,y=X.to(device),y.to(device) #gpu上运行X,y pred = net(X) #衡量y与y_hat之前的loss #y:128 ,pred:128*10 CrossEntropyLoss处理的 loss=loss_fn(pred,y) #基于loss信息利用优化器从后向前更新网络的全部参数 optimizer.zero_grad() loss.backward() optimizer.step() # print(f"batch index: {ind},loss:{loss.item()}")#item()方法将单个tensor转化成一个数字 epoch_loss+=loss.item() #每一个batch产生一个lossm #训练正确的个数 correct+=(pred.argmax(1)==y).type(torch.float).sum().item() # print((pred.argmax(1)==y).type(torch.float).sum().item()) # if s%100==0: # print(s) # s+=1 #统计一个周期的平均loss avg_loss=epoch_loss/batch_num avg_accuracy=correct/size return avg_accuracy,avg_loss #验证网络 def val(dataloader,net,loss_fn): size=len(dataloader.dataset) val_losses=0 batch_num=len(dataloader) correct=0 net.eval() with torch.no_grad(): for X,y in dataloader: X,y=X.to(device),y.to(device) pred=net(X) loss=loss_fn(pred,y) val_losses+=loss.item()#一个batch是一个loss值 correct+=(pred.argmax(1)==y).type(torch.int).sum().item()#一个batch的正确的数量 accuracy=correct/size avg_loss=val_losses/batch_num print(accuracy) print(f"正确率是{accuracy * 100}%") return accuracy,avg_loss #(8)评估网络 def tet(dataloader,net,loss_fn): size=len(dataloader.dataset) correct=0 #当前处于评估阶段 evaluation net.eval() with torch.no_grad(): for X,y in dataloader: X,y=X.to(device),y.to(device) #gpu上运行X,y #每次遍历是是一个batch pred=net(X) #128*10 #当前batch的正确的数量 correct+=(pred.argmax(1)==y).type(torch.int).sum().item() accuracy=correct/size print(accuracy) print(f"正确率是{accuracy*100}%") return accuracy*100 #数据集的获取 class getData: def __init__(self,batch_size): self.batch_size=batch_size # self.train_ds = datasets.MNIST( # root='data', # download=True, # train=True, # transform=ToTensor(), # 将原始的数据格式(PIL)转换为Tensor格式 # ) # (1,1)将训练集划分为训练集+验证集 self.train_ds,self.val_ds=torch.utils.data.random_split(datasets.MNIST( root='data', download=False, train=True, transform=ToTensor(), # 将原始的数据格式(PIL)转换为Tensor格式 ),[50000,10000]) # 测试集:评估模型的性能/效果 self.text_ds = datasets.MNIST( root='data', download=False, train=False, transform=ToTensor(), ) # print(train_ds[0]) # print(text_ds[0]) # (3) self.train_loader = DataLoader( dataset=self.train_ds, batch_size=self.batch_size, # 将60000个数据分成每一段的大小是128 shuffle=True, # 每一次我去拿那个128的数据都是打乱的,不是有序的。1-60000 打乱数据的次序,一般用于训练集,不需要在测试集 ) self.val_loader = DataLoader( dataset=self.val_ds, batch_size=self.batch_size, ) # (4) # 训练集共有469个batch 469*128 # print("训练集的batch{}".format(len(train_loader))) self.test_loader = DataLoader( dataset=self.text_ds, batch_size=self.batch_size, ) if __name__=='__main__': #(0)测试机器是否支持GPU device='cuda' if torch.cuda.is_available() else 'cpu' loss_fn = nn.CrossEntropyLoss() lr_list=[0.1, 0.01, 0.001, 0.0001] lr_train_ac=[] lr_train_loss=[] lr_val_ac=[] lr_val_loss=[] for i in lr_list: print("-"*100) lr_train_ac_d= [] lr_train_loss_d = [] lr_val_ac_d = [] lr_val_loss_d = [] data = getData(256) trains = data.train_loader vals = data.val_loader net = MyNet().to(device) optimizer = torch.optim.SGD(net.parameters(), i) for j in range(100): print("*"*100) # (6)网络的输入、输出以及测试网络的性能(不经过任何训练的网络) # net = MyNet().to(device) # to()GPU上运行该网络 # 网络训练模型 # X, 真实的标签y, 网络预测的标签y_hat # 目标: y_hat越来越接近y # 算法:mini-bacth 梯度下降 # 优化器 # 具体实现梯度下降算法的传播 # SGD随机梯度下降学习度 # y=ax+b # optimizer = torch.optim.SGD(net.parameters(), lr=0.001) # 损失函数 # 衡量yy与y_hat之前的差异 # loss_fn = nn.CrossEntropyLoss() l,s=train(trains,net,loss_fn,optimizer) d,k=val(vals,net,loss_fn) lr_train_ac_d.append(l) lr_train_loss_d.append(s) lr_val_ac_d.append(d) lr_val_loss_d.append(k) lr_train_ac.append(lr_train_ac_d) lr_train_loss.append(lr_train_loss_d) lr_val_ac.append(lr_val_ac_d) lr_val_loss.append(lr_val_loss_d) sss=[] sss.append(lr_train_ac) sss.append(lr_train_loss) sss.append(lr_val_ac) sss.append(lr_val_loss) lala=["train_accuracy","train_loss","validate_accuracy","validate_loss"] fig = plt.figure(figsize=(15, 15), dpi=100) c = 0 for i in sss: c += 1 ax = fig.add_subplot(2, 2, c) fig.suptitle("Predictions") plt.xlabel("epoch") plt.ylabel(lala[c-1]) plt.title(lala[c-1]+" Graph") ax.plot(i[0], color='g', label='batch_size_8') ax.plot(i[1], color='red', label='batch_size_16') ax.plot(i[2], color='pink', label='batch_size_32') ax.plot(i[3], color='blue', label='batch_size_64') ax.plot(i[4], color='yellow', label='batch_size_128') ax.plot(i[5], color='black', label='batch_size_256') ax.legend() plt.savefig("predictions.svg") plt.show() plt.clf() plt.close() |
最后结果如图所示。
3 结语
通过实验发现,在0.1到0.0001的学习率区间上,学习率越大,在训练集和验证集上的准确度就越大,loss就越小。本文的对batch_size,优化器的设置可能不是最佳,未来可以继续研究batch_size,优化器等因素对精度和损失的影响。