恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
深度学习中的Sigmoid:从logits到概率输出的关键细节与工程实践
首页
资讯中心
/
深度学习中的Sigmoid:从logits到概率输出的关键细节与工程实践
深度学习中的Sigmoid:从logits到概率输出的关键细节与工程实践
发布时间:2026/10/21 3:12:59
搞深度学习的人早晚都会撞上同一个困惑模型最后一层明明只输出一个浮点数可一写进报告就变成了“模型认为该样本为正类的概率是87%”。这个 float 到底经历了什么才配得上“概率”这个称呼答案基本绕不开 Sigmoid——深度学习里最经典的、把线性得分映射成 0 到 1 概率输出的函数。今天这篇就围绕 Sigmoid 与概率输出这条主线从数学原理、统计含义、训练数值稳定性、标签空间设计到后处理这几个角度把它讲透。适合刚接触分类模型、被各种损失函数和输出层搞晕的读者也适合已经跑通模型但想深挖“为什么不这么写就会炸”的工程师。1. 分类模型的最后一层输出的那个裸分数到底是什么1.1 从一次“有没有猫”的二分类说起假设我们要训练一个二分类模型判断一张图片里有没有猫。经典结构是 backbone 提取特征最后接一个全连接层输出一个标量 z。这个 z 在业界叫 logits也就是“未经归一化的得分”它可以写成 z w·x b。网络本身对这个 z 没有任何约束——它是负一百还是正一百全凭训练数据说了算。训练初期 z 可能是 3.2也可能是 -1.8甚至有时候跑到 12。这时候如果我们直接拿这个裸分数跟标签做比较问题立刻就来了第一z 的量纲没定义你不知道 10 到底算“非常确信有猫”还是“有点确信”第二z 的取值范围是 (-∞, ∞)这不符合概率的基本要求——概率必须落在 [0, 1] 区间里。Sigmoid 解决的正是这个“裸分数没法看”的问题。它的作用一句话就能概括把任意实数单调地压到 (0, 1) 开区间。大于 0 的 logits 会被映射到 0.5 以上小于 0 的会被映射到 0.5 以下等于 0 则刚好落在 0.5。1.2 为什么不直接线性缩放当概率有朋友问过那我用 min-max 归一化或者干脆把 z 乘个系数加个偏移缩放到 0~1不也一样能达到目的吗表面看差不多实际上差远了。概率要能参与后续计算和分析起码得有非负性、有界性并且在数学上能自洽。更重要的是Sigmoid 不是拍脑袋选出来的函数它背后有“对数几率”这个统计模型的支撑。真实建模过程应该是这样我们先假设样本的对数几率 log(p/(1-p)) 是特征的线性组合然后反解出 p 的表达式解出来的恰好就是一个 Sigmoid。换句话说Sigmoid 是“logit 空间到概率空间”的翻译器而不是随便找的一个挤压函数。理解了这一层后面第 3 节的内容就顺理成章了。2. Sigmoid 的数学细节一条 S 曲线背后的可导账本2.1 公式、形状和两个极限Sigmoid 的函数形式是σ(z) 1 / (1 e^(-z))画出来是一条经典的 S 形曲线。当 z 趋向正无穷时e^(-z) 趋向 0σ 趋向 1当 z 趋向负无穷时e^(-z) 趋向正无穷σ 趋向 0。z 0 是它的中心点输出正好是 0.5。这带来一个很实用的性质Sigmoid 是严格单调递增的也就是说 logits 的相对顺序永远不会被打乱。模型觉得 A 样本比 B 样本更像是正类那经过 Sigmoid 之后 A 的概率依然比 B 高。这个保序性特别重要因为很多后续操作比如排序、选 TopK、画 PR 曲线都依赖于“概率只是 logits 的单调变换”这个前提。2.2 导数里的梯度账Sigmoid 有个非常漂亮的导数形式σ(z) σ(z) · (1 - σ(z))这意味着我们不需要额外计算指数函数就能得到梯度。而且从公式能直接看出梯度饱和的规律当 σ 接近 0.5 时导数最大等于 0.25当 σ 偏向 0 或 1 时导数迅速衰减到接近 0。这就是为什么很少有人把 Sigmoid 堆在隐藏层里——多个 Sigmoid 叠加反向传播时梯度会被连续乘上好几个小于 1 的数传到前面几层基本就消失干净了。常规做法是把 Sigmoid 只放在输出层做概率解释中间隐藏层用 ReLU 这类导数恒定的激活函数保证梯度流通。这属于两层分工中间层负责学习特征输出层负责把分数翻译成概率。2.3 0.5 这个阈值到底意味着什么因为 Sigmoid 单调z 0 等价于 σ 0.5所以 0.5 天然是 logits 从负到正的“分水岭”。但这里要泼一盆冷水0.5 只是决策边界的默认值不是最优值。当正负样本比例失衡或者两类误判代价不一样时0.5 往往会带来很差的业务结果。后面第 6 节我会专门讲阈值怎么挑这里先记住一个结论不要把 0.5 当成金科玉律。3. 为什么 Sigmoid 输出的数能被读成概率3.1 从 logit 反推出来的唯一答案如果真实的类别概率是 p那么 p/(1-p) 被称为“几率”odds对 odds 取自然对数就得到“对数几率”也就是 logit。逻辑回归的核心假设是ln(p/(1-p)) w·x b也就是认为 logit 是特征的线性组合。这个式子本身没什么神秘的就是给线性回归套了一层“对数几率”的外壳。现在把 p 单独解出来p 1 / (1 e^(-(w·xb))) σ(w·xb)看到没有Sigmoid 完全是这个反推过程的必然产物。所以逻辑回归并没有发明一个奇怪的激活函数它只是选择了“logit 是线性的”这个建模假设然后 p 的表达式自然就长成了 Sigmoid 的样子。这也是为什么 Sigmoid 的输出被认为有概率含义——它在数学上就是概率空间的坐标。3.2 与交叉熵形成的“天生一对”光有形式还不够还得看训练目标。二分类交叉熵长这样L -[y·ln(p̂) (1-y)·ln(1-p̂)]把 p̂ σ(z) 代进去然后对 z 求梯度结果会化简成非常干净的形式∂L/∂z p̂ - y这个式子有多舒服呢它意味着梯度只取决于“预测概率和真实标签的差”。当模型很自信地犯错时比如 y1 但 p̂ 接近 0梯度会很大模型会被猛推一把当模型接近正确时梯度自动变小更新步长放缓。这种“误差驱动”的机制正是分类训练想要的。反过来看如果拿 MSE 去拟合概率梯度里会多出一个 σ(z) 因子。在 Sigmoid 饱和区 σ(z) 几乎为 0于是梯度消失训练彻底停滞。这就是分类任务默认用交叉熵而不是 MSE 的根本原因。3.3 这个“概率”必须打引号我必须反复强调一个容易误导新人的点Sigmoid 的输出本质上是“模型在训练数据分布下的置信度分数”不等同于真实世界中事件发生的概率。一个模型完全可能对某个误分类样本输出 0.99 的置信度尤其是当训练数据和真实分布有偏移时这种“过置信”现象非常普遍。所以如果你要对业务方说“模型有 99% 的把握”最好先做概率校准比如温度缩放或保序回归。否则这句话严格来说站不住脚。概率输出是给决策系统用的原料不是给领导看的绝对承诺。4. 训练时最容易翻车的环节直接在 Sigmoid 后面接交叉熵4.1 数值爆炸的真实现场初学者最容易写出的代码是这样先对 logits 做 Sigmoid拿到概率再手动算交叉熵。数学上没错数值上会出事。问题出在 log 函数身上。假设 z -100Sigmoid 在单精度的浮点表示下会被直接舍入成 0然后 ln(0) 就是负无穷反向传播回去梯度直接变 NaN。另一种情况是 z 很大时模型输出的 p̂ 离 1 极度接近1-p̂ 发生灾难性抵消精度几乎全部丢失。我见过不止一个刚上手的朋友在这上面卡了一下午loss 曲线突然蹦到 inf然后开始怀疑是学习率问题改了半天才发现是数值实现的问题。4.2 成熟的框架都提供了合并版本主流深度学习框架老早就把这件事合并成一个函数直接在 logits 上算损失内部用等价但数值稳定的形式绕开中间过程的溢出。PyTorch 里就是BCEWithLogitsLoss或者F.binary_cross_entropy_with_logits而不是先F.sigmoid(z)再F.binary_cross_entropy。TensorFlow / Keras 里对应的是binary_crossentropy(from_logitsTrue)。import torch import torch.nn.functional as F # 不推荐手动先过 sigmoid 再算交叉熵极端 logits 下会出现 NaN prob torch.sigmoid(logits) loss F.binary_cross_entropy(prob, labels) # 推荐直接对 logits 算框架内部做了数值稳定合并 loss F.binary_cross_entropy_with_logits(logits, labels)逻辑上这两个写法是等价的差异全在浮点运算的稳定性上。从工程可复现的角度讲永远不要自己手工拆开这两个操作。4.3 那什么时候才显式地算 Sigmoid答案很明确推理阶段。也就是模型训练收敛之后我们需要把 logits 翻译成给人看的概率这时候才调用torch.sigmoid或tf.sigmoid。我有一个坚持了很久的习惯模型保存时保存 logits而不是只保存概率。有一次做内容风控项目模型已经上线了业务方突然说想调整判定阈值而且希望不重新训练。如果当时保存的是概率我还得把全量数据重新过一遍模型因为保存的是 logits我只需要在 logits 上做一个简单变换——加偏移量、再做 Sigmoid——就等价于平移了决策边界几分钟搞定。这个细节省下的工作量远比想象中大。5. 一张图有猫又有狗Sigmoid 与 Softmax 的分工边界5.1 单标签问题和多标签问题的本质区别很多人在 Softmax 和 Sigmoid 之间选错是因为没有分清任务空间。Softmax 可以看成 Sigmoid 在多类别上的推广它通过对所有类别输出做归一化强制各类概率之和为 1因此天然适合单标签任务。手写数字识别就是典型——一个样本必然只属于 0 到 9 中的一个类别。多标签任务就完全不同了。比如一张图里同时有猫又有狗模型需要回答“图里有没有猫”和“图里有没有狗”两个独立的问题。正确做法是每个类别单独接一个 Sigmoid 输出每个输出单独用二分类交叉熵训练。这时候模型输出的 N 个概率互不相关加起来也完全可能大于 1——这是正常的不是 bug。5.2 选错之后的典型症状把多标签任务错误地套上 Softmax会出现一个非常典型的现象所有类别的输出相互竞争强的那一类会压低其他类别。比如一张确实“有猫也有狗”的图Softmax 输出可能是猫 0.6、狗 0.4看似模型“不太确定”实际上模型的意思是“只能二选一的话我倾向于猫”这根本不是我们要的答案。身边有同学做过一个多标签分类模型硬生生用了 Softmax验证集指标一直上不去调参调了一周。后来我让他把输出层改成 N 个独立的 Sigmoid损失函数改成 N 路 BCE同样的 backbone没调别的指标立刻恢复正常。这类问题在代码上只是几行的差异但对任务建模的理解差之毫厘结果谬以千里。下面是两类模型的对照维度Sigmoid多标签Softmax单标签多类输出范围每个类别独立落在 (0,1)所有类别总和为 1类别关系互相独立可同时为正互斥只能有一个为正损失函数多路二分类交叉熵多分类交叉熵典型场景图像多标签、标签体系可叠加手写数字、物体种类识别是否加总为 1不加总可能大于 1强制加总为 15.3 One-vs-Rest 思路下的 Sigmoid 能做多分类吗理论上可以。用 one-vs-rest 思路为每个类别训练一个二分类器最后拼出多分类结果。但这样做有一个绕不开的问题每个二分类器看到的是“本类 vs 其他所有类”正负样本比会非常夸张类别不平衡被成倍放大训练效率很差。Softmax 天然处理了类别间的归一化与竞争所以现代深度模型在单标签分类里基本都直接用 Softmax很难再见到用多个 Sigmoid 拼多分类的做法。6. 拿到概率之后阈值、校准和不平衡样本的实战处理6.1 阈值不是拍脑袋定的 0.5前面提到阈值 0.5 只是默认值真正落地几乎都要重新选。做法不复杂在验证集上把概率从 0 到 1 之间按步长扫描每个阈值算一组精确率和召回率画出 PR 曲线然后根据业务目标挑点。不同场景诉求完全不同。医疗初筛任务宁可误报也要把所有疑似阳性找出来那就把阈值下调优先保召回垃圾邮件过滤拦错一封正常邮件比漏掉一封垃圾邮件更恼火那就把阈值上调优先保精确率。这类决策跟模型本身无关是纯工程和业务权衡。这里再送一个我常用的进阶技巧如果模型保存的是 logits调整阈值根本不用重新跑模型。你只需要在 logits 上减去一个偏移量再做 Sigmoid等效于把决策边界平移。这在模型部署之后响应业务变化时非常实用改动成本瞬间从“全量重算”降到“一个线性变换”。6.2 不平衡样本下的输出层初始化正样本占比只有 1% 的任务比如点击率预测、故障检测如果输出层 bias 初始化为 0模型前期输出概率会在 0.5 附近徘徊需要好几轮训练才能慢慢把整体预测均值拉到接近 1% 的水平收敛特别慢。更聪明的做法是直接利用先验把 bias 初始化到位。设正样本先验比例为 π那么 bias 初始化为 ln(π/(1-π))。这样模型第一轮的输出均值已经接近真实正样本比例损失起点更低训练速度快一截。import math prior_pos 0.01 # 训练集里正样本占比你先统计一下就行 bias_init math.log(prior_pos / (1.0 - prior_pos))这个技巧在文档里不常被提及但在我做过的几个严重不平衡项目里它节省的迭代时间非常可观属于性价比极高的小改动。6.3 概率校准别把置信度当准确率最后再聊校准。一个输出 0.9 的样本如果落到现实里只有 70% 是对的那这个模型就是过置信的。检查方法很简单画可靠性图reliability diagram把验证集样本按预测概率分桶比如每 0.1 一桶然后统计每个桶里真实正样本的比例跟桶内的平均预测概率做对比。两条线越接近校准越好。发现偏差明显时最简单的修正手段是温度缩放在验证集上优化一个标量温度系数 T把 logits 除以 T 再做 Sigmoid。T 大于 1 会压低极端置信度T 小于 1 会拉开差距。关键的是温度缩放只改变置信度水平不改变样本之间的排序所以它不会破坏 AUC 之类的排序类指标只会让输出的概率更接近真实频率。我个人的习惯是任何模型的概率输出在完成校准验证之前都只把它当作排序分数来用而不是绝对概率。等验证集上的校准曲线和最优阈值都确认后才让这个输出出现在对外展示或下游决策里。Sigmoid 本身只是一个极简的函数但围绕它展开的 logits 记账、数值稳定、标签空间设计和后处理才是决定一个分类模型是否能扛得住真实业务需求的关键。希望这篇能帮你在自己的项目里把每一个细节都安排明白。