掌握激活函数(一):深度学习的成功之源

news2025/2/25 18:30:19

文章目录

  • 引言
  • 基本概念
  • 常用激活函数举例
    • Sigmoid激活函数
      • 公式
      • Sigmoid函数的数学特性
      • 示例
        • 基于NumPy和PyTorch实现Sigmoid函数
        • 将Sigmoid函数应用于二分类任务
      • Sigmoid激活函数的局限性举例
    • ReLU激活函数
      • 公式
      • ReLU函数的数学特性
      • ReLU函数的特点
      • 示例
        • 基于NumPy和PyTorch实现ReLU函数
        • 搭建基于ReLU函数的卷积神经网络(CNN)
  • 结束语

引言

深度学习作为人工智能领域的一颗璀璨之星,其背后的神经网络模型是无数智能应用的基石。而在这些神经网络中,激活函数担任了不可或缺的角色。它们如同魔法一般,为神经网络带来了非线性特性,使其能够学习和模拟复杂的现实世界模式。没有激活函数,深度学习模型充其量只是一堆线性回归的堆叠。本文将带您逐渐深入掌握激活函数的原理、类型以及在深度学习中的应用,让您真正领略这背后的“魔法”之源。


基本概念

激活函数,也称为非线性激活函数,是神经网络中每一层的输出函数。在神经网络的构建中,激活函数发挥着至关重要的作用。它不仅赋予了神经元非线性特性,使得神经网络能够学习和模拟复杂的、非线性的数据模式,更是神经网络表达能力的核心驱动力。没有激活函数,神经网络将仅能执行线性的计算,极大地限制了其应用范围和表达能力。


常用激活函数举例

Sigmoid激活函数

Sigmoid函数是一种非常常用的激活函数,它可以将任何输入值映射到0到1之间。这个特性使得Sigmoid函数在二分类问题中特别受欢迎,因为输出可以被解释为属于某一类的概率

公式

Sigmoid函数的数学特性

特性描述
非线性Sigmoid函数可以将输入映射到0-1之间的任意值,允许神经网络学习和模拟复杂的非线性模式。
饱和性当输入值远离0时,Sigmoid函数的输出会非常接近0或1,这种现象称为饱和。
可微分性Sigmoid函数是连续且可微的,这意味着基于梯度的优化算法(如反向传播)能够有效地用于训练神经网络。

示例

基于NumPy和PyTorch实现Sigmoid函数
# 基于NumPy实现Sigmoid函数
import numpy as np

def sigmoid(x):
    # 将输入值转换为浮点数
    x = np.float32(x)
    # 计算sigmoid值
    return 1 / (1 + np.exp(-x))

# 基于PyTorch实现Sigmoid函数(使用PyTorch的内置函数torch.sigmoid())
import torch  
  
# 创建一个张量  
x = torch.tensor([-1.0, 0.0, 1.0])  
  
# 应用sigmoid函数  
y = torch.sigmoid(x)  
  
print(y)

# 基于PyTorch实现Sigmoid函数(手动实现)
import torch  

def sigmoid(x):  
    return 1 / (1 + torch.exp(-x))
  
# 创建一个张量  
x = torch.tensor([-1.0, 0.0, 1.0])

# 应用sigmoid函数  
y = sigmoid(x)  
将Sigmoid函数应用于二分类任务
import torch  
import torch.nn as nn  
import torchvision.transforms as transforms  
import torchvision.datasets as datasets  
  
# 定义超参数  
input_size = 784       # 输入图像的维度(28*28)  
hidden_size = 100       # 隐藏层的大小  
num_epochs = 10           # 训练周期数  
batch_size = 100           # 批处理大小  
learning_rate = 0.001       # 学习率  
  
# 加载数据集并进行预处理  
transform = ... # 待定
train_dataset = ... # 待定
test_dataset = ... # 待定
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)  
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)  
  
# 定义模型结构  
class NeuralNetwork(nn.Module):  
    def __init__(self, input_size, hidden_size):  
        super(NeuralNetwork, self).__init__()  
        self.fc1 = nn.Linear(input_size, hidden_size)   
        self.relu = nn.ReLU()  
        self.fc2 = nn.Linear(hidden_size, 1)    
        self.sigmoid = nn.Sigmoid()  # 添加Sigmoid激活函数  
      
    def forward(self, x):  
        out = self.fc1(x)  
        out = self.relu(out)  
        out = self.fc2(out)  
        out = self.sigmoid(out)  # 在输出层使用Sigmoid激活函数  
        return out  
  
# 实例化模型、损失函数和优化器  
model = NeuralNetwork(input_size, hidden_size)  
criterion = ... # 待定
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)  # 使用Adam优化器  
  
# 训练模型  
for epoch in range(num_epochs):  
    for i, (images, labels) in enumerate(train_loader):  # 遍历每个批次的数据  
        # 将图像张量转换为2D张量(矩阵)形式,并作为模型的输入  
        inputs = images.view(-1, input_size)  
        labels = labels.long()  # 将标签转换为长整数型张量  
          
        # 前向传播,计算输出结果  
        outputs = model(inputs)  
        loss = criterion(outputs, labels)  # 计算损失值  
          
        # 反向传播,更新权重参数  
        optimizer.zero_grad()  # 清空梯度缓存,以便计算新的梯度值  
        loss.backward()  # 计算梯度值并累积在模型参数上  
        optimizer.step()  # 更新模型参数  
          

Sigmoid激活函数的局限性举例

Sigmoid函数在深度学习模型中作为激活函数使用,其局限性主要表现在以下几个方面:

  1. 梯度消失问题:当输入值非常大或非常小时,Sigmoid函数的导数趋近于0。在深度神经网络中,误差反向传播时,梯度会逐层乘以激活函数的导数。当层数较深时,梯度的连乘可能导致梯度变得非常小,甚至接近于0,使得参数无法有效更新,这就是所谓的梯度消失问题
  2. 输出非0均值:Sigmoid函数的输出值恒大于0,不是0均值的。这会导致后层的神经元的输入是非0均值的信号,对梯度产生影响,进而影响网络的收敛速度(参考链接)。
  3. 容易饱和:Sigmoid函数在输入值较大或较小时容易进入饱和区,此时函数的输出对输入的变化不敏感,可能导致模型训练困难。

ReLU激活函数

和Sigmoid函数一样,ReLU(Rectified Linear Unit)函数也是非常常用的激活函数。它将负值映射为0,对于正值则直接输出其本身。

公式

ReLU函数的数学特性

特性描述
简单性ReLU函数仅需比较输入值和0的大小来确定输出值,计算效率高。
非线性ReLU函数实际上是非线性的,能够引入非线性因素,增强模型的表达能力。
激活稀疏性当输入值小于0时,ReLU函数的输出为0,只激活输入中的一部分神经元,增强模型的泛化能力和鲁棒性。
缓解梯度消失问题与传统的激活函数(如Sigmoid)相比,ReLU有助于缓解梯度消失问题,因为它的梯度在正区间为1,有助于更好地传播梯度。

ReLU函数的特点

  1. 线性与非线性:ReLU函数在输入值大于0时表现为线性函数,即f(x)=x,这有助于提高计算速度。而在输入值小于或等于0时,ReLU函数表现为非线性,即输出值为0。这种线性与非线性的结合使得ReLU函数在深度学习中具有很好的性能。

  2. 简单高效:ReLU函数的计算过程非常简单,只需要一次比较操作和一次赋值操作,因此计算速度非常快。这使得ReLU函数在训练深度神经网络时非常高效,可以显著加速模型的收敛速度。

  3. 缓解梯度消失问题:与Sigmoid等激活函数相比,ReLU激活函数的梯度在反向传播过程中不会消失,有助于提高训练速度和模型的收敛效果。

  4. 神经元"死亡"问题:与Sigmoid函数类似,ReLU函数也可能导致某些神经元在训练过程中始终处于"死亡"状态(即输出值一直为0),这可能会影响模型的性能。为了解决这个问题,一些变体的ReLU激活函数也被开发出来,如Leaky ReLU和Parametric ReLU等。

示例

基于NumPy和PyTorch实现ReLU函数
# 基于NumPy实现ReLU函数
import numpy as np  
  
def relu(x):  
    return np.maximum(0, x)
    
# 基于PyTorch实现ReLU函数(使用PyTorch的内置函数F.relu())
import torch.nn.functional as F
  
# 创建一个张量  
x = torch.tensor([-1.0, 0.0, 1.0])  
  
# 应用sigmoid函数  
y = F.relu(x)
  
print(y)
搭建基于ReLU函数的卷积神经网络(CNN)
import torch  
import torch.nn as nn  
  
# 定义一个简单的卷积神经网络  
class SimpleCNN(nn.Module):  
    def __init__(self):  
        super(SimpleCNN, self).__init__()  
        # 第一个卷积层,使用32个3x3的卷积核,输入通道数为1,输出通道数为32,ReLU激活函数  
        self.conv1 = nn.Conv2d(1, 32, 3, padding=1)  
        # 第二个卷积层,使用64个3x3的卷积核,输入通道数为32,输出通道数为64,ReLU激活函数  
        self.conv2 = nn.Conv2d(32, 64, 3, padding=1)  
        # 全连接层,输入节点数为64*7*7(假设输入图像大小为28x28),输出节点数为10(假设有10个类别)  
        self.fc = nn.Linear(64 * 7 * 7, 10)  
        # 输出层,全连接层的输出作为输入,输出节点数为10,使用softmax激活函数  
        self.out = nn.LogSoftmax(dim=1)  
  
    def forward(self, x):  
        # 通过第一个卷积层和ReLU激活函数  
        x = self.conv1(x)  
        x = nn.functional.relu(x)  
        # 通过第二个卷积层和ReLU激活函数  
        x = self.conv2(x)  
        x = nn.functional.relu(x)  
        # 将卷积层的输出展平,作为全连接层的输入  
        x = x.view(x.size(0), -1)  
        # 通过全连接层和softmax激活函数  
        x = self.fc(x)  
        x = self.out(x)  
        return x

在这个示例中:

  • 我们定义了一个名为SimpleCNN的类,继承自nn.Module。这是PyTorch中定义神经网络的标准方式。
  • __init__方法中,我们定义了网络中的各个层。首先有两个卷积层,每个卷积层后都使用了ReLU激活函数。然后是一个全连接层,最后是一个输出层。
  • forward方法中,我们定义了数据在网络中的前向传播过程。数据首先通过两个卷积层和ReLU激活函数,然后被展平以便输入全连接层,最后通过全连接层和输出层。
  • 我们使用了nn.functional模块中的函数来应用ReLU激活函数(nn.functional.relu)和Softmax激活函数(nn.functional.log_softmax)。注意,ReLU激活函数的参数默认为0,因此不需要额外指定。

结束语

  • 亲爱的读者,感谢您花时间阅读我们的博客。我们非常重视您的反馈和意见,因此在这里鼓励您对我们的博客进行评论。
  • 您的建议和看法对我们来说非常重要,这有助于我们更好地了解您的需求,并提供更高质量的内容和服务。
  • 无论您是喜欢我们的博客还是对其有任何疑问或建议,我们都非常期待您的留言。让我们一起互动,共同进步!谢谢您的支持和参与!
  • 我会坚持不懈地创作,并持续优化博文质量,为您提供更好的阅读体验。
  • 谢谢您的阅读!

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

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

相关文章

Python+OpenGL绘制3D模型(四)绘制线段

系列文章 一、逆向工程 Sketchup 逆向工程(一)破解.skp文件数据结构 Sketchup 逆向工程(二)分析三维模型数据结构 Sketchup 逆向工程(三)软件逆向工程从何处入手 Sketchup 逆向工程(四&#xf…

[RoarCTF2019] TankGame

不多说,用dnspy反编译data文件夹中的Assembly-CSharp文件 使用分析器分析一下可疑的FlagText 发现其在WinGame中被调用,跟进WinGame函数 public static void WinGame(){if (!MapManager.winGame && (MapManager.nDestroyNum 4 || MapManager.n…

DevOps持续交付之容器化CICD流水线

DevOps持续交付 随着DevOps⼤规模化的落地和应⽤,持续集成以及持续交付已经是⼀种常态的。CI指的是持续集成,使⽤的开源⼯具是Jenkins,CD指的是持续交付和持续部署,⼀个完整的软件开发⽣命周期为: 主要流程可以具体为: 构建阶段…

JS 嵌套循环之退出顶层循环

我们常常写循环的时候&#xff0c;可能会遇到嵌套循环&#xff0c;如果出现退出循环&#xff0c;一层还好&#xff0c;多层循环就费劲了&#xff0c;传统做法是加 flag&#xff0c;如下&#xff1a; for (let i 0; i < 10; i) {let flag falsefor (let j 0; j < 5; j…

C++ BuilderXE10 关于Intraweb关于IWTemplateProcessorHTML1操作

1、端口设置,port参数修改端口号。 2、初始化设置成ciMultiThreaded。这样可以避免ADO组件的加载错误。 3、IWTemplateProcessorHTML1设置&#xff0c; IWForm1->LayoutMgr IWTemplateProcessorHTML1;//关联模板(IWForm1. html) IWTemplateProcessorHTML1->RenderStyles…

【Recruitment Mercedes Benz】

Network I) JDII) IPv4与IPv6之间的区别是什么III) was advices3.1&#xff09; 防火墙&#xff0c;配置&#xff0c;数据的in/out (data flow in or flow out)3.2&#xff09; 域名&#xff0c;网址&#xff0c;端口3.3) 三次握手&#xff0c;四次挥手3.4) TCP/IP, 几层协议&a…

原生微信小程序如何动态配置主题颜色及如何调用子组件的方法

一、最终效果 二、步骤 1、在初始化进入项目时&#xff0c;获取当前主题色 2、把主题色定义成全局变量&#xff08;即在app.js中设置&#xff09; 3、tabBar也需要定义全局变量&#xff0c;在首页时需要重新赋值 三、具体实现 1、app.js onLaunch () {//获取主题数据this.set…

Go 泛型之明确使用时机与泛型实现原理

Go 泛型之明确使用时机与泛型实现原理 文章目录 Go 泛型之明确使用时机与泛型实现原理一、引入二、何时适合使用泛型&#xff1f;场景一&#xff1a;编写通用数据结构时场景二&#xff1a;函数操作的是 Go 原生的容器类型时场景三&#xff1a;不同类型实现一些方法的逻辑相同时…

Xshell 从github克隆项目:使用ssh方式。

接上文&#xff1a; https://blog.csdn.net/liu834189447/article/details/135247868 是能克隆项目了&#xff0c;但是速度太磕碜了&#xff0c;磕碜到难以直视。 找到另外一种办法&#xff0c;使用SSH克隆项目 速度嘎嘎猛。 首先得能进得去github网站&#xff0c;不能点上边…

电缆故障测试仪的其他用途是什么?

电缆故障测试仪是电力行业非常重要的设备。它可以帮助电缆维护人员快速准确地判断电缆故障点和类型&#xff0c;帮助电缆维护人员快速维护和维护电缆&#xff0c;从而减少电缆故障引起的安全事故。此外&#xff0c;电缆故障测试仪的其他用途是什么&#xff1f;现在让我们一起分…

Download Monitor Email Lock下载监控器邮件锁插件

打开Download Monitor Email Lock下载监控器邮件锁插件 Download Monitor Email Lock下载监控器邮件锁插件下载监视器的电子邮件锁定扩展允许您要求用户在获得下载访问权限之前填写他们的电子邮件地址。 Download Monitor Email Lock下载监控器邮件锁插件用法 安装扩展程序后…

德鲁伊(Druid)链接PGsql前端请求或者后端自动任务频繁出现IOException

尝试在druid配置文件中增加&#xff1a; socket-timeout: 60000 druid一些版本默认会给链接数据库socket默认10s&#xff0c;超出10s之后socket断开&#xff0c;对于GP数据库报的个IO异常。 &#xff08;对于同样的场景mysql超出10s后提示的是socketTimeOut&#xff0c;所以相…

Buck电源设计常见的一些问题(五)MOS管振荡抑制方法(三)

MOS管振荡抑制方法(三)Rboot的选取 1.Rboot的选取2.总结1.Rboot的选取 同步 Buck 变换器一般采用自举电路供电,如图所示。开关节点上升沿的振荡与上管开通关系密切,上管开通时的驱动电流路径如图所示。因此,可以通过增大 Rboot来减缓上管开通的速度,从而抑制开关节点的振…

洛谷:线性表

今天开始刷洛谷&#xff0c;之前刷leetcode都是核心代码模式&#xff0c;现在突然让我用ACM模式&#xff0c;刚开始还是很不习惯的&#xff0c;但做了几道题好点了&#xff0c;只能说洛谷题的难度是比leetcode大的。 还有就是&#xff0c;STL牛逼&#xff01; 1.询问学号(vect…

C语言—每日选择题—Day64

前言 两天没更新了&#xff0c;作者在复习期末考试&#xff0c;更新一波&#xff0c;祝大家都能顺利通过期末考试&#xff01;&#xff01;&#xff01; 指针相关博客 打响指针的第一枪&#xff1a;指针家族-CSDN博客 深入理解&#xff1a;指针变量的解引用 与 加法运算-CSDN博…

Python可视化之Matplotlib

文章目录 Matplotlib与可视化分析简单图形的绘制pylot的高级功能添加图例与注释 Matplotlib与可视化分析 我们之前对数据的处理与分析&#xff0c;其实最终还是要利用可视化工具进行更加直观的输出 我们开业通过 pip install matplotlib命令来安装对应的模块 简单图形的绘制…

《深入理解JAVA虚拟机笔记》Java 运行时内存区域

程序计数器&#xff08;线程私有&#xff09; 程序计数器&#xff08;Program Counter Register&#xff09;是一块较小的内存空间&#xff0c;它可以看做是当前线程所执行的字节码的行号指示器。在 Java 虚拟机的概念模型里&#xff0c; 字节码解释器工作时就是通过改变这个计…

mfc140u.dll丢失的解决方法,怎样修复mfc140u.dll

最近看到很多朋友在问找不到mfc140u.dll丢失怎么办&#xff1f;有什么解决方法&#xff0c;今天就给小伙伴们解答一下&#xff0c;mfc140u.dll丢失的解决办法&#xff0c;怎么修复mfc140u.dll。 一.丢失的原因 1.损坏的程序安装:在安装某个程序时&#xff0c;可能会出现意外中…

【数据库】为什么要分库分表

为什么要分库分表 1.为什么要分库分表&#xff1f;2.垂直拆分3.水平拆分4.总结4.1 逻辑库和物理库4.2 逻辑表和物理表 1.为什么要分库分表&#xff1f; 随着近些年信息化大跃进&#xff0c;各行各业无纸化办公产生了大量的数据&#xff0c;而越来越多的数据存入了数据库中。当…

代码随想录-刷题第三十九天

动态规划理论基础 动态规划的题目由重叠子问题构成&#xff0c;每一个状态一定是由上一个状态推导出来的。这一点就区分于贪心&#xff0c;贪心没有状态推导&#xff0c;而是从局部直接选最优的。 动态规划五步曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义…