PyTorch 2.x 深度学习专题【左扬精讲】— 激活函数:从 Sigmoid 到 ReLU 的演进之路
PyTorch 2.x 深度学习专题【左扬精讲】— 激活函数:从 Sigmoid 到 ReLU 的演进之路
激活函数(Activation Function)是深度神经网络中最核心的组件之一。它决定了神经元是否应该被"激活",从而影响网络的表达能力。
从 1943 年 McCulloch-Pitts 神经元的阶跃函数,到 2010 年代席卷整个深度学习领域的 ReLU,激活函数的演进史几乎就是半部深度学习史。
本文将系统梳理激活函数的发展脉络,深入剖析每个阶段出现的动机、解决的问题以及带来的新问题。通过理解"为什么会出现",我们才能真正掌握"什么时候用"。
激活函数 Sigmoid Tanh ReLU Leaky ReLU 梯度消失 死亡神经元
学习重点
必须掌握:
- 激活函数的核心作用:引入非线性
- Sigmoid 和 Tanh 的数学公式与梯度特性
- ReLU 的优势与"死亡神经元"问题
- 梯度消失的本质原因与解决方案演进
需要了解:
- 激活函数演进的历史脉络
- 各种 ReLU 变体的设计动机
- Swish、Mish 等新型激活函数
目录导航
一、激活函数的核心作用
What — 激活函数是什么?
激活函数是神经网络中每个神经元对输入信号进行"非线性变换"的函数。给定神经元的净输入 z = w^T x + b,激活函数 a = σ(z) 决定该神经元是否被"激活"以及激活的强度。
从数学上看,激活函数将线性变换的结果映射到非线性空间,使得堆叠多层线性变换(多层感知机)能够表达任意复杂的非线性函数。
Why — 为什么必须有激活函数?
没有激活函数会发生什么?
假设我们有一个 L 层网络,每层的变换是 h^{(l)} = W^{(l)} h^{(l-1)} + b^{(l)},没有激活函数。
经过 L 层变换后:
h^{(L)} = W^{(L)} W^{(L-1)} \cdots W^{(1)} x + 偏置项
由于矩阵乘法满足结合律,这等价于一次线性变换 h^{(L)} = W_{eq} x + b_{eq}。
结论:没有激活函数,多层网络退化为单层网络!
这意味着无论网络有多少层,都无法拟合 XOR 这样的非线性问题。
激活函数的核心价值在于打破线性约束。如果把神经网络比作一台计算机,线性变换(矩阵乘法)提供了"连线",而激活函数提供了"开关"——正是这种"开/关"的非线性组合,才使得神经网络具有了逼近任意函数的能力。
著名的万能近似定理(Universal Approximation Theorem)证明:具有单层隐藏层的前馈神经网络,只要该层有足够多的神经元,就可以逼近任意连续函数。而这个证明的关键前提,正是使用了非线性激活函数。
二、混沌初开:阶跃函数与早期探索
What — 阶跃函数
最早的激活函数是 McCulloch-Pitts 神经元(1943)使用的阶跃函数:
σ(z) = 1 z ≥ 0 0 z < 0
这个函数将输入映射为 0 或 1,模拟神经元的"兴奋/抑制"状态。
Why — 为什么阶跃函数被抛弃?
问题一:梯度无处可寻
阶跃函数在 z = 0 处不可微,且导数几乎处处为 0。这使得基于梯度的反向传播算法完全无法工作——梯度信号无法从输出层传回输入层。
问题二:输出恒定导致学习停滞
无论输入如何变化,只要不跨越阈值,输出就保持不变。这导致网络无法学习到输入的连续变化。
没有可微激活函数会发生什么?
- 无法使用梯度下降训练
- 无法构建多层网络
- 深度学习的理论基础无法建立
早期激活函数总结
阶跃函数虽然直观,但不可微的缺陷使其无法用于现代深度学习。反向传播算法的出现(1986)催生了对可微激活函数的强烈需求。
三、Sigmoid 时代:平滑可微的突破
What — Sigmoid 函数
Sigmoid 函数(也叫 Logistic 函数)是深度学习早期最流行的激活函数:
σ(z) = (1)/(1 + e^-z) = (1)/(1 + e^-z)
它的输出范围是 (0, 1),可以将任意实数映射到概率区间,非常适合二分类问题的输出层。
Why — Sigmoid 为何成为早期主流?
优势一:完美可微
Sigmoid 函数处处可导,且导数可以用自身表示:
σ'(z) = σ(z)(1 - σ(z))
这使得梯度计算和反向传播变得简洁高效。
优势二:输出归一化
输出范围 (0, 1) 自然地解释了"激活概率",非常适合二分类输出层。在输出层使用 Sigmoid 可以直接输出样本属于正类的概率 P(y=1|x)。
优势三:物理直观
Sigmoid 的 S 形曲线模拟了神经元的"饱和"特性——当输入很大或很小时,神经元趋于饱和(输出接近 1 或 0),这在生物学上对应神经元的"全兴奋/全抑制"状态。
Sigmoid 的致命缺陷:梯度消失
Sigmoid 的导数最大值为 0.25(发生在 z=0 处):
σ'(0) = (1)/(4)
当网络层数增加时,反向传播的梯度会不断相乘:
(∂ L)/(∂ z^{(1)}) = (∂ L)/(∂ a^{(L)}) · σ'(z^{(L)}) · σ'(z^{(L-1)}) · · · σ'(z^{(2)})
每经过一层,梯度至少衰减到原来的 1/4。经过 10 层后,梯度衰减到约 10^-6,几乎为零。
What — 梯度消失的本质
梯度消失(Vanishing Gradient Problem)是指在深层网络中,反向传播时梯度逐层衰减,导致靠近输入层的参数几乎无法更新。
考虑一个 10 层网络,每层使用 Sigmoid,每层梯度约乘以 0.25:
0.25^10 ≈ 9.5 × 10^-7
这意味着输出层的一个单位梯度,传到第一层时只剩下百万分之一!
经验法则:Sigmoid 适用场景
- 二分类问题的输出层(输出概率)
- 隐藏层不超过 3-4 层的浅层网络
- 不推荐用于深层网络或隐藏层
四、Tanh:零中心化的改进
What — Tanh 函数
双曲正切函数(Tanh)是 Sigmoid 的"平移+缩放"版本:
tanh(z) = (e^z - e^-z)/(e^z + e^-z) = 2σ(2z) - 1
输出范围是 (-1, 1),是零中心化的。
Why — Tanh 比 Sigmoid 好在哪里?
优势:零中心化输出
Tanh 的输出以 0 为中心,而 Sigmoid 的输出以 0.5 为中心。这看似微小的差异,对梯度下降有重要影响。
考虑梯度下降更新:w ← w - η (∂ L)/(∂ w)
如果激活值 a 总是正的(如 Sigmoid),那么梯度 (∂ L)/(∂ w) = (∂ L)/(∂ a) · (∂ a)/(∂ z) 的符号完全取决于 (∂ L)/(∂ a)。这意味着同一层的所有权重 w_1, w_2, … 必须同时增加或减少——收敛速度较慢。
Tanh 的输出可正可负,因此梯度可以"相消",收敛更快。
Tanh 仍然有梯度消失问题
Tanh 的导数最大值为 1(发生在 z=0 处):
tanh'(z) = 1 - tanh^2(z)
虽然比 Sigmoid 的 0.25 好,但深层网络中梯度仍会逐渐衰减。Tanh 解决了"零中心化"问题,但没有解决根本的"梯度消失"问题。
Tanh vs Sigmoid 对比
| 特性 | Sigmoid | Tanh |
|---|---|---|
| 输出范围 | (0, 1) | (-1, 1) |
| 零中心化 | 否 | 是 |
| 导数最大值 | 0.25 | 1 |
| 适用场景 | 二分类输出层 | 隐藏层(浅层) |
| 梯度消失 | 严重 | 仍存在 |
五、ReLU 革命:简单即力量
What — ReLU 函数
修正线性单元(Rectified Linear Unit, ReLU)于 2010 年在深度网络中提出:
ReLU(z) = max(0, z) = z z > 0 0 z ≤ 0
这个函数如此简单——正半轴恒等,负半轴置零——却成为深度学习史上最重要的突破之一。
Why — ReLU 为什么能解决梯度消失?
关键洞察:正半轴导数为 1
ReLU 的导数非常简洁:
ReLU'(z) = 1 z > 0 0 z ≤ 0
在正区间,梯度恒为 1!无论网络多深,梯度都可以无损传播。这意味着:
- 反向传播时,梯度乘以 1 而不是 0.25
- 输入层和输出层之间的梯度衰减大大缓解
- 深层网络终于可以真正训练了
ReLU 的"单侧抑制"特性与生物神经元的稀疏激活现象高度吻合。神经科学研究表明,大脑在任何时刻只有约 1%-4% 的神经元同时激活,这种稀疏性可能正是大脑高效计算的关键。
ReLU 通过将负值置零,自然地实现了"硬稀疏"——不活跃的神经元完全关闭,活跃的神经元传递等量信息。这种设计:
- 降低了网络的计算成本(稀疏计算更高效)
- 减少了过拟合风险(信息解耦)
- 模拟了神经元的"死亡"机制(信息选择性传递)
Why — ReLU 的其他优势
优势一:计算极快
ReLU 的前向传播只需要一次比较操作,而 Sigmoid/Tanh 需要指数运算。在 GPU 上,这可以将训练速度提升数倍。
优势二:梯度稀疏
当 z ≤ 0 时,ReLU 输出恒为 0,梯度也为 0。这意味着这些神经元在本次迭代中被"冻结",不参与参数更新。这种稀疏性可以看作是一种无监督的正则化。
优势三:缓解过拟合
稀疏激活使得网络不会"记住"训练数据,而是学习到更鲁棒的稀疏特征表示。
ReLU 的致命缺陷:Dying ReLU(死亡神经元问题)
当神经元的输入 z = w^T x + b 始终为负时,ReLU 永远输出 0,梯度也永远为 0。这个神经元就"死"了——无论输入如何变化,都不会再激活。
导致 Dying ReLU 的原因:
- 学习率设置过大,导致参数更新后进入负区间
- 初始化不当
- 数据分布偏移(如 BN 后的统计量变化)
没有解决方案会发生什么?
大量神经元死亡后,网络表达能力急剧下降,甚至退化为只训练了部分参数的浅层网络。据观察,在训练过程中,高达 40%-60% 的神经元可能永久死亡。
import numpy as np
def relu(z):
"""ReLU 激活函数"""
return np.maximum(0, z)
def relu_gradient(z):
"""ReLU 梯度"""
return (z > 0).astype(float)
# 示例:梯度无损传播
z = np.array([1.0, 2.0, 3.0]) # 正区间
gradient = relu_gradient(z)
print(f"输入: {z}")
print(f"ReLU 输出: {relu(z)}")
print(f"梯度: {gradient}") # [1, 1, 1] - 无损传播
# 对比 Sigmoid 的梯度衰减
sigmoid = 1 / (1 + np.exp(-z))
sigmoid_grad = sigmoid * (1 - sigmoid)
print(f"\nSigmoid 输出: {sigmoid}")
print(f"Sigmoid 梯度: {sigmoid_grad}") # [0.20, 0.11, 0.05] - 衰减严重
六、ReLU 变体百花齐放
6.1 Leaky ReLU:让负区间有梯度
What — Leaky ReLU
Leaky ReLU 是 ReLU 的第一个改进版本,由 Maas 等人在 2013 年提出:
LeakyReLU(z) = max(α z, z) = z z > 0 α z z ≤ 0
其中 α 是一个小常数,通常取 0.01。
Why — Leaky ReLU 解决了什么?
解决 Dying ReLU 问题
在负区间,Leaky ReLU 不会将输出置零,而是保留一个很小的斜率 α。这意味着即使 z 为负,梯度也不会为零,神经元不会"死亡"。
导数对比:
ReLU'(z) = 1 z > 0 0 z ≤ 0
LeakyReLU'(z) = 1 z > 0 α z ≤ 0
负区间梯度从 0 变为 α,神经元得以继续学习。
6.2 PReLU:让网络自己学习斜率
What — PReLU(Parametric ReLU)
PReLU 将 Leaky ReLU 的固定 α 变为可学习参数:
PReLU(z) = max(α_i z_i, z_i)
其中 α_i 可以是每通道(channel)独立的参数,在训练过程中与其他参数一起学习。
Why — PReLU 的设计动机
固定斜率 α = 0.01 是人工设定的,但不同任务、不同层可能需要不同的负区间斜率。PReLU 让网络自己决定"什么样的负值值得保留信息"。
实验表明,在 ImageNet 分类任务中,PReLU 的学习到的斜率分布接近 0,说明网络倾向于选择接近 ReLU 的行为(负值大部分是无用的);但在某些层,学习到的斜率接近 0.5,说明这些层的负值包含重要信息。
6.3 ELU:负值平滑化
What — ELU(Exponential Linear Unit)
ELU 使用指数函数平滑负区间:
ELU(z) = z z > 0 α(e^z - 1) z ≤ 0
Why — ELU 的设计理念
优势:输出接近零均值
ELU 的负值不是线性的,而是指数增长的。这使得 ELU 的输出更接近零均值分布,有助于梯度向两个方向传播。
优势:更强的生物学 plausibility
ELU 的负值输出使得激活值的分布更接近自然信号的真实分布——大多数值接近零,少数值较大。
代价:计算复杂度
负区间需要计算指数函数,计算量比 Leaky ReLU 更大。在极端负值时,ELU 的输出趋于 -α,梯度趋于 0。
6.4 Swish:数据依赖的自门控
What — Swish
Swish 由 Google Brain 在 2017 年提出:
Swish(z) = z · σ(β z)
其中 σ 是 Sigmoid 函数,β 是可选的常数或可学习参数。当 β = 1 时简化为 Swish(z) = z · σ(z)。
Why — Swish 为什么会有效?
自门控机制
Swish 可以看作是一种"自门控":Sigmoid 函数根据输入值动态决定"保留多少信息"。当 z 较大时,σ(z) ≈ 1,输出接近 z;当 z 较小时,σ(z) ≈ 0,输出趋近于 0。
与 ReLU 的"硬门控"(0 或 1)不同,Swish 是"软门控",可以根据输入的连续值平滑调节。
梯度特性
Swish 的导数:
Swish'(z) = σ(β z) + β z · σ(β z)(1 - σ(β z))
当 z = 0 时,导数约为 β · 0.25,大于 0。这意味着 Swish 在零点附近仍有梯度,不容易"死亡"。
ReLU 家族特性对比
| 激活函数 | 负区间行为 | 梯度特性 | 计算复杂度 |
|---|---|---|---|
| ReLU | 硬阈值(0) | 0 或 1 | 极低 |
| Leaky ReLU | 线性缩放(α z) | α 或 1 | 低 |
| PReLU | 可学习线性 | 可学习 | 中等 |
| ELU | 指数平滑 | 近似 α | 较高 |
| Swish | 软门控 | 平滑过渡 | 最高 |
| Mish | 平滑非线性 | 平滑过渡 | 较高 |
七、激活函数选择指南
选择原则:没有银弹
激活函数的选择取决于任务性质、数据分布、网络深度、计算资源等多种因素。以下是一般性指导原则:
隐藏层激活函数选择
首选:ReLU(及其变体)
- 层数 1-5:ReLU 或 Leaky ReLU
- 层数 5-20:Leaky ReLU、ELU、或 PReLU
- 层数 20+:考虑 Swish、Mish 或残差连接
不推荐:Sigmoid 和 Tanh
- 除非网络极浅(小于 3 层)
- 除非有特殊需求(如输出概率)
输出层激活函数选择
- 二分类:Sigmoid(输出概率)
- 多分类:Softmax(输出概率分布)
- 回归(无界):恒等函数(无激活)
- 回归(有界):Sigmoid((0,1))、Tanh((-1,1))
在 PyTorch 中,激活函数作为 torch.nn 模块的组成部分提供。源码位置在 torch/nn/modules/activation.py,每个激活函数都继承自 Module 基类,实现 forward() 方法。
以 ReLU 为例(简化版):
class ReLU(Module):
def forward(self, input):
return F.relu(input, inplace=self.inplace)
PyTorch 采用"函数式 API + 模块封装"的策略:F.relu() 是纯函数实现,nn.ReLU 是模块封装。这种设计使得激活函数既可以作为独立函数使用,也可以通过 nn.Sequential 组合成网络。
工程实践建议:
- 隐藏层优先尝试 ReLU,简单高效
- 遇到 Dying ReLU 时,换用 Leaky ReLU 或 PReLU
- 追求性能时,尝试 Swish(但计算成本更高)
- 几乎不需要考虑 Sigmoid/Tanh(除非输出层)
FAQ 常见问题解答
Q1. 为什么 ReLU 在负区间要将输出置零?不能像 Leaky ReLU 那样保留一点吗?
可以,但这是设计权衡。ReLU 的"硬稀疏"有两大好处:① 产生真正的零值,实现无监督的特征选择;② 计算极简。但代价是可能产生 Dying ReLU。Leaky ReLU 牺牲了硬稀疏性,换取了梯度的连续性。如果你遇到 Dying ReLU 问题,换用 Leaky ReLU 即可。
Q2. Sigmoid 是不是完全被淘汰了?
没有,在输出层仍是首选。二分类问题输出层需要输出 [0,1] 的概率,Sigmoid 是最自然的选择。在隐藏层,Sigmoid 确实几乎不再使用(因为梯度消失),但在输出层,它的概率解释能力无可替代。
Q3. 为什么 Tanh 的输出零中心化对梯度下降有帮助?
因为梯度方向更灵活。假设输入恒正(如 Sigmoid 输出),所有权重的梯度同号,必须"一起增减",收敛路径受限。Tanh 输出可正可负,梯度可以"相消",权重可以"此消彼长",收敛更快更稳定。
Q4. Swish 这么好,为什么没有完全取代 ReLU?
计算成本和不确定性。Swish 需要计算 Sigmoid(涉及指数运算),计算量比 ReLU 大。在超大规模部署时,这是不小的开销。另外,Swish 的超参数 β 需要调优,而 ReLU 没有超参数。在实践中,ReLU 的"足够好"使其成为默认选择。
Q5. 如何判断我的网络是否出现了梯度消失?
观察训练曲线。如果 loss 在前几个 epoch 下降很快,然后突然停滞;或者靠近输入层的参数梯度远小于靠近输出层的梯度;再或者深层网络训练效果不如浅层网络——这些都是梯度消失的典型症状。
Q6. 如何判断我的网络是否出现了 Dying ReLU?
检查激活值分布。如果大量神经元的输出恒为 0(统计发现 40%-50% 的神经元死亡),且 loss 不再下降,说明出现了 Dying ReLU。此时可以:① 降低学习率;② 换用 Leaky ReLU;③ 检查数据标准化是否正确。
Q7. Batch Normalization 能否缓解梯度消失?
可以部分缓解,但不是万能药。BN 通过归一化使输入分布稳定,减轻了层间协变量偏移(covariate shift)。但 BN 不能解决 Sigmoid/Tanh 固有的梯度衰减问题。在使用 Sigmoid/Tanh 的深层网络中,即使加了 BN,梯度仍会逐层衰减。
Q8. 残差连接(ResNet)和激活函数是什么关系?
互补关系,不是替代关系。ResNet 通过跨层 shortcut 解决了深层网络的训练难题,但每个残差块内部仍使用 ReLU。残差连接让梯度可以直接回传,ReLU 负责引入非线性。两者结合使得训练 1000+ 层的网络成为可能。
Q9. 为什么负数输入在 ReLU 中会"死"?这不是一种浪费吗?
是设计选择,不是缺陷。ReLU 的"死亡"可以理解为:负值对当前任务没有信息贡献,置零是一种无监督的特征选择。这种稀疏性有助于:① 降低过拟合;② 加速推理(零值跳过计算)。当然,如果你认为负值可能有用,Leaky ReLU/PReLU 是更好的选择。
Q10. 不同层可以使用不同的激活函数吗?
完全可以,而且这可能是最优策略。研究表明,不同层可能适合不同的激活函数:浅层更适合 ReLU(提取低级特征),深层可能需要更平滑的激活(如 Swish)。不过在实践中,同一网络混用多种激活函数会增加调参复杂度,一般不推荐。
Q11. Softmax 是不是也是一种激活函数?
是,但比较特殊。Softmax 是多分类输出层的专用激活函数,它将多个输出归一化为概率分布:Softmax)(z_i) = (e^z_i)/(Σ_j e^z_j)。Softmax 的特点是"竞争性"——一个类别的概率升高,其他类别的概率必然降低。它通常与交叉熵损失函数配合使用。
Q12. Maxout 激活函数是什么?为什么没有流行?
Maxout 是 ReLU 的推广。Maxout 单元的输出是 max(w_1^T x + b_1, w_2^T x + b_2),可以看作是对多个仿射变换取最大值。Maxout 可以拟合任意凸激活函数,且不会饱和。但它的参数量翻倍(需要学习两组权重),计算量也更大,因此不如 ReLU 流行。
Q13. GELU 是什么?为什么在 Transformer 中这么火?
GELU 是 Gaussian Error Linear Unit。GELU 的公式是 z · Φ(z),其中 Φ 是标准正态分布的 CDF。与 ReLU 的"确定性门控"不同,GELU 是一种"随机门控"——输入被保留的概率取决于其值与标准正态分布的关系。BERT、GPT 等 Transformer 模型广泛使用 GELU,它被认为比 ReLU 更平滑、更符合注意力机制的直觉。
Q14. 激活函数的导数有什么规律?
三个层次。① 导数恒为 1(ReLU 正区间):梯度无损传播,最理想;② 导数有上限(Sigmoid 最大 0.25,Tanh 最大 1):存在梯度衰减;③ 导数可为零(ReLU 负区间、Hard 系列):可能导致训练问题。选择激活函数时,导数特性是重要考量。
Q15. 为什么 ReLU 的负区间导数是 0 而不是别的值?
简化设计 + 稀疏性收益。ReLU 的设计哲学是"简单即力量":正区间恒等(导数 1),负区间置零(导数 0)。这个极端的设定虽然可能导致 Dying ReLU,但带来了:① 硬稀疏(真正省计算);② 零值是唯一真正的"不激活"状态;③ 数学上容易分析。Leaky ReLU 则是对这种简单性的修正。
Q16. 如何选择 Leaky ReLU 的斜率 alpha?
默认值 0.01 通常足够好。alpha = 0.01 意味着负值被压缩到原来的 1%,这个幅度足够小,不会破坏稀疏性;又足够大,可以保证梯度流通。如果你的网络 Dying ReLU 问题严重,可以尝试 alpha = 0.1 或 0.2。PReLU 则让网络自己学习最优斜率。
Q17. 激活函数需要加在 BatchNorm 之前还是之后?
现代实践倾向 BN-ReLU-Conv 或 Conv-BN-ReLU。早期是 Conv-ReLU-BN(激活前归一化),但后来发现 Conv-BN-ReLU 更好:① BN 层在推理时可以融合到卷积中,节省计算;② BN 放在 ReLU 之后可以避免 BN 破坏 ReLU 的稀疏性。
Q18. 什么是 Hard-Swish?为什么 MobileNet 在用?
Swish 的近似版本,计算更高效。Hard-Swish 定义为 z · (ReLU6)(z+3)/(6),其中 ReLU6 是截断到 6 的 ReLU。Hard-Swish 避免了 Swish 中的指数运算,在移动端 GPU 上推理速度更快。MobileNetV3 就采用了 Hard-Swish 作为主要激活函数。
Q19. 激活函数和正则化有什么关系?
稀疏激活本身是一种隐式正则化。ReLU 的硬稀疏性使得部分神经元恒为零,相当于网络自动学习了特征选择。这种稀疏性可以减少过拟合,提高泛化能力。L1 正则化可以看作是将这种稀疏性"显式化"。
Q20. 激活函数的最新研究方向是什么?
自动化搜索和理论分析。① AutoML 搜索激活函数:如 Google 的 Swish、PowerReLU 等是通过神经网络架构搜索(NAS)发现的;② 动态激活函数:让激活函数根据输入动态调整;③ 理论分析:为什么 ReLU 如此有效?什么条件下某种激活函数最优?这些问题的理论答案仍在探索中。
本文核心知识点回顾
- 1 个核心作用:引入非线性,使多层网络具有表达能力
- 2 类主要缺陷:梯度消失(Sigmoid/Tanh)、死亡神经元(ReLU)
- 3 代演进:Sigmoid/Tanh → ReLU → ReLU 变体
- 4 个选择原则:首选 ReLU、警惕 Dying ReLU、输出层用 Sigmoid、灵活使用变体
Roadmap 后续预告
在理解了激活函数之后,下一篇我们将学习前向传播与反向传播——神经网络是如何通过激活函数的梯度信号,从最终的损失函数一步步调整参数的。我们将深入探讨:
- 计算图与链式法则
- 反向传播的矩阵形式推导
- 梯度消失与梯度爆炸的应对策略
- 从零实现一个多层感知机

浙公网安备 33010602011771号