跳转至

P5-3.6 输出层(output layer)与激活的选择

Section ID: P5-3.6 Version: v2026.07.20

在 P5-3.1 里,我们已经看过为什么需要激活函数;而从 P5-3.2 到 P5-3.5,则分别看了 sigmoid、tanh、ReLU 与代表性函数的公式比较。走到这里之后,下一个问题就会自然出现。

既然隐藏层里经常会用 ReLU 这类函数,那么最后的输出层到底该用什么样的激活?

这个问题会立刻连到损失函数(loss function)。所以这一节既是激活函数这一章的收束,也是通向下一章的桥。

输出层的激活会随着模型到底在预测什么而改变,它必须被选成一种能够匹配“输出值应该具有什么意义”的形式。

如果后面又开始混淆输出解读与激活选择的标准,更适合一起回看英文概念词汇表里的 output 条目activation function 条目

选择输出层激活的问题

  • 为什么隐藏层激活与输出层激活不能被当成同一个问题?
  • 在回归(regression)、二元分类(binary classification)、多分类(multiclass classification)里,输出层分别该怎样阅读?
  • 为什么输出层激活必须和损失函数一起考虑?
  • 看起来像概率的输出分数(score)应该怎样区分?

损失函数本身的设计会在 P5-4.1 与 P5-4.2 继续;而 calibration 的基本阅读与类概率输出的解释,则会在 P4-6.4 再接回去。也就是说,这一节先要闭合的是:输出层激活到底会把最后那个数字固定成什么样的解读单位。

预测目标与损失连接的判断标准

  • 能说明:输出层激活的选择,和模型到底在预测什么直接相关。
  • 能在回归、二元分类、多分类里,用不同方式阅读输出层。
  • 能理解输出层激活与损失函数并不是彼此分开的两件事。
  • 能按输出形式,区分最后那个数字到底应该按什么单位来读。

为什么隐藏层与输出层必须分开看

隐藏层(hidden layer)里的激活,主要和让表征变得更丰富的非线性有关。相反,输出层(output layer)里的激活,则更直接地连到最后那个值到底应该具有什么意义

也就是说:

  • 隐藏层激活更接近于“如何形成内部表征”的问题,
  • 输出层激活更接近于“如何解释最终输出”的问题。

这里可以先用下面这条区分来理解。

隐藏层改变数值,是为了形成更复杂的模式;输出层改变数值,则是为了让这些值能够以某种预测结果的形式被正确读取。

这个区分之所以重要,是因为它们都叫“激活函数”,很容易让角色混在一起。对于隐藏层,中心问题是它能不能形成更复杂的表征?;而对于输出层,中心问题则是最后这个数字到底应该怎样当作答案候选来读? 因此,输出层的选择并不是先从内部计算方便出发,而是更直接地绑定在预测对象的意义与损失解释上。

输出层要按预测目标来选

如果模型要预测的对象不同,那么最后所需要的输出形式也会不同。

例如:

  • 如果预测的是混合批次的总能耗这类连续值,就可以直接输出一个数字;
  • 如果要判断一个新警报到底该“立即停机”还是“继续监控”,就可能需要一个可以被读成 0 到 1 之间的值;
  • 如果要在“正常 / 细微划痕 / 污染”这些候选里做选择,就需要一种能比较多个候选的输出结构。

也就是说,输出层并不只是最后一个节点,而是问题定义决定最后输出长什么样子的地方

在回归(regression)里该怎样读

在回归问题里,预测的是连续数值。比如:

  • 下一批的预期能耗,
  • 压力稳定完成时间,
  • 某时段的冷却水需求量。

在这种情况下,输出层常常不会再额外套一个特殊的非线性激活,而是保留线性输出(linear output)。原因很简单:如果本来就要预测一个真实数值,却把它硬压到 0 到 1 或 -1 到 1 之间,反而会把表达范围限制住。

如果要直接预测连续值,那么让输出尽可能保持数字本身,会更自然。

在二元分类(binary classification)里该怎样读

二元分类就是在两个选择里做判断。

  • 立即停机 / 继续监控
  • 需要复测 / 自动通过
  • 过热风险 / 正常状态

在这种问题里,sigmoid 很常出现。因为 sigmoid 会把输出压成 0 到 1 之间,所以读者很容易把它读成某种像概率的值

但这里必须小心一件事。

sigmoid 输出是一个很容易按概率那样去读的值,但它并不会在所有情境里自动保证那就是严格意义上的概率。

在真实系统里,它后面往往还会跟着 threshold(阈值)策略。比如:

  • 大于等于 0.5 就判为阳性,
  • 大于等于 0.9 就直接阻断,
  • 介于 0.6 到 0.9 之间则送人工复核。

所以,输出层里的数字,与服务里的最终决策,必须分开来看。

在多分类(multiclass classification)里该怎样读

多分类就是候选不止两个,而是三个以上。

  • 正常 / 细微划痕 / 污染
  • 压力恢复 / 冷却不稳 / 传感器异常
  • 初级警报 / 现场检查 / 生产中断

在这种问题里,常见做法是先给每个类别(class)形成一个自己的分数,再通过 softmax 把这些分数变成可以互相比较的相对比例。

这里先用下面这种直觉来理解就够了。

  • 每个类别先都有自己的分数;
  • softmax 会把这些分数放在一起比较,显示出哪一个相对更大

也就是说,多分类不应该被读成每个输出各自独立解释,而应该被读成一种候选之间相互竞争的结构

把它画得最简单,就是下面这样。

flowchart TD
  A["隐藏表征"]
  B["类别分数<br/>正常、划痕、污染"]
  C["softmax 比较"]
  D["类似类别概率的输出"]

  A --> B
  B --> C
  C --> D

这张图会帮助你把多分类输出层读成先形成各类分数,再把这些分数放在一起比较的结构。softmax 不是只是把数字“变好看”,而是那个真正让多个类别候选的相对强弱显出来的步骤。

分数(score)、logit、像概率的值是同一回事吗

这里最容易让读者混淆的,有三个表达。

  • 分数(score)
  • logit
  • 像概率一样的输出

在这一节里,先做到下面这种区分就够了。

表达 给读者的解释
分数(score) 模型内部为了比较而形成的值
logit 送进 softmax 或 sigmoid 之前的最后一组分数
像概率一样的输出 经过 sigmoid 或 softmax 后,更容易被人解释的值

这个区分很重要,因为它会直接连到下一章的损失函数。有些损失函数会被设计成直接接收 logits,而有些则默认你传进来的是已经激活后的输出。

这里可以先固定这样一点:logit 还是解释前的分数,而激活后的值才是更容易被人读取的形式。 如果这个区分没有立住,那么即便是同一个数字,也很容易被混淆成:它到底是模型内部拿来比较的分数,还是人可以像概率一样去读的值。

为什么输出层激活和损失函数必须一起看

如果只单独决定输出层激活,解释会只完成一半。因为损失函数负责的,是去读取输出到底和正确答案差了多少

例如:

  • 在回归里,连续值输出与均方误差(mean squared error)通常会自然连在一起;
  • 在二元分类里,sigmoid 与 binary cross-entropy 常常一起被提起;
  • 在多分类里,softmax 与 cross-entropy 常常会配对出现。

输出层激活负责对齐输出的意义,而损失函数则会按照这种意义去读取它与正确答案的差距。

也就是说,输出层与损失函数更适合被看成一对设计,而不是两件彼此分离、各自去背的东西。

案例与例子

案例 1. 能耗预测

假设我们要预测一批混合工艺的最终能耗。人在这个场景里首先想知道的是这一批大概会用多少 kWh?,而不是它属于哪个能耗区间的概率。也就是说,输出必须保留成像 12.5kWh 这样的连续值,才能直接拿来和真实能耗比较到底差了多少。

在这类问题里,人通常想要先知道是多少,而不是先在一堆概率类别中挑一个。因此,与其把输出压成 0 到 1 之间,不如直接让能耗数字本身保留下来更自然。比如说,重要的是它到底更接近 12.0kWh 还是 15.0kWh,而像高能耗批次概率 0.8这种绕一层的值并不方便直接使用。这里真正重要的标准不是它属于哪个类别,而是它离正确数字到底有多远。因此在这个例子里,要确认的结果是:输出有没有作为一个连续值被保留下来,让你能直接比较与真实使用量之间的距离,而不是被压成某种像概率的东西。

人最容易先做的误读 为什么更差 更好的读法
看到 12.7 后,只判断它大概算高还是算低 它错过了回归输出的核心:离正确答案有多远 先比较真实答案是 12.4 还是 16.0,以及误差到底有多大
12.7 读成某个区间的概率 它会把连续值预测问题错误地改读成分类问题 把这个数字本身当成预测值,并结合允许误差一起判断

案例 2. 警报阻断过滤器

再想一个场景:线路控制系统需要决定,新出现的警报到底应该立即停机,还是继续监控。在这种情况下,操作员首先关心的不是某个精确数字,而是到底该拦还是该放? 所以像 0.91 这样的输出,不应该只被看成一个小数,而应该被看成一个明显偏向“立即停机”一侧的分数。也就是说,这类问题更接近于去读它在两个选择里偏向哪一边、有多强,而不是像回归那样直接预测一个连续数值。比如 0.91 可能触发自动停机,而 0.55 可能只会送去现场确认,因此这个输出值后面很容易立刻接上一条运行策略。关键点在于:sigmoid 输出本身并不等于最终策略。

但真实运行不会停在这里。比如说,0.91 可能触发自动停机,0.65 可能送去现场确认,而 0.30 则可能只是被记录下来。因此这个案例真正要确认的结果是:即使面对同一个 sigmoid 输出,分数的解释与实际控制规则,仍然是两个不同阶段。

如果把 0.91 立刻读成停机决定,那就会把模型输出与运行策略揉成一团。在输出层解读里,更合理的做法是:先把 0.91 看成模型输出,再在下一步通过政策规则决定是否停机。即使是同样的小数,不同设备也可能使用不同阈值,所以 sigmoid 分数的解读与 threshold 政策必须分开。

即便是同样的 sigmoid 输出,也有一些误读相对没那么糟,而有些则更危险。

输出场景 相对没那么糟的误读 更危险的误读 更好的读法
0.55 读成偏向阳性,但仍然模糊 直接决定自动停机 把模型输出与运行阈值拆开,优先看是否落在现场确认这样的中间策略区间
0.91 只把它读成强警告,细化策略稍后再看 0.91 本身当作策略,忽略不同设备阈值会不同 把它先读成强阳性分数,再确认自动停机标准究竟设在什么位置

案例 3. 质量状态分类

假设我们有一个模型,会自动把表面检测画面分成正常细微划痕污染。人往往会先想直接看到一个名字,像是这到底是什么状态? 但模型实际上会先形成一组相互竞争的分数,比如 normalscratchcontamination。这时重要的,不只是第一名叫什么,而是它到底领先了多少。

例如,如果输出是 normal 0.70, scratch 0.20, contamination 0.10,人可以读成它最明显地偏向正常。但如果输出变成 normal 0.38, scratch 0.34, contamination 0.28,那即使系统仍会选出一个答案,也很难说模型真的有很高把握。人一开始很容易觉得只看第一名名字就够了,可在实际使用里,它与其他候选到底拉开了多大距离也同样重要。比如自动分类能不能直接确认,还是应该交给人复核,就会强烈依赖这个差距。因此在这个例子里,需要确认的结果就是:输出里不只保留第一名的类别名字,还保留了它与其他候选之间的差距,从而把自动处理和人工复核分开。

输出场景 人最容易先下的判断 为什么这还不够 更好的读法
normal 0.70, scratch 0.20, contamination 0.10 normal 第一名,所以直接确定 在这个例子里问题也许不大,但它没有留下“为什么可以自动确认”的标准 同时检查第一名与其他候选之间的分数差距是否足够大
normal 0.38, scratch 0.34, contamination 0.28 normal 第一名,所以仍然直接判正常 候选差距太小,模型把握不高,却仍可能被自动确认 比起第一名名字,更先看差距不足,并转到人工复核流程

把这三个案例并排看时,就会发现:输出层的选择并不是先决定最后到底挂哪个函数,而是先决定最后那个数字到底应该被读成什么

如果把这些案例里的数字重新固定成图,差异会更明显。回归里,最先看到的是预测值离真实值有多远。

显示回归输出应按与正确答案的距离来读的图

二元分类里,则能更清楚地看出:像 0.91 这样的分数并不是策略本身,而是落在某个阈值区间里的模型输出。

显示二元分类输出应按阈值区间来读的图

多分类里,不能只盯着第一名的类别名字,还必须一起看第一名与第二名之间的差距到底大不大。

显示多分类输出应按候选分数差距来读的图

因此,在这些图里首先该看的不是曲线或柱子的样子,而是三种不同的解读单位:回归看距离二元分类看阈值位置多分类看候选差距

问题类型 人最容易先看的结果 输出层实际应当留下的解释 与损失自然连在一起的输出感觉
回归 像“多少”这样的连续数字 可以直接和真实数值比较大小的连续值 与正确数字之间的距离
二元分类 像“拦还是放”这样的两选一 0~1 之间的分数,以及其后分离的政策 朝阳性类别倾斜了多少
多分类 第一名到底叫什么 候选之间的相对比较与分数差距 正确类别在多个候选中领先了多少

读者在这张表里首先要抓住的结果是:输出层激活的选择,不是选择一个函数名字,而是先固定最后那个将被拿来和正确答案比较的输出,究竟意味着什么。

练习与例题

即使看起来都像数字,输出层也必须按问题类型不同来不同地阅读。把下面三个场景放在一起看,这个差异会更明显。

问题类型 模型最后输出 首先该读的单位 损失函数首先会比较什么
回归 预测能耗 = 12.7kWh,正确答案 12.4kWh 与正确数字的距离 预测值与真实值之间的误差
二元分类 sigmoid output = 0.881,正确答案 阳性 阈值区间与政策分离 它朝正确的阳性类倾斜了多少
多分类 normal 0.214, scratch 0.713, contamination 0.072,正确答案 scratch 第一名候选与其他候选之间的差距 正确类别比其他候选领先了多少

这张表里首先必须看清的一点是:输出值的形状它会怎样被拿去和正确答案比较是一起确定下来的。回归会保留数字本身,并直接看它离正确答案有多远。二元分类则把输出读成 0 到 1 之间的分数,再去看这个分数到底朝正确类别倾了多少。多分类不仅要看第一名是谁,还要看正确类别是否真的明显领先于其他候选。

如果把同一个场景再稍微改一下,也能更清楚看见“接下来到底该先重新看什么”。

改变后的输出场景 应该先重新看的标准 立刻该想到的问题
回归输出从 12.7 变成 13.2 与正确答案的距离,而不是数字本身的大小 它是不是离正确答案 12.4 更远了?
二元分类输出从 0.881 降到 0.61 阈值策略与分数倾向 它是不是从“自动阻断”掉进了“现场确认”区间?
多分类输出变成 0.38, 0.34, 0.28 这种彼此接近的结构 候选之间的差距,而不是第一名名字 这时人工复核会不会比自动确认更安全?

在这个练习里,下面三个问题必须自己真正闭合。

  1. 为什么像 12.7 这样的回归输出,应该先按它离正确答案 12.4 的距离来读,而不是像 sigmoid 或 softmax 那样去压缩后再读?
  2. 为什么像 0.881 这样的二元分类输出,应该先被看成一个落在阈值以上的模型输出,而不是策略本身?
  3. 为什么在多分类里,光看到 scratch 排第一还不够,还必须一起看它到底领先了其他候选多少?

答案方向是明确的。回归里,最后那个数字本身就是预测值,所以损失首先会比较它到底离真实答案差了多少。二元分类里,sigmoid 输出展示的是朝阳性类别倾斜的方向与强度,所以损失会结合真实标签是阳性还是阴性来读它。多分类里,多个候选本来就在一起竞争,因此损失也会自然地连到:正确类别到底有没有明显领先其他候选。

所以,这一节练习真正想让读者留下来的,不是用了哪个激活函数,而是最后那个数字到底该按什么单位来读,以及损失究竟会比较这个数字的哪一部分。

在早期神经网络与统计分类模型的教学传统里,最后的输出到底应该怎样读一直都是个核心问题。逻辑回归(logistic regression)与 sigmoid 的连接、多分类概率解释、以及损失函数如何与之配套,这些都不是深度学习出现以后才突然冒出来的问题。

这也是为什么在深度学习课程里,这一节必须存在。

  • 如果把激活函数只当成隐藏层里的非线性,
  • 就很容易漏掉:为什么最后那个输出会随着问题而改变,
  • 等到下一章损失函数出现时,就会只剩下突然冒出来的一堆公式。

因此,这一节其实是在为下一章做准备:它要说明,损失函数并不是凭空出现的规则,而是和输出解读绑在一起的设计

什么时候应该先把输出层解读单独分出来看

一旦隐藏层激活解释完,接下来就必须把最后那个数字到底该意味着什么单独分出来看。这一节正是负责这个转折点。

第一步,先问问题类型是什么。如果是连续值,就把最后的数字直接当预测值来读;如果是在两个选择之间做判断,就把 0 到 1 之间的分数与阈值策略一起读;如果是多个类别在竞争,就不要只看第一名名字,还要一起看候选分数与它们之间的差距。只有先把这个解读固定下来,损失函数“该怎样去读它与正确答案的差距”这一标准才会真正固定下来。

flowchart TD
  A["预测目标是什么?"]
  B["连续数值"]
  C["二选一"]
  D["多个类别中的一个"]
  E["把数字当作数值保留"]
  F["读取 0~1 分数<br/>并附上阈值策略"]
  G["比较类别分数<br/>以及领先差距"]
  H["连接到匹配的损失"]

  A --> B
  A --> C
  A --> D
  B --> E
  C --> F
  D --> G
  E --> H
  F --> H
  G --> H

在这条流程里,尤其要小心的一点,是把服务里的策略与模型里的分数直接读成一回事。模型输出是拿来和正确答案比较的最后一个值,而自动阻断、现场确认、人工复核这些运行决策,属于它之后的下一步。只有先把输出层解读拆开,P5-4 里的损失函数与评估标准才会继续沿着同一个单位接下去。

检查清单

  • 能否说明输出层激活的选择为什么会直接连到预测对象的意义?
  • 能否解释为什么隐藏层激活与输出层激活不应该被当成同一个问题?
  • 能否说明隐藏层激活与输出层激活承担的是不同角色?
  • 能否说明输出层激活必须按问题类型与输出解读来选?
  • 能否解释在回归、二元分类、多分类里,输出值应该怎样各自被阅读?
  • 能否说明输出层激活与损失函数更适合被当成一对设计?
  • 当自己因为它们都叫激活函数,就开始用同一种方式解释隐藏层与输出层时,能否主动把“输出解读问题”单独拆出来?
  • 当很容易把 sigmoid 或 softmax 输出误读成服务策略本身时,能否主动区分模型分数与运行决策?

出处与参考资料