ML 学习站
跳到正文

激活函数与损失函数

ReLU / Sigmoid / Softmax 与交叉熵的搭配。

25 分钟3 / 42,158
加载中...

激活函数和损失函数是神经网络中至关重要的两个组件,分别决定了网络能否学习到非线性关系以及学习的效果是否准确。本章详细介绍了多种激活函数和损失函数,并提供了选择建议。核心概念包括:1)激活函数如ReLU适用于隐藏层,Sigmoid适用于二分类输出层,Softmax适用于多分类输出层;2)损失函数方面,回归任务常用MSE,分类任务则使用二元交叉熵(Binary Cross Entropy)和分类交叉熵(Categorical Cross Entropy)。读者将学会如何根据任务类型选择合适的激活函数和损失函数组合,例如隐藏层使用ReLU,二分类输出层使用Sigmoid加二元交叉熵,多分类输出层使用Softmax加分类交叉熵,回归任务则使用线性激活加MSE。此外,本章还探讨了神经元死亡问题及其缓解方法,如使用Leaky ReLU或Batch Normalization。掌握这些知识后,读者能够有效地构建和训练神经网络,避免常见的梯度消失或爆炸问题。

激活函数与损失函数

激活函数决定网络能不能学到非线性,损失函数决定网络"学得对不对"。这一章讲清楚怎么搭配。

激活函数全景

名称公式输出范围适用场景
Sigmoid1 / (1 + e^(-x))(0, 1)二分类输出层
Tanhtanh(x)(-1, 1)老的隐藏层,0 中心
ReLUmax(0, x)[0, ∞)隐藏层默认
Leaky ReLUmax(0.01*x, x)(-∞, ∞)防神经元死亡
PReLUmax(alpha*x, x),alpha 可学(-∞, ∞)进一步提升
ELUx if x>0 else alpha*(e^x - 1)(-α, ∞)平滑,均值接近 0
Softmaxe^(x_i) / sum(e^(x_j))(0, 1) 和为 1多分类输出

选哪个?

神经元死亡问题(Dead ReLU)

ReLU 在 x < 0 时梯度为 0。如果某个神经元的输入永远是负的,它就永远不更新,变成"死神经元"。

缓解方法:

  • Leaky ReLU: x < 0 时也有一个小的梯度(0.01)
  • 合理的学习率(太大容易让神经元"被冲过零")
  • Batch Normalization(让输入分布稳定)

损失函数全景

回归任务

损失公式特点
MSE(1/n) * sum((y - y_hat)^2)对大误差惩罚重,最常用
MAE`(1/n) * sum(y - y_hat
Huber(1/n) * sum(L_delta(y - y_hat))MSE 和 MAE 的混合
# PyTorch
loss = torch.nn.MSELoss()
loss = torch.nn.L1Loss()  # MAE
loss = torch.nn.SmoothL1Loss()  # Huber

分类任务

二分类(Binary Cross Entropy):

L = -(1/n) * sum[ y*log(y_hat) + (1-y)*log(1-y_hat) ]

要求输出层是 sigmoid(把 logits 压到 0~1)。

loss = torch.nn.BCELoss()  # 输入已经是 sigmoid 后的概率
# 或者更稳的:
loss = torch.nn.BCEWithLogitsLoss()  # 输入是 logits,内部加 sigmoid

多分类(Categorical Cross Entropy):

L = -(1/n) * sum_c (y_c * log(y_hat_c))

要求输出层是 softmax(输出概率分布,各类和为 1)。

loss = torch.nn.CrossEntropyLoss()  # 内部包含 softmax + NLLLoss
# 输入:logits (N, C), 目标:类别索引 (N,)

为什么这个搭配最稳?

直觉上,激活函数 + 损失函数要"匹配":

Sigmoid + Binary Cross Entropy:

  • BCE 的梯度形式非常简洁
  • 避免了 sigmoid 输出接近 0/1 时梯度饱和的问题(因为 BCE 的 log 项会自动放大错误信号的梯度)

Softmax + Categorical Cross Entropy:

  • Softmax 输出的概率分布 → 交叉熵天然衡量两个分布的距离
  • 数学上:softmax + cross_entropy 的反向传播梯度就是 y_hat - y,简洁到不能再简洁

线性 + MSE:

  • 输出没有范围限制(实数)
  • MSE 直接衡量"差多少"

不匹配的灾难

                sigmoid → MSE      softmax → MSE       linear → BCE
                (不推荐)           (不推荐)              (不推荐)
                
为什么?         梯度饱和          梯度饱和              类别不平衡时差
                收敛慢            几乎学不到东西

经验:选错了损失函数,网络可能"装死"(loss 不下降)或"发疯"(loss 飞出去)。激活函数 + 损失函数 + 输出范围三者必须自洽。

实战建议

# 一个典型的多分类网络
class Classifier(nn.Module):
    def __init__(self, input_dim, num_classes):
        super().__init__()
        self.features = nn.Sequential(
            nn.Linear(input_dim, 256),
            nn.ReLU(),              # 隐藏层用 ReLU
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, num_classes)  # 输出层不加激活!CrossEntropyLoss 会加 softmax
        )

    def forward(self, x):
        return self.features(x)

model = Classifier(784, 10)
criterion = nn.CrossEntropyLoss()  # 内部 softmax
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

小结

  • 隐藏层默认 ReLU,输出层由任务决定:sigmoid(二分类)/ softmax(多分类)/ 线性(回归)
  • 损失函数跟任务匹配:二分类 BCE、多分类 CCE、回归 MSE/MAE
  • CrossEntropyLoss 内部含 Softmax,不要再加
  • 选错搭配梯度会消失或爆炸,网络根本训不动

练习思考

  1. 为什么 BCELoss 经常出 nan?改用 BCEWithLogitsLoss 会有什么改善?
  2. 多分类任务里有 1000 个类别,最后一层线性层的输出维度应该是多少?
  3. 用 MSE 做多分类有什么具体问题?可以从梯度大小的角度定量分析。

章末小测验

检验你对《激活函数与损失函数》的掌握程度。

1

为什么隐藏层默认用 ReLU 而不是 Sigmoid?

2

为什么 nn.CrossEntropyLoss 内部已经包含 Softmax,不要再加?

讨论区(0)

加载评论中...