type
status
date
slug
summary
tags
category
icon
password
在掌握了神经网络的基本结构之后,我们将深入探讨那些赋予神经网络“智能”的核心组件,包括激活函数、参数初始化策略、损失函数的设计、反向传播的优化,以及如何防止模型“学跑偏”的正则化技巧。最后,我们会通过一个完整的项目实战来巩固所学知识。

一、激活函数:赋予网络非线性能力

激活函数是神经网络的灵魂,它负责在神经元的输出端引入非线性能力。如果没有激活函数,无论神经网络有多少层,其本质都只是一个线性模型,无法解决复杂的现实问题。

1.1 Sigmoid

Sigmoid 函数能将任意实数输入映射到 (0, 1) 区间,常用于二分类任务的输出层,因为它能直观地解释为概率。
  • 核心原理:
  • 主要问题
    • 梯度消失:当输入值过大或过小时,其导数接近于 0,导致深层网络在反向传播时梯度更新缓慢。
    • 计算成本高:包含指数运算。
  • 实践建议:由于梯度消失问题,现在已很少在隐藏层使用 Sigmoid,主要用于二分类输出层。

1.2 Tanh(双曲正切)

Tanh 函数将输入映射到 (-1, 1) 区间,输出以 0 为中心,这在一定程度上优于 Sigmoid,有助于加速模型收敛。
  • 核心原理
  • 主要问题:仍然存在梯度消失问题,只是比 Sigmoid 稍好。
  • 实践建议:在某些场景下可以作为 Sigmoid 的替代品,但同样不建议在深层网络的隐藏层中大规模使用。

1.3 ReLU(修正线性单元)

ReLU 是目前深度学习中最常用的激活函数,因其简单高效而广受欢迎。
  • 核心原理
  • 优点
    • 计算极其简单,训练速度快。
    • 在正数区间的导数恒为 1,有效缓解了梯度消失问题。
    • 引入稀疏性,让部分神经元输出为 0,降低了计算量。
  • 主要问题:“神经元死亡”(Dying ReLU),即如果一个神经元的输入恒为负,它将永远不会被激活。

1.4 LeakyReLU

LeakyReLU 是 ReLU 的改进版,旨在解决“神经元死亡”问题。
  • 核心原理:为负数区间的输入赋予一个微小的正斜率 (α)。
  • 优点:避免了神经元完全不激活的情况,允许负值信息通过。
  • 实践建议:当发现 ReLU 效果不佳或怀疑存在大量“死亡”神经元时,可以尝试使用 LeakyReLU。

1.5 Softmax

Softmax 主要用于多分类问题的输出层,它将一组实数转换为概率分布,所有输出值的和为 1。
  • 核心原理:对每个输出值取指数,然后用该值除以所有输出值的指数之和。
  • 特点
    • 将输出转换为概率分布,便于理解和决策。
    • 放大差异,最大的输入值对应的概率会更突出。
  • 实践建议:多分类任务的输出层标准选择,通常与交叉熵损失函数配合使用。

1.6 如何选择激活函数?

  • 隐藏层
      1. 首选 ReLU:它简单、高效,是绝大多数情况下的第一选择。
      1. 备选 LeakyReLU:如果 ReLU 效果不佳,可以尝试 LeakyReLU 或其变体。
      1. 尽量避免 Sigmoid:它容易导致梯度消失,拖慢训练。
  • 输出层
      1. 二分类问题:使用 Sigmoid
      1. 多分类问题:使用 Softmax
      1. 回归问题:通常 不使用 激活函数。

二、参数初始化:决定训练的起点

正确的参数初始化对模型的训练速度和最终性能至关重要。糟糕的初始化可能导致梯度消失/爆炸,使模型难以收敛。
  • nn.init 模块:PyTorch 在 torch.nn.init 中提供了多种初始化方法。
  • 目标:打破对称性(各神经元学习不同特征)、保持输入输出方差一致。

2.1 固定值初始化(不推荐)

如全零、全一或固定常数初始化。会导致所有神经元学习到完全相同的特征(对称性问题),模型无法学习。

2.2 随机初始化

从正态分布或均匀分布中随机采样,打破对称性。这是最基本的有效方法,但可能导致梯度不稳定。

2.3 Xavier 初始化 (Glorot 初始化)

一种自适应初始化方法,根据输入和输出神经元的数量调整权重方差,使各层输出的方差保持一致,以缓解梯度问题。
  • 核心思想
  • 适用场景:在 Sigmoid 和 Tanh 激活函数下表现良好。

2.4 He 初始化 (Kaiming 初始化)

专为 ReLU 及其变体设计的初始化方法。考虑到 ReLU 会将一半的输入置零,He 初始化相应地调整了权重的方差。
  • 核心思想
  • 适用场景:当隐藏层使用 ReLU 或 LeakyReLU 时,He 初始化是首选。

三、损失函数:衡量模型的预测差距

损失函数(Loss Function)用于量化模型预测值与真实值之间的差异。训练的目标就是通过优化算法(如梯度下降)最小化这个损失。

3.1 回归任务损失函数

  • MAE (L1-Loss):平均绝对误差,对异常值不敏感(鲁棒性好)。
    • MSE (L2-Loss):均方误差,对较大误差的惩罚更重,数学性质好,是回归任务中最常用的损失函数。

      3.2 分类任务损失函数

      • CrossEntropyLoss:交叉熵损失,是多分类任务的标准选择。
        • 重要提示:PyTorch 的 nn.CrossEntropyLoss 内置了 Softmax 操作。因此,模型的最后一层不应再接 Softmax 激活函数。
      • BCELoss:二元交叉熵损失,专用于二分类任务。
        • 重要提示:使用 nn.BCELoss 时,模型的输出 必须 先经过 Sigmoid 激活函数。为了数值稳定性,更推荐使用 nn.BCEWithLogitsLoss,它将 Sigmoid 和 BCELoss 合二为一。

      四、反向传播与优化器:如何更新模型参数

      反向传播(Backpropagation, BP)是训练神经网络的核心算法,它计算损失函数对每个参数的梯度。而优化器(Optimizer)则根据这些梯度来更新参数,以最小化损失。

      4.1 梯度下降基础

      • 批量梯度下降 (BGD):使用整个数据集计算梯度,方向准确但速度慢,内存消耗大。
      • 随机梯度下降 (SGD):每次只用一个样本计算梯度,速度快但更新不稳定,容易震荡。
      • 小批量梯度下降 (MBGD):BGD 和 SGD 的折中,是目前的主流选择。它在每次更新时使用一小批数据(batch)。

      4.2 常用优化器

      • Momentum:在 SGD 基础上引入“动量”(历史梯度的指数加权平均),帮助“冲过”局部最小值或鞍点,加速收敛。
      • AdaGrad:为每个参数自适应调整学习率,对稀疏数据友好,但学习率会随时间单调递减,可能导致训练后期停滞。
      • RMSProp:AdaGrad 的改进版,使用梯度的指数加权移动平均而非累积,解决了学习率过早衰减的问题。
      • Adam当前最流行的优化器之一。它结合了 Momentum 和 RMSProp 的优点,既有动量加速,又能自适应调整学习率,适用于绝大多数场景。

      五、正则化:防止模型过拟合

      过拟合指模型在训练集上表现优异,但在未见过的新数据(测试集)上表现很差。正则化是解决过拟合的常用技术。

      5.1 L1 和 L2 正则化

      通过在损失函数中添加对权重的惩罚项来限制模型复杂度。
      • L2 正则化 (权重衰减):惩罚项为权重的平方和,使权重值趋向于较小但非零的值,使模型更平滑。在 PyTorch 的优化器中通过 weight_decay 参数实现。
        • L1 正则化:惩罚项为权重的绝对值和,倾向于将不重要的特征权重压缩至零,从而实现特征选择,产生稀疏模型。需要手动实现。

          5.2 Dropout

          在训练过程中,以一定概率 p 随机“丢弃”(即置零)一部分神经元的输出。这能强制网络学习更鲁棒的特征,减少神经元之间的协同适应。
          • 核心组件nn.Dropout 用于全连接层,nn.Dropout2d 用于卷积层。
          • 注意:Dropout 只在训练时生效 (model.train()),在评估时会自动关闭 (model.eval())。

          5.3 数据增强

          通过对训练数据进行随机变换(如旋转、裁剪、翻转、颜色抖动等)来创造更多样的训练样本,是提高模型泛化能力、降低过拟合风险的有效手段。
          • 核心模块torchvision.transforms
          • 实践:通常使用 transforms.Compose 将多个变换组合成一个处理流水线。

          六、批量标准化 (Batch Normalization)

          Batch Normalization (BN) 是一种强大的正则化技术,通过对每一批数据的每个特征通道进行标准化,来解决“内部协变量偏移”问题。
          • 位置:通常放在全连接层或卷积层之后,激活函数之前。
          • 作用
            • 加速网络训练,允许使用更大的学习率。
            • 提高模型稳定性,减少对参数初始化的依赖。
            • 提供轻微的正则化效果。
          • 核心组件nn.BatchNorm1d, nn.BatchNorm2d

          七、模型的保存与加载

          训练好的模型需要被保存,以便后续部署、评估或继续训练。
          • 推荐方法:只保存模型的状态字典(state_dict),它包含了模型的所有可学习参数(权重和偏置)。这种方式轻量且灵活。
          • 不推荐方法:保存整个模型对象。虽然简单,但代码依赖性强,可能在不同环境中加载失败。

          八、项目实战:用全连接网络训练和验证 CIFAR10 数据集

           
          Python-深度学习-全连接神经网络1Python-Transformer全面解析
          Loading...