PyTorch深度学习实战(4)——常用激活函数和损失函数详解

news2024/12/28 19:51:28

PyTorch深度学习实战(4)——常用激活函数和损失函数详解

    • 0. 前言
    • 1. 常用激活函数
      • 1.1 Sigmoid 激活函数
      • 1.2 Tanh 激活函数
      • 1.3 ReLU 激活函数
      • 1.4 线性激活函数
      • 1.5 Softmax 激活函数
    • 2. 常用损失函数
      • 2.1 均方误差
      • 2.2 平均绝对误差
      • 2.3 分类交叉熵
    • 2.4 实现自定义损失函数
    • 小结
    • 系列链接

0. 前言

激活函数和损失函数是深度学习模型中重要组成部分,激活函数和损失函数的选择很大程度上决定了深度神经网络的性能和精度,需要根据具体问题的特点和数据分布等因素进行选择。在本节中,将介绍深度学习中常见的激活函数和损失函数,并说明不同函数的常见应用场景。

1. 常用激活函数

使用激活函数可以实现网络的高度非线性,这对于建模输入和输出之间的复杂关系非常关键。如果没有非线性激活函数,那么该网络将仅仅能够表达简单的线性映射,即便有再多的隐藏层,其整个网络跟单层神经网络也是等价的,只有加入了非线性激活函数之后,深度神经网络才具备了令人惊异的非线性映射学习能力,可以在网络中的多个层中应用激活函数。

1.1 Sigmoid 激活函数

sigmoid 是使用范围最广的一类激活函数,其取值范围为 [0, 1],它可以将一个实数映射到 [0, 1] 的区间,可以将其用于二分类问题。

Sigmoid 函数公式定义如下所示:

s i g m o i d ( x ) = 1 1 + e − x sigmoid(x)=\frac 1 {1+e^{-x}} sigmoid(x)=1+ex1

使用 Python 实现此函数:

def sigmoid(x):
     return 1/(1+np.exp(-x))

函数图像如下所示,可以看到函数的形状如 S 曲线,因此也称为 S 型生长曲线:

Sigmoid

  • sigmoid 函数优点:平滑、易于求导。
  • sigmoid 函数缺点:反向传播求导涉及除法,因此计算量大;反向传播时,很容易就会出现梯度消失的情况,从而限制了深层网络的训练。

1.2 Tanh 激活函数

Tanh 是双曲函数的一种,其是 Sigmoid 激活函数的改进,是以零为中心的对称函数,其取值范围为 [-1, 1]Tanh 激活函数计算公式如下:
t a n h ( x ) = e x − e − x e x + e − x = 2 s i g m o i d ( 2 x ) − 1 tanh(x) =\frac {{e^x} -e^{-x}} {{e^x} +e^{-x}}=2sigmoid(2x)-1 tanh(x)=ex+exexex=2sigmoid(2x)1
使用 Python 实现此函数:

def tanh(x):
    return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))

函数图像如下所示,它在开区间 (-1, 1) 内是单调递增的奇函数,函数图形关于原点对称:

tanh

  • tanh 函数优点:tanh 函数是 sigmoid 函数的改进,收敛速度快,不易出现 loss 值晃动。

  • tanh 函数缺点:无法解决梯度弥散的问题,函数的计算量同样是指数级的,计算相对复杂。

1.3 ReLU 激活函数

修正线性单元 (Rectified Linear Units, ReLU) 激活函数是 sigmoidtanh 激活函数的完美替代激活函数,是深度学习领域最重要的突破技术之一。ReLU 激活函数计算公式如下:

r e l u ( x ) = { 0 , x < 0 x , x ≥ 0 relu(x) = \begin{cases} 0, & {x<0} \\ x, & {x\ge0} \end{cases} relu(x)={0,x,x<0x0
使用 Python 实现此函数:

def relu(x):
    return np.where(x>0, x, 0)

函数图像如下所示,当输入值 大于等于 0 时,则 ReLU 函数按原样输出。如果输入小于 0,则 ReLU 函数值为 0。因为 ReLU 函数的大于等于 0 的线性分量具有固定导数,而对另一个线性分量导数为 0。因此,使用 ReLU 函数训练模型要快得多。

ReLU

  • ReLU 函数优点:不存在梯度消失问题,计算成本很低,收敛速度比 sigmoidtanh 函数快得多。
  • ReLU 函数缺点:当梯度值过大时,其权重更新后为负数,在 ReLU 函数中导数恒为零,导致后面的梯度也不再更新,也被称为 dying ReLU 问题。

1.4 线性激活函数

线性激活的输出是输入值本身,按原样输出输入值:
l i n e a r ( x ) = x linear(x) = x linear(x)=x
使用 Python 实现此函数:

def linear(x):
    return x

线性激活函数
该函数仅用于解决回归问题的神经网络模型的输出层,注意不能在隐藏层中使用线性激活函数。

1.5 Softmax 激活函数

通常,softmax 在神经网络输出最终结果前使用。通常使用 softmax 是为了确定输入在给定场景中属于 n 个可能的输出类别之一的概率。假设我们正在尝试将数字图像分类为可能的 10 类(数字从0到9)之一。在这种情况下,有 10 个输出值,其中每个输出值代表输入图像属于某个类别的概率。Softmax 激活函数计算公式如下:

s o f t m a x ( x i ) = e i ∑ j = 0 N e j softmax(x_i)=\frac {e^i} {\sum _{j=0} ^N e^j} softmax(xi)=j=0Nejei

softmax 激活用于为输出中的每个类别提供一个概率值,其中 i i i 表示输出的索引。使用 Python 实现此函数:

def softmax(x):
    return np.exp(x) / np.sum(np.exp(x))

softmax 函数一般作为神经网络的最后一层,接受来自上一层网络的输入值,然后将其转化为概率。例如我们要识别一张图片,其可能的标签为 [apple, banana, lemon, pear],则网络最后一层值 [1.0, 2.0, 3.0, 4.0] 经过 softmax 函数后输出为 [0.0320586, 0.08714432, 0.23688282, 0.64391426]

2. 常用损失函数

利用损失函数计算损失值,模型就可以通过反向传播去更新各个参数,通过降低真实值与预测值之间的损失,使得模型计算得到的预测值趋近于真实值,从而达到模型训练的目的,损失函数的选择取决于问题的类型和所需的输出结果。损失函数需要为非负实值函数。

2.1 均方误差

误差是网络输出的预测值与实际值之差。我们对误差取平方,是因为误差可以是正值或负值。平方确保正误差和负误差不会相互抵消。我们计算均方误差 (Mean Square Error, MSE),以便当两个数据集的大小不相同时,它们间的误差是可比较的。预测值 (p) 和实际值 (y) 之间的均方误差计算如下:
m s e ( p , y ) = 1 n ∑ i = 1 n ( p − y ) 2 mse(p,y)=\frac 1 n \sum _{i=1} ^n(p-y)^2 mse(p,y)=n1i=1n(py)2

使用 Python 实现此函数:

def mse(p, y):
    return np.mean(np.square(p - y))

当神经网络需要预测连续值时,通常使用均方误差。

2.2 平均绝对误差

平均绝对误差 (Mean Absolute Error, MSE) 的工作方式与均方误差非常相似。平均绝对误差通过对所有数据点上的实际值和预测值之间的绝对差值取平均值,从而确保正误差和负误差不会相互抵消。预测值 (p) 和实际值 (y) 之间的平均绝对误差的实现方式如下:
m s e ( p , y ) = 1 n ∑ i = 1 n ∣ p − y ∣ mse(p,y)=\frac 1 n \sum _{i=1} ^n|p-y| mse(p,y)=n1i=1npy
使用 Python 实现此函数:

def mae(p, y):
    return np.mean(np.abs(p - y))

与均方误差相似,平均绝对误差通常用于连续变量值的预测。

2.3 分类交叉熵

交叉熵是对两种不同分布(实际分布和预测分布)之间差异的度量。与上述两个损失函数不同,它被广泛用于离散值输出数据。两种分布之间的交叉熵计算如下:

− ( y l o g 2 p + ( 1 − y ) l o g 2 ( 1 − p ) ) -(ylog_2p+(1-y)log_2(1-p)) (ylog2p+(1y)log2(1p))

y y y 是实际结果, p p p 是预测结果。预测值 (p) 和实际值 (y) 之间的分类交叉熵的 python 实现方式如下:

def categorical_cross_entropy(p, y):
    return -np.sum((y*np.log2(p) + (1-y)*np.log2(1-p)))

当预测值远离实际值时,分类交叉熵损失具有较高的值,而当与实际值接近时,分类交叉熵损失具有较低的值。

2.4 实现自定义损失函数

在实际场景中,我们可能必须实现针对需要解决的问题自定义损失函数,尤其是在涉及目标检测、生成对抗网络等复杂神经网络中,PyTorch 提供了通过编写函数来构建自定义损失函数的方法。
在本节中,我们将实现一个自定义损失函数,它与 nn.Module 中预构建的 MSELoss 函数功能相同。

(1) 导入数据,构建数据集和 DataLoader,并定义神经网络:

x = [[1,2],[3,4],[5,6],[7,8]]
y = [[3],[7],[11],[15]]
import torch
X = torch.tensor(x).float()
Y = torch.tensor(y).float()
import torch.nn as nn
device = 'cuda' if torch.cuda.is_available() else 'cpu'
X = X.to(device)
Y = Y.to(device) 
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
class MyDataset(Dataset):
    def __init__(self,x,y):
        self.x = x.clone().detach() # torch.tensor(x).float()
        self.y = y.clone().detach() # torch.tensor(y).float()
    def __len__(self):
        return len(self.x)
    def __getitem__(self, ix):
        return self.x[ix], self.y[ix]
ds = MyDataset(X, Y)
dl = DataLoader(ds, batch_size=2, shuffle=True)
class MyNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.input_to_hidden_layer = nn.Linear(2,8)
        self.hidden_layer_activation = nn.ReLU()
        self.hidden_to_output_layer = nn.Linear(8,1)
    def forward(self, x):
        x = self.input_to_hidden_layer(x)
        x = self.hidden_layer_activation(x)
        x = self.hidden_to_output_layer(x)
        return x
mynet = MyNeuralNet().to(device)

(2) 定义自定义损失函数,将两个张量对象作为输入,计算它们的差的平方,并返回两者平方差的平均值:

def my_mean_squared_error(_y, y):
    loss = (_y-y)**2
    loss = loss.mean()
    return loss

(3) 使用相同的输入和输出组合,调用内置的 MSELoss 函数,并将其结果与我们构建的自定义函数进行比较。

利用 nn.MSELoss 获取均方误差损失:

loss_func = nn.MSELoss()
loss_value = loss_func(mynet(X),Y)
print(loss_value)
# tensor(151.1184, device='cuda:0', grad_fn=<MseLossBackward>)

使用自定义损失函数 my_mean_squared_error,输出损失值:

print(my_mean_squared_error(mynet(X),Y))
# tensor(151.1184, device='cuda:0', grad_fn=<MeanBackward0>)

通常,使用怎样的自定义函数,具体取决于我们正在解决的问题。

小结

激活函数是深度学习神经网络中的一种函数,其作用是将输入信号进行“激活”,输出一个非线性的结果,本节中,介绍了常用的激活函数包括 SigmoidReLUSoftmax 等;损失函数是指在训练神经网络时,用于衡量模型预测值和真实值之间的差距的函数,本节中,介绍了常用的损失函数包括均方误差、交叉熵、对数损失等。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/675723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享一组开关按钮

先看效果&#xff1a; 再看代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>豆子开关</title><style>* {margin: 0;padding: 0;box-sizing: border-box;-webkit-tap-hi…

STM32单片机(八)DMA直接存储器存取----第一节:DMA直接存储器存取

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

使用Python制作简单的图表并设置图表元素

案例01 在python中制作简单的图表 import matplotlib.pyplot as plt # 导入matplotlib模块 x [1, 2, 3, 4, 5, 6] # 给出x坐标的数据 y [2, 4, 6, 8, 10, 12] # 给出y坐标的数据 plt.plot(x, y, color red, linewidth 3, linestyle solid) # 绘制折线图 plt.show() # …

动态库的入口——VCRT(DLL)和CRT(SO)

摘要&#xff1a;为了更加深入的理解动态库的加载初始化过程&#xff0c;本文根据VCRT和Linux-CRT的代码实现详细描述了windows和linux平台下对应动态库加载时会进行哪些工作。本文重点关注全局变量的初始化时机&#xff0c;以及是否有其他额外的操作。   关键字&#xff1a;…

被微服务循环依赖调用坑了 !

最近的迭代转测后&#xff0c;遇到了一个比较有意思的问题。系统在测试环境整体运行还算平稳&#xff0c;但是过一段时间之后&#xff0c;就开始有接口超时了&#xff0c;日志中出现非常多的 “java.net.SocketTimeoutException: Read timed out”。 试了几次重启大法&#xf…

用魔法打败魔法!用AI制作AI分割数据集!

本节内容我们使用SAM将边界框转换为分割数据集&#xff0c;这对于实例分割数据集的制作非常有用&#xff0c;下面我会一步步给出我的代码&#xff0c;希望对你有用。 有兴趣的朋友可以研究一下这本书&#xff0c;详细的介绍了数据集制作到分割的实际项目应用&#xff01; 步骤 …

【 计算机组成原理 】期末重点

文章目录 前言第一章 【计算机系统概论】1.1 知识点1.1核心例题 第二章 【运算方法和运算器】2.1 知识点2.2 核心例题 第三章 【存储系统】3.1 知识点3.2 核心例题 第四章 【指令系统】4.1 知识点4.2 核心例题 第五章 【中央处理器】5.1 知识点5.2 核心例题 第六章6.1 知识点6.…

【MSP432电机驱动学习—上篇】TB6612带稳压电机驱动模块、MG310电机、霍尔编码器

所用控制板型号&#xff1a;MSP432P401r 今日终于得以继续我的电赛小车速通之路&#xff1a; 苏轼云 “ 素面常嫌粉涴 &#xff0c; 洗妆不褪朱红。 ” 这告诫我们不能只注重在表面粉饰虚伪的自己&#xff0c;要像梅花一样&#xff0c;不断磨砺自己的内在~ 后半句是 “…

JavaSE基础语法--类和对象

在Java中&#xff0c;一切皆为对象&#xff0c;类和对象是一个抽象的概念。我们可以从面向过程来过渡到面向对象。 那么什么是面向过程呢&#xff1f; 举一个简单的例子&#xff0c;现实生活中&#xff0c;你需要买一台手机的时候会经历如下步骤&#xff1a; 这里的每一步都可…

【python程序设计】——期末大作业

【python程序设计】——期末大作业&#x1f60e; 前言&#x1f64c;一、所用技术&#xff1a;二、 系统设计三、 系统实现3.1 核心功能代码实现&#xff1a;3.2 演示结果展示 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&am…

yaffs格式的根文件系统制作

linux内核启动后&#xff0c;它接下来要做的事就是启动应用程序&#xff0c;而应用程序在哪里呢&#xff0c;类比windows&#xff0c;启动时要读取c盘&#xff0c;所以linux的文件系统就类似于c盘&#xff0c;并且我们使用的ls、cp等一些类命令&#xff08;本质是应用程序&…

JavaScript 手写代码 第二期

文章目录 1.为什么要手写代码&#xff1f;2. 手写代码2.1 手写实现判断类型函数2.1.1 前置知识2.1.1 手写实现 2.2 手写实现aplly,call,bind方法2.2.1 基本使用2.2.2 实现思路2.2.3 手写实现 1.为什么要手写代码&#xff1f; 我们在日常开发过程中&#xff0c;往往都是取出来直…

Linux(centos7)缺失.bashrc文件登录出现bash-4.2

一、问题描述 最近遇到几次登陆linux&#xff08;centos7.5&#xff09;系统后&#xff0c;虽然在/root用户下&#xff0c;但出现了如下界面&#xff1a; 二、解决思路 使用不同的linux发行版本&#xff0c;&#xff08;比如&#xff1a;IP为*...90,以下简称90&#xff09;会…

课程19:个人中心功能与提示优化

🚀前言 本文是《.Net Core从零学习搭建权限管理系统》教程专栏的课程(点击链接,跳转到专栏主页,欢迎订阅,持续更新…) 专栏介绍:以实战为线索,基于.Net 7 + REST + Vue、前后端分离,不依赖任何第三方框架,从零一步一步讲解权限管理系统搭建。 专栏适用于人群:We…

Android中加载一张大图,如何正常显示且不发生OOM ?

问题 在Android中&#xff0c;获取一个1000*20000(宽1000px&#xff0c;高20000px)的大图&#xff0c;如何正常加载显示且不发生OOM呢? 分析 Android系统会为应用分配一定大小的堆内存 而如果遇到高分辨率图片时&#xff0c;如果它的配置为ARGB(每个像素占4Byte) 那么它要消…

深度学习(23)——YOLO系列(2)

深度学习&#xff08;23&#xff09;——YOLO系列&#xff08;2&#xff09; 文章目录 深度学习&#xff08;23&#xff09;——YOLO系列&#xff08;2&#xff09;1. model2. dataset3. utils4. test/detect5. detect全过程 今天先写YOLO v3的代码&#xff0c;后面再出v5&…

【PCB专题】案例:PCB板厂说焊盘宽度太小容易沉金不良,但加宽又可能导致阻焊桥在阻焊为黑色油墨下无法做出?

此案例是最近在Layout一块PCB板卡,使用了一个以前我没有接触过的器件,此器件的封装是QFN128。 总的问题是:PCB板厂说如果按原稿制作的话,焊盘宽度太小沉金容易不良,但电话里和我说如果加宽又可能导致阻焊桥在黑色油墨情况下无法做出? 板厂给的EQ如下所示,表示TOP面设计…

【Unity之IMGUI】—编译模式下控件可视化及其封装

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【从零开始开发一个线上网课系统-01】账号登录及退出登录功能开发

文章目录 1 视图层开发2 form表单验证3 配置urls.py4 模板层开发 实际上在系统开发的博客中应该先描述数据库设计&#xff0c;但由于设计的表比较多&#xff0c;其理解简单&#xff0c;但撰写和描述较为麻烦&#xff0c;所以我以可视化方式来呈现这些数据表以及其中的关系&…

RISCV Reader笔记_1 RISCV的意义

RISCV Reader RISCV的诞生 出众之处 RISCV架构被设计的目的就是成为一个通用的指令集架构 ISA。不仅支持从微控制器到高性能计算机的各种处理器&#xff0c;兼容各种编程语言&#xff0c;还适应FPGA ASIC等所有实现技术&#xff0c;稳定…… 计算机体系结构为了在指令集更新…