【AI课程领学】第九课 · 激活函数(课时8) 激活函数实践:如何选、如何调、如何诊断?(含一键对比实验模板)
【AI课程领学】第九课 · 激活函数(课时8) 激活函数实践:如何选、如何调、如何诊断?(含一键对比实验模板)
·
【AI课程领学】第九课 · 激活函数(课时8) 激活函数实践:如何选、如何调、如何诊断?(含一键对比实验模板)
【AI课程领学】第九课 · 激活函数(课时8) 激活函数实践:如何选、如何调、如何诊断?(含一键对比实验模板)
文章目录
欢迎铁子们点赞、关注、收藏!
祝大家逢考必过!逢投必中!上岸上岸上岸!upupup
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文。详细信息可扫描博文下方二维码 “
学术会议小灵通”或参考学术信息专栏:https://ais.cn/u/mmmiUz
详细免费的AI课程可在这里获取→www.lab4ai.cn
前言
前面 7 篇讲的是“单个激活函数的原理”。这一篇我们站在工程实践角度回答三个最常见的问题:
- 我到底该用哪个激活?
- 激活函数和初始化/归一化/优化器怎么配?
- 训练不稳定时,如何判断是不是激活的问题?
1. 选择激活函数的“实用决策树”
1.1 默认推荐(强基线)
- CNN / MLP:ReLU 或 GELU(Transformer 中常用 GELU)
- 若死 ReLU 明显:LeakyReLU
- 若想更强表达:PReLU(但小数据注意过拟合)
- 若想更平滑、均值更接近 0:ELU
- 小数据想正则化:RReLU 可试
1.2 输出层选择规则
- 二分类:Sigmoid(配 BCEWithLogitsLoss)
- 多分类:Softmax(配 CrossEntropyLoss)
- 回归:一般不用激活或用 clamp/tanh 约束范围(如 [-1,1])
2. 激活与初始化的匹配(你前面“初始化课”可直接呼应)
- Sigmoid / tanh:Xavier
- ReLU / LeakyReLU / PReLU / ELU:He(Kaiming)
- Transformer:常用 Xavier + LayerNorm(对初始化更鲁棒)
3. 如何诊断“激活相关”问题?
3.1 看激活分布(是否大量为 0?是否饱和?)
# 在 forward hook 里统计激活分布(示例)
import torch
import torch.nn as nn
import torch.nn.functional as F
def activation_stats_hook(name):
def hook(module, inp, out):
with torch.no_grad():
out_t = out if torch.is_tensor(out) else out[0]
zero_ratio = (out_t == 0).float().mean().item()
mean = out_t.mean().item()
std = out_t.std().item()
print(f"{name}: mean={mean:.3f}, std={std:.3f}, zero_ratio={zero_ratio:.3f}")
return hook
- 把 hook 注册到某层 ReLU 后,你就能监控死神经元。
3.2 看梯度范数(是否消失/爆炸)
def grad_norm(model):
total = 0.0
for p in model.parameters():
if p.grad is not None:
total += p.grad.data.norm(2).item() ** 2
return total ** 0.5
4. 一键对比实验模板:同一任务对比多种激活(可直接跑)
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(0)
X = torch.randn(2048, 20)
y = (X[:, :5].sum(dim=1) > 0).long()
class MLP(nn.Module):
def __init__(self, act_layer):
super().__init__()
self.fc1 = nn.Linear(20, 128)
self.fc2 = nn.Linear(128, 128)
self.fc3 = nn.Linear(128, 2)
self.act = act_layer
def forward(self, x):
x = self.act(self.fc1(x))
x = self.act(self.fc2(x))
return self.fc3(x)
def run(act_layer, epochs=30):
model = MLP(act_layer)
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
for _ in range(epochs):
logits = model(X)
loss = F.cross_entropy(logits, y)
opt.zero_grad()
loss.backward()
opt.step()
with torch.no_grad():
acc = (model(X).argmax(1) == y).float().mean().item()
return loss.item(), acc
acts = {
"ReLU": nn.ReLU(),
"LeakyReLU": nn.LeakyReLU(0.01),
"PReLU": nn.PReLU(),
"ELU": nn.ELU(),
"tanh": torch.tanh,
"sigmoid": torch.sigmoid
}
for name, act in acts.items():
loss, acc = run(act)
print(f"{name:10s} loss={loss:.4f} acc={acc:.3f}")
你会观察到:
- sigmoid/tanh 隐藏层通常更难训(尤其深一点)
- ReLU/LeakyReLU/PReLU/ELU 更稳定
- 具体差异取决于数据分布与网络深度
5. 实战总结表
| 激活 | 优点 | 缺点 | 常用场景 |
|---|---|---|---|
| Sigmoid | 概率输出、门控 | 饱和、梯度消失、非零均值 | 二分类输出、LSTM门 |
| tanh | 零均值、RNN常用 | 饱和、深层易梯度消失 | RNN候选状态、输出约束 |
| ReLU | 简单快、梯度稳定、稀疏 | 死 ReLU | CNN/MLP 默认 |
| LeakyReLU | 缓解死 ReLU | α需调,稀疏性下降 | 数据分布偏移/不稳定时 |
| PReLU | α可学习、更灵活 | 参数多、可能过拟合 | 追求精度、数据充足 |
| RReLU | 随机正则化 | 收敛波动、需观察 | 小数据、过拟合明显 |
| ELU | 负区间平滑、均值更接近0 | exp成本高 | 需要更平滑/更稳 |
更多推荐


所有评论(0)