一文讲清 ReLU, Softmax, Dropout, Cross Entropy

107 阅读6分钟

生活化比喻 + 直观代码 + 图形化思维,彻底讲清楚这四个最常用函数:

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(未归一化的分数),输出是 probabilities

logits 是模型最后一层输出的“原始分数” —— 还没经过归一化(如 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)

✅ 总结卡片:

函数公式/行为输入输出关键特点
ReLUmax(0, x)任意实数≥0引入非线性,计算快
Softmaxexp(x_i)/sum(exp(x))logits概率分布(和=1)用于多分类输出
Dropout随机设部分值为0任意同输入(训练时缩放)只在训练时启用!
Cross Entropy-log(p_correct)logits + 标签标量loss分类任务标准损失

🧠 记忆口诀:

  • ReLU → “负数归零,正数通行”
  • Softmax → “原始分变百分比,谁大谁赢”
  • Dropout → “训练开天窗,测试全上岗”
  • Cross Entropy → “猜得越准,扣分越少”