用 生活化比喻 + 直观代码 + 图形化思维,彻底讲清楚这四个最常用函数:
✅
ReLU—— 让神经网络“会说不”
✅Softmax—— 让模型“打分并归一化”
✅Dropout—— 让模型“考试不靠死记硬背”
✅Cross Entropy—— 告诉模型“你猜得有多离谱”
🧠 总览表(先看这张表,再看详解)
| 函数 | 作用 | 类比 | 是否可训练 | 常用位置 |
|---|---|---|---|---|
ReLU | 把负数变0,保留正数 → 增加非线性 | “过滤器”:只让正能量通过 | ❌ 无参数 | 激活函数(几乎每层后) |
Softmax | 把一组数变成概率分布(和=1) | “打分归一化器”:把原始分变百分比 | ❌ 无参数 | 分类任务输出层 |
Dropout | 随机“关闭”一部分神经元 → 防止过拟合 | “突击小测验”:不让学生背答案 | ❌ 无参数(但有状态) | 训练时隐藏层后 |
Cross Entropy | 衡量预测概率和真实标签的差距 → 损失函数 | “老师批改试卷”:算你错多少分 | ❌ 无参数 | 损失函数(分类任务) |
1️⃣ ReLU —— “正能量过滤器”
ReLU 的全称是:
Rectified Linear Unit
中文:修正线性单元
🎯 作用:
把所有负数变成 0,正数原样保留 →
f(x) = max(0, x)
- 当 x > 0 → 输出 x(线性)
- 当 x ≤ 0 → 输出 0(被“修正”)
🧂 类比:
你是一个“正能量导师”,学生向你倾诉:
- 如果他说“我今天赚了100块” → 你鼓励他:“太棒了!继续!” ✅ 保留
- 如果他说“我亏了50块” → 你安慰:“别想它了,归零重启!” → 变成 0 ❌
→ 这样,网络只传递“有希望”的信号,避免梯度消失。
📈 图形:
y
|
| /
| /
|___/______ x
0
✅ 代码示例:
import torch
import torch.nn.functional as F
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
y = F.relu(x)
print(y) # tensor([0., 0., 0., 1., 2.])
💡 为什么用 ReLU?
- 计算快(就是
max(0, x)) - 缓解梯度消失(正数梯度=1)
- 稀疏激活(很多神经元输出0 → 更高效)
- 实践效果好 —— 在 CNN、Transformer 等架构中表现优异
🚫 缺点:负数全变0 → “神经元死亡”(可用 LeakyReLU 解决)
2️⃣ Softmax —— “打分归一化器”
🎯 作用:
把任意一组数 → 变成“和为1”的概率分布
公式:softmax(x_i) = exp(x_i) / sum(exp(x_j))
🧂 类比:
三个学生考试原始分:A=2, B=1, C=0
老师不想看原始分,想看“相对优势” → 用 Softmax 转成百分比:
- A: e² / (e² + e¹ + e⁰) ≈ 0.67
- B: e¹ / (...) ≈ 0.24
- C: e⁰ / (...) ≈ 0.09
→ 现在可以说:A有67%概率是最高分!
📊 代码示例:
import torch
import torch.nn.functional as F
logits = torch.tensor([2.0, 1.0, 0.1]) # 模型原始输出(未归一化)
probs = F.softmax(logits, dim=0)
print(probs) # tensor([0.6590, 0.2424, 0.0986])
print(probs.sum()) # tensor(1.) ✅ 和为1
💡 为什么用 Softmax?
- 多分类任务必须输出“概率分布”
- 放大最大值的相对优势(指数运算)
- 配合 Cross Entropy 使用效果最佳
📌 注意:输入叫
logits(未归一化的分数),输出是probabilitieslogits 是模型最后一层输出的“原始分数” —— 还没经过归一化(如 Softmax),不能直接当概率用。
💡 为什么叫 “logits”? 源于 “log-odds”(对数几率),最早在逻辑回归中使用:
logit(p) = log(p / (1-p))→ 把概率 p 映射到实数空间 但在深度学习中,logits 泛指“未归一化的原始输出”,不一定是 log-odds。
3️⃣ Dropout —— “防作弊突击测验”
🎯 作用:
训练时,随机“关闭”(设为0)一部分神经元(比如50%),测试时全开 → 防止模型死记硬背,提高泛化能力
🧂 类比:
老师为了防止学生背答案:
- 平时小测:随机抽掉50%题目 → 学生必须真正理解所有知识点
- 期末考试:所有题目都出现 → 学生靠实力拿高分
→ 模型被迫“不依赖特定神经元”,更健壮!
📉 代码示例:
import torch
import torch.nn.functional as F
x = torch.ones(1, 10) # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
print("原始:", x)
# 训练模式:50%神经元被“关闭”(设为0),其余放大2倍(保持期望值不变)
y_train = F.dropout(x, p=0.5, training=True)
print("训练时:", y_train) # 如: [2, 0, 2, 0, 0, 2, 0, 2, 2, 0]
# 测试模式:所有神经元保留(不关闭)
y_eval = F.dropout(x, p=0.5, training=False)
print("测试时:", y_eval) # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
💡 为什么用 Dropout?
- 防止过拟合(尤其在小数据集上)
- 相当于训练了“多个子网络”,测试时集成
- 几乎成为标配(CNN、Transformer 都用)
⚠️ 注意:只在训练时用!测试时关闭!
4️⃣ Cross Entropy Loss —— “老师打分器”
Cross Entropy(交叉熵) 衡量的是:“你预测的概率分布” 和 “真实分布” 有多不一样 —— 越不一样,损失越大。 在信息论中:
- 熵(Entropy):
H(P) = -Σ P(i) log P(i)→ 衡量真实分布 P 的“不确定性” - 交叉熵(Cross Entropy):
H(P, Q) = -Σ P(i) log Q(i)→ 用分布 Q 来编码 P 所需的平均比特数 - KL散度(相对熵):
D_KL(P||Q) = H(P, Q) - H(P)→ 衡量 Q 离 P 有多远
→ 最小化 Cross Entropy = 最小化 KL散度(因为 H(P) 是常数)
“猜得越准,扣分越少;猜错还自信,扣到你哭!”
—— Cross Entropy 就是这么“严厉又公平”的老师 👩🏫
🎯 作用:
衡量“模型预测的概率分布”和“真实标签”的差距 → 值越小越好
公式(简化):loss = -log(预测正确的那个类的概率)
🧂 类比:
学生考试:
- 正确答案是 A
- 如果学生说“A的概率是0.9” → 得分:
-log(0.9) ≈ 0.1→ 高分!- 如果学生说“A的概率是0.1” → 得分:
-log(0.1) = 2.3→ 低分!
→ 模型目标:让正确类的概率 → 越接近1越好!
📊 代码示例:
import torch
import torch.nn.functional as F
# 模型输出(未经过softmax的logits)
logits = torch.tensor([[2.0, 1.0, 0.1]]) # batch=1, 3分类
# 真实标签:第0类(A)
target = torch.tensor([0])
# 方法1:手动 softmax + log + nll_loss
probs = F.softmax(logits, dim=1)
log_probs = torch.log(probs)
loss_manual = F.nll_loss(log_probs, target)
print("手动计算:", loss_manual.item()) # ≈ 0.417
# 方法2:直接 cross_entropy(推荐!内部自动做 softmax + log + nll)
loss = F.cross_entropy(logits, target)
print("直接计算:", loss.item()) # ≈ 0.417 ✅ 一样!
# 如果预测正确类概率高,loss 就低
logits_good = torch.tensor([[10.0, 0.1, 0.1]])
loss_good = F.cross_entropy(logits_good, target)
print("预测准的loss:", loss_good.item()) # ≈ 0.00005 → 很小!
💡 为什么用 Cross Entropy?
- 分类任务的“黄金标准”损失函数
- 梯度友好(配合 Softmax 数值稳定)
- 惩罚“低置信度正确”和“高置信度错误”
📌 注意:输入是
logits(不是概率!),函数内部自动做softmax
🧩 综合示例:一个完整分类模型
import torch
import torch.nn as nn
import torch.nn.functional as F
class Classifier(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super().__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.fc2 = nn.Linear(hidden_size, num_classes)
self.dropout = nn.Dropout(0.5)
def forward(self, x):
x = F.relu(self.fc1(x)) # ✅ ReLU激活
x = self.dropout(x) # ✅ Dropout防过拟合
x = self.fc2(x) # 输出 logits
return x # 不在这里做 softmax!
# 模拟数据
model = Classifier(10, 20, 3)
x = torch.randn(5, 10) # batch=5, input=10
target = torch.tensor([0, 1, 2, 0, 1]) # 真实标签
# 前向
logits = model(x) # shape: [5, 3]
# 计算损失(内部自动 softmax)
loss = F.cross_entropy(logits, target)
print("损失:", loss.item())
# 预测(测试时)
model.eval()
with torch.no_grad():
logits = model(x)
probs = F.softmax(logits, dim=1) # ✅ 测试时手动加 softmax 得概率
preds = torch.argmax(probs, dim=1)
print("预测:", preds)
✅ 总结卡片:
| 函数 | 公式/行为 | 输入 | 输出 | 关键特点 |
|---|---|---|---|---|
ReLU | max(0, x) | 任意实数 | ≥0 | 引入非线性,计算快 |
Softmax | exp(x_i)/sum(exp(x)) | logits | 概率分布(和=1) | 用于多分类输出 |
Dropout | 随机设部分值为0 | 任意 | 同输入(训练时缩放) | 只在训练时启用! |
Cross Entropy | -log(p_correct) | logits + 标签 | 标量loss | 分类任务标准损失 |
🧠 记忆口诀:
- ReLU → “负数归零,正数通行”
- Softmax → “原始分变百分比,谁大谁赢”
- Dropout → “训练开天窗,测试全上岗”
- Cross Entropy → “猜得越准,扣分越少”