激活函数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 结语

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

目录
相关文章
|
9天前
|
机器学习/深度学习 算法
**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。
【6月更文挑战第28天】**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。数据从输入层流经隐藏层到输出层,计算预测值。接着,比较预测与真实值计算损失。然后,从输出层开始,利用链式法则反向计算误差和梯度,更新权重以减小损失。此过程迭代进行,直到损失收敛或达到训练次数,优化模型性能。反向传播实现了自动微分,使模型能适应训练数据并泛化到新数据。
19 2
|
2月前
|
数据挖掘 计算机视觉
YOLOv5改进 | 损失篇 | VarifocalLoss密集检测专用损失函数 (VFLoss,论文一比一复现)
YOLOv5改进 | 损失篇 | VarifocalLoss密集检测专用损失函数 (VFLoss,论文一比一复现)
277 1
|
9天前
|
机器学习/深度学习 算法 网络架构
**深度学习中的梯度消失与爆炸影响模型训练。梯度消失导致输入层参数更新缓慢,梯度爆炸使训练不稳。
【6月更文挑战第28天】**深度学习中的梯度消失与爆炸影响模型训练。梯度消失导致输入层参数更新缓慢,梯度爆炸使训练不稳。解决办法包括:换激活函数(如ReLU)、权重初始化、残差连接、批量归一化(BN)来对抗消失;梯度裁剪、权重约束、RMSProp或Adam优化器来防止爆炸。这些策略提升网络学习能力和收敛性。**
17 0
|
2月前
|
人工智能 测试技术 网络架构
DenseMamba:大模型的DenseNet时刻,Mamba和RetNet精度显著提升
【2月更文挑战第25天】DenseMamba:大模型的DenseNet时刻,Mamba和RetNet精度显著提升
82 7
DenseMamba:大模型的DenseNet时刻,Mamba和RetNet精度显著提升
|
2月前
|
机器学习/深度学习 数据可视化 算法
R语言多分类logistic逻辑回归模型在混合分布模拟单个风险损失值评估的应用
R语言多分类logistic逻辑回归模型在混合分布模拟单个风险损失值评估的应用
|
2月前
|
机器学习/深度学习 资源调度 算法
深度学习模型数值稳定性——梯度衰减和梯度爆炸的说明
深度学习模型数值稳定性——梯度衰减和梯度爆炸的说明
36 0
|
数据可视化
探索不同学习率对训练精度和Loss的影响
探索不同学习率对训练精度和Loss的影响
216 0
|
数据可视化
探索VGG网络与LeNet网络对精度的影响
探索VGG网络与LeNet网络对精度的影响
54 0
|
机器学习/深度学习 数据可视化 计算机视觉
图像分类_03分类器及损失:线性分类+ SVM损失+Softmax 分类+交叉熵损失
解释:w的每⼀⾏都是其中⼀个类的分类器。这些数字的⼏何解释是,当我们改变w的⼀行时,像素空间中相应的线将以不同的⽅向旋转。⽽其中的偏置是为了让我们避免所有的分类器都过原点。
126 0
|
机器学习/深度学习 TensorFlow 算法框架/工具
TensorFlow 神经网络优化:指数衰减学习率、滑动平均、正则化
TensorFlow 神经网络优化:指数衰减学习率、滑动平均、正则化
TensorFlow 神经网络优化:指数衰减学习率、滑动平均、正则化