激活函数Relu对精度和损失的影响研究

简介: 激活函数Relu对精度和损失的影响研究

1 问题

在学习深度学习的过程中,欲探究激活函数Relu对精度和损失的影响。


2 方法

测试设置激活函数时和没有设置激活函数时网络的性能。

控制其余变量:

  • Beach_size=128
  • optimizer = torch.optim.SGD
  • 网络为三层全连接网络(784->512->10)
  • 训练周期=50

测试代码如下

from torchvision import datasets
from torchvision.transforms import ToTensor
from torch import nn
import torch
from torch.utils.data import DataLoader
import torch.nn.functional as F
import matplotlib.pyplot as plt
from collections import defaultdict
# (5)定义三层全连接网络
# (5.1)创建一个新的类继承nn.Module
class MyNet(nn.Module):
   # (5.2) 定义网络有哪些层,这些层都作为成员变量
   def __init__(self) -> None:
       super().__init__()
       # 第一层,第一个全连接层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=torch.flatten(x,1)
       x = self.fc1(x)  # 输出:512,Layer 2
       # x=F.relu(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的训练网络
   for batch_ind, (X,y) in enumerate(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产生一个loss
       correct+=(pred.argmax(1)==y).type(torch.float).sum().item()
       #f-str
       if batch_ind % 100==0:
           print(f'[{batch_ind+1 :>5d} / {batch_num :>5d}], loss:{loss.item()}')
   #统计一个周期的平均loss
   avg_loss=epoch_loss/batch_num
   avg_accurcy = correct / size
   return  avg_accurcy,avg_loss
def test(dataloder,net,loss):
   size=len(dataloder.dataset)
   batch_num = len(dataloder)
   net.eval()
   losses=0
   correct = 0
   with torch.no_grad():
       for X,y in dataloder:
           X,y = X.to(device),y.to(device)
           pred = net(X)
           loss = loss_fn(pred,y)
           losses+=loss.item() #一个batch产生一个loss
           correct+=(pred.argmax(1) ==y).type(torch.int).sum().item()
   accuracy = correct / size
   avg_loss = losses /batch_num
   print(f'accuracy is {accuracy*100}%')
   return accuracy,avg_loss
#数据的获取
class getData:
   def __init__(self):
       self.train_ds = datasets.MNIST(
           root='data',
           download=True,
           train=True,
           transform=ToTensor(),  # 将原始的数据格式(PIL)转换为Tensor格式
       )
       # 测试集:评估模型的性能/效果
       self.text_ds = datasets.MNIST(
           root='data',
           download=True,
           train=False,
           transform=ToTensor(),
       )
       # print(train_ds[0])
       # print(text_ds[0])
       # (3)
       self.train_loader = DataLoader(
           dataset=self.train_ds,
           batch_size=128,  # 将60000个数据分成每一段的大小是128
           shuffle=True,  # 每一次我去拿那个128的数据都是打乱的,不是有序的。1-60000 打乱数据的次序,一般用于训练集,不需要在测试集
       )
       # (4)
       # 训练集共有469个batch  469*128
       # print("训练集的batch{}".format(len(train_loader)))
       self.test_loader = DataLoader(
           dataset=self.text_ds,
           batch_size=128,
       )
if __name__=='__main__':
   #(0)测试机器是否支持GPU
   batch_size=128
   device='cuda' if torch.cuda.is_available() else 'cpu'
   # print(device)
   train_ds = datasets.MNIST(
       root='data',
       download=True,
       train=True,
       transform=ToTensor(),  # 将原始的数据格式(PIL)转换为Tensor格式
   )
   # 测试集:评估模型的性能/效果
   text_ds = datasets.MNIST(
       root='data',
       download=True,
       train=False,
       transform=ToTensor(),
   )
  #(1.1)将训练集划分为训练集+验证集
   train_ds,val_ds= torch.utils.data.random_split(train_ds,[50000,10000])
   # (3)
   train_loader = DataLoader(
       dataset=train_ds,
       batch_size=batch_size,  # 将60000个数据分成每一段的大小是128
       shuffle=True,  # 每一次我去拿那个128的数据都是打乱的,不是有序的。1-60000 打乱数据的次序,一般用于训练集,不需要在测试集
   )
   val_loder = DataLoader(
       dataset=val_ds,
       batch_size=batch_size,
   )
   # (4)
   # 训练集共有469个batch  469*128
   # print("训练集的batch{}".format(len(train_loader)))
   test_loader = DataLoader(
       dataset=text_ds,
       batch_size=batch_size,
   )
   #(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.15)
   #损失函数
   #衡量yy与y_hat之前的差异
   loss_fn=nn.CrossEntropyLoss()
   #训练一下
   # train(train_loader,net,loss_fn,optimizer)
   #一个周期表示一个完整的训练集
   #训练100个周期epoch
   train_loss=[] #记录所有周期的平均loss
   train_acc_list,train_loss_list,val_acc_list,val_loss_list=[],[],[],[]
   #找出周期内最好的模型
   #评价标准:验证集的精度
   best_acc=0
   for epoch in range(50):
       print('-'*50)
       print(f'eopch:{epoch+1}')
       train_accuracy,train_loss=train(train_loader,net,loss_fn,optimizer)
       val_accuracy,val_loss =test(train_loader,net,loss_fn)
       print(f'train acc:{train_accuracy},train_val:{train_loss}')
       train_acc_list.append(train_accuracy)
       train_loss_list.append(train_loss)
       val_acc_list.append(val_accuracy)
       val_loss_list.append(val_loss)
       if val_accuracy > best_acc:
           best_acc = val_accuracy
           #保存当前模型
           torch.save(net.state_dict(),'model_best.pth')
   #(7)评估模型`
   #加载最好的模型
   net.load_state_dict(torch.load('model_best.pth'))
   print('the best val_acc is:')
   test(test_loader,net,loss_fn)
   plt.figure()
   ax1=plt.subplot(121)
   plt.plot([i for i in range(len(train_acc_list))],train_acc_list,ls='-',c='b')
   plt.title('accuracy')
   plt.xlabel('epoch')
   plt.ylabel('number')
   ax = plt.subplot(122)
   plt.plot([i for i in range(len(train_loss_list))], train_loss_list, ls='-', c='b')
   plt.title('loss')
   plt.xlabel('epoch')
   plt.ylabel('number')
   plt.show()

最后无激活函数时结果如图所示:

有激活函数时结果如图所示:


3 结语

通过实验发现,在未使用激活函数时,通过不断地训练模型,模型的准确率和损失率都时比较稳定地上升和下降,但是在上升和下降地过程中会出现抖动地情况,但是使用激活函数之后,模型的准确率和损失率就会上升和下降的非常平滑,更有利于实验的进行,以及对模型行为的预测。

目录
相关文章
|
22小时前
|
机器学习/深度学习 数据可视化 算法
R语言多分类logistic逻辑回归模型在混合分布模拟单个风险损失值评估的应用
R语言多分类logistic逻辑回归模型在混合分布模拟单个风险损失值评估的应用
|
22小时前
|
机器学习/深度学习 资源调度 算法
深度学习模型数值稳定性——梯度衰减和梯度爆炸的说明
深度学习模型数值稳定性——梯度衰减和梯度爆炸的说明
22 0
|
22小时前
|
机器学习/深度学习 监控 Python
【顶刊2023】重新审视Dropout层的作用,不止可有效防止过拟合!来源:《Dropout Reduces Underfitting》
【顶刊2023】重新审视Dropout层的作用,不止可有效防止过拟合!来源:《Dropout Reduces Underfitting》
38 1
【顶刊2023】重新审视Dropout层的作用,不止可有效防止过拟合!来源:《Dropout Reduces Underfitting》
|
9月前
|
机器学习/深度学习 数据采集 人工智能
放弃Softmax,首个线性注意力Transformer大模型:1750亿参数,速度、精度更优
放弃Softmax,首个线性注意力Transformer大模型:1750亿参数,速度、精度更优
|
11月前
|
数据可视化
探索不同学习率对训练精度和Loss的影响
探索不同学习率对训练精度和Loss的影响
184 0
|
11月前
|
数据可视化
探索VGG网络与LeNet网络对精度的影响
探索VGG网络与LeNet网络对精度的影响
47 0
|
机器学习/深度学习 数据可视化 计算机视觉
图像分类_03分类器及损失:线性分类+ SVM损失+Softmax 分类+交叉熵损失
解释:w的每⼀⾏都是其中⼀个类的分类器。这些数字的⼏何解释是,当我们改变w的⼀行时,像素空间中相应的线将以不同的⽅向旋转。⽽其中的偏置是为了让我们避免所有的分类器都过原点。
112 0
|
机器学习/深度学习
损失函数:均方误和交叉熵,激活函数的作用
损失函数(loss function)或代价函数(cost function)是将随机事件或其有关随机变量的取值映射为非负实数以表示该随机事件的“风险”或“损失”的函数。
152 1
损失函数:均方误和交叉熵,激活函数的作用
|
机器学习/深度学习 数据挖掘
精度是远远不够的:如何最好地评估一个分类器?
精度是远远不够的:如何最好地评估一个分类器?
129 0
精度是远远不够的:如何最好地评估一个分类器?
|
数据可视化 TensorFlow 算法框架/工具
Dropout 与过拟合抑制 | 学习笔记
快速学习 Dropout 与过拟合抑制
75 0
Dropout 与过拟合抑制 | 学习笔记

相关实验场景

更多