Focal Loss 是怎么来的 从信息论说起
flyfish
Focal Loss 焦点损失的核心创新在于:能够依据模型自身的预测置信度,动态调整每个样本对应的损失惩罚权重。
在常规监督学习流程中,假如是计算机视觉中的目标检测任务,检测器会对一张图像内数千个候选区域做判别。绝大多数候选区域仅包含背景,标准损失函数会累积大量来自简单负样本的微弱误差信号,稀释少数正样本携带的有效训练梯度。
焦点损失引入了调制因子:模型对真实类别预测置信度越高,该样本贡献的损失就会被大幅衰减。举个例子:若模型已有99%把握判定某块图像区域是背景,该区域对应的损失会被压缩至趋近于0。
最终,模型参数更新将主要依靠错分样本、或是模型判别存在不确定性的样本。
按照如下思路解释
-
自信息(单个事件的意外程度)按自身概率加权平均
-
信息熵(单个分布的平均不确定性) 引入预测分布,计算差异损耗
-
KL散度(两个分布的信息差异)熵 + 差异损耗 = 交叉平均信息量
-
交叉熵(真实权重+预测信息量的平均) 落地到分类任务,one-hot简化
-
交叉熵损失(衡量预测与真实的差距,用于模型训练)
-
标准交叉熵损失(所有样本权重平等,错多少扣多少)发现痛点:难易失衡+类别失衡,简单样本主导训练方向,第一步改进:加入 (1-p_t)^γ 调制因子
-
基础版Focal Loss(动态加权难易样本,强制聚焦难分样本)第二步改进:加入 α 类别平衡权重
-
完整版Focal Loss(同时解决难易失衡与类别数量失衡)优化:加入标签平滑、全向量化实现
-
Focal Loss代码
前置:符号说明
交叉熵部分
| 符号 | 含义 | 备注 |
|---|---|---|
| x i x_i xi | 随机事件的第 i i i种可能结果 | 比如抛硬币的正面反面 |
| p ( x i ) p(x_i) p(xi) | 事件 x i x_i xi的真实发生概率 | 真实分布 p p p的概率值 |
| q ( x i ) q(x_i) q(xi) | 事件 x i x_i xi的预测/估计概率 | 近似分布 q q q的概率值 |
| I ( x ) I(x) I(x) | 单个事件的自信息(信息量) | 单位:比特(底数为2时) |
| H ( p ) H(p) H(p) | 分布 p p p的信息熵 | 单个分布的属性 |
| D K L ( p ∣ ∣ q ) D_{KL}(p || q) DKL(p∣∣q) | 以 p p p为基准的KL散度 | 衡量两个分布的差异 |
| H ( p , q ) H(p,q) H(p,q) | 交叉熵 | 两个分布的交叉度量 |
Focal Loss部分
| 符号 | 含义 | 备注 |
|---|---|---|
| p t p_t pt | 模型对真实类别的预测概率 | 取值(0,1],值越大代表模型判断越确信 |
| C E CE CE | 标准交叉熵损失 | 单个样本的基础损失值 |
| F L FL FL | 焦点损失(Focal Loss) | 加权后的最终损失值 |
| γ \gamma γ | 聚焦参数(gamma) | 控制对简单样本的压制强度,默认取2 |
| α t \alpha_t αt | 真实类别对应的平衡权重 | 用于平衡不同类别的样本数量差异 |
第1步:自信息 ------ 单个事件的信息量
1.1 含义
自信息用来量化单个随机事件发生时,带来的意外程度 :事件发生的概率越低,发生后越让人意外,带来的新信息就越多。
必然发生的事(概率=1),发生了也不会带来任何新信息,信息量为0;
概率极低的事发生了,会带来极大的信息量。
1.2 三大公理性约束
自信息的形式不是凭空定义的,它必须同时满足三条符合直觉的基本规则:
- 单调性:概率越小的事件,信息量越大;概率越大,信息量越小。
- 非负性:信息量永远≥0,事件发生最多不提供新信息,不会让认知变得更混乱。
- 独立可加性:两个相互独立的事件,同时发生的总信息量,等于两个事件各自信息量之和。
1.3 公式推导
数学上可以证明:唯一同时满足以上三条公理的连续函数,只有对数函数 。
独立事件的概率满足乘法: p ( A , B ) = p ( A ) ⋅ p ( B ) p(A,B) = p(A) \cdot p(B) p(A,B)=p(A)⋅p(B)
我们要求信息量满足加法: I ( A , B ) = I ( A ) + I ( B ) I(A,B) = I(A) + I(B) I(A,B)=I(A)+I(B)
能把乘法转化为加法的连续函数只有对数,再加上负号保证非负性,就得到自信息公式:
I ( x i ) = − log 2 p ( x i ) \boldsymbol{I(x_i) = -\log_2\ p(x_i)} I(xi)=−log2 p(xi)
底数为2时,信息量单位为比特(bit) ,是信息论的标准单位;
深度学习中常用自然对数(底数 e e e),单位为奈特,仅改变数值尺度,不影响相对大小。
1.4 示例表格
不同概率事件对应的自信息数值:
| 事件 | 发生概率 p p p | 自信息 I ( x ) I(x) I(x)(比特) | 直观理解 |
|---|---|---|---|
| 太阳东升(必然事件) | 1.0 | 0 | 完全不意外,无新信息 |
| 抛公平硬币出正面 | 0.5 | 1.0 | 有一定意外性 |
| 掷公平骰子出6点 | 1/6 ≈ 0.167 | ≈ 2.58 | 意外程度更高 |
| 抛硬币连续3次正面 | 0.125 | 3.0 | 意外程度进一步提升 |
| 中百万分之一大奖 | 1e-6 | ≈ 19.93 | 极度意外,信息量极大 |
第2步:信息熵 ------ 单个分布的平均不确定性
2.1 含义
信息熵(简称熵)描述一整个概率分布的整体平均不确定性 ,也就是长期观测这个随机事件,平均每次能获得的信息量。
熵越大 → 分布越分散 → 结果越难预测 → 不确定性越高;
熵越小 → 分布越集中 → 结果越好猜 → 不确定性越低;
必然事件的熵=0,完全没有不确定性。
2.2 公式推导
熵是自信息在自身分布下的加权平均值(数学期望):
每个事件有自己的信息量 I ( x i ) I(x_i) I(xi);
每个事件发生的频率不同,概率越高的事件对平均值的贡献越大;
用事件自身的概率作为权重,对自信息做加权平均,就得到整个分布的平均信息量。
数学期望形式:
H ( p ) = E x ∼ p I ( x ) H(p) = \mathbb{E}_{x \sim p}\left\\ I(x)\\ \\right H(p)=Ex∼p I(x)
代入自信息公式,展开为离散求和形式:
H ( p ) = − ∑ i = 1 n p ( x i ) ⋅ log 2 p ( x i ) \boldsymbol{H(p) = -\sum_{i=1}^n p(x_i) \cdot \log_2\ p(x_i)} H(p)=−i=1∑np(xi)⋅log2 p(xi)
2.3 性质
- 非负性:熵永远≥0,当且仅当分布为必然事件时取0;
- 极值性:当所有结果概率均等(均匀分布)时,熵取得最大值,此时不确定性最高。
2.4 示例表格(抛硬币场景)
三种不同偏向的硬币,对应的熵值计算:
| 场景 | 正面概率 | 反面概率 | 熵值计算过程 | 熵值(比特) | 不确定性描述 |
|---|---|---|---|---|---|
| 两面都是正面 | 1.0 | 0.0 | − 1.0 × log 2 1.0 − 0 × log 2 0 = 0 -1.0\times\log_21.0 - 0\times\log_20 = 0 −1.0×log21.0−0×log20=0 | 0 | 完全确定,无不确定性 |
| 作弊硬币(正面居多) | 0.9 | 0.1 | − 0.9 × log 2 0.9 − 0.1 × log 2 0.1 -0.9\times\log_20.9 - 0.1\times\log_20.1 −0.9×log20.9−0.1×log20.1 | ≈ 0.47 | 不确定性很低 |
| 公平硬币 | 0.5 | 0.5 | − 0.5 × log 2 0.5 − 0.5 × log 2 0.5 -0.5\times\log_20.5 - 0.5\times\log_20.5 −0.5×log20.5−0.5×log20.5 | 1.0 | 不确定性最高 |
补充视角:事件发生前,熵代表当前的不确定性大小;事件发生后,熵代表观测结果能消除的不确定性大小,两者数值完全相等。
第3步:KL散度(相对熵)------ 两个分布的信息差异
3.1 含义
KL散度(Kullback-Leibler Divergence)用来量化用预测分布 q q q去近似真实分布 p p p时,产生的平均信息损耗 ,也就是两个分布的差异程度。
两个分布越像,KL散度越小;
两个分布完全相同时,KL散度=0;
两个分布差得越远,KL散度越大。
3.2 公式推导
对单个事件 x i x_i xi:
真实的信息量(按真实分布 p p p计算): I p ( x i ) = − log p ( x i ) I_p(x_i) = -\log p(x_i) Ip(xi)=−logp(xi)
我们误以为的信息量(按预测分布 q q q计算): I q ( x i ) = − log q ( x i ) I_q(x_i) = -\log q(x_i) Iq(xi)=−logq(xi)
单个事件的信息损耗: I q ( x i ) − I p ( x i ) = log p ( x i ) q ( x i ) I_q(x_i) - I_p(x_i) = \log\frac{p(x_i)}{q(x_i)} Iq(xi)−Ip(xi)=logq(xi)p(xi)
对所有事件,按真实分布 p p p的概率 做加权平均,得到平均信息损耗,就是KL散度:
D K L ( p ∣ ∣ q ) = E x ∼ p log p ( x ) q ( x ) D_{KL}(p\ ||\ q) = \mathbb{E}_{x \sim p}\left\\ \\log\\frac{p(x)}{q(x)}\\ \\right DKL(p ∣∣ q)=Ex∼p logq(x)p(x)
展开为离散求和形式:
D K L ( p ∣ ∣ q ) = ∑ i = 1 n p ( x i ) ⋅ log 2 p ( x i ) q ( x i ) \boldsymbol{D_{KL}(p\ ||\ q) = \sum_{i=1}^n p(x_i) \cdot \log_2\frac{p(x_i)}{q(x_i)}} DKL(p ∣∣ q)=i=1∑np(xi)⋅log2q(xi)p(xi)
3.3 性质
- 非负性 :由吉布斯不等式可证明,KL散度永远≥0,当且仅当 p = q p=q p=q时取0;
- 不对称性 : D K L ( p ∣ ∣ q ) ≠ D K L ( q ∣ ∣ p ) D_{KL}(p\ ||\ q) \neq D_{KL}(q\ ||\ p) DKL(p ∣∣ q)=DKL(q ∣∣ p),它是以真实分布 p p p为基准的单向损耗。
3.4 示例计算
真实分布 p p p:公平硬币, p = 0.5 , 0.5 p=0.5,\\ 0.5 p=0.5, 0.5
预测分布 q q q:作弊硬币, q = 0.9 , 0.1 q=0.9,\\ 0.1 q=0.9, 0.1
代入公式计算:
D K L ( p ∣ ∣ q ) = 0.5 × log 2 0.5 0.9 + 0.5 × log 2 0.5 0.1 ≈ 0.5 × ( − 0.848 ) + 0.5 × 2.322 ≈ 0.737 比特 \begin{align*} D_{KL}(p\ ||\ q) &= 0.5 \times \log_2\frac{0.5}{0.9} + 0.5 \times \log_2\frac{0.5}{0.1} \\ &\approx 0.5 \times (-0.848) + 0.5 \times 2.322 \\ &\approx 0.737\ \text{比特} \end{align*} DKL(p ∣∣ q)=0.5×log20.90.5+0.5×log20.10.5≈0.5×(−0.848)+0.5×2.322≈0.737 比特
含义:用9:1的作弊硬币去近似5:5的公平硬币,平均每次观测会产生约0.737比特的信息损耗。
第4步:交叉熵 ------ 两个分布的交叉平均信息量
4.1 含义
交叉熵是用预测分布 q q q计算信息量,按真实分布 p p p的概率加权,得到的平均信息量。
交叉的含义:概率权重用真实分布 p p p,信息量用预测分布 q q q,两个分布交叉使用;
它等于真实分布自身的熵加上两个分布的信息损耗(KL散度)。
4.2 公式推导
从KL散度的公式出发,展开拆分:
D K L ( p ∣ ∣ q ) = ∑ i p i log 2 p i q i = ∑ i p i log 2 p i − ∑ i p i log 2 q i = − H ( p ) − ∑ i p i log 2 q i \begin{align*} D_{KL}(p\ ||\ q) &= \sum_{i} p_i \log_2\frac{p_i}{q_i} \\ &= \sum_{i} p_i \log_2 p_i - \sum_{i} p_i \log_2 q_i \\ &= -H(p) - \sum_{i} p_i \log_2 q_i \end{align*} DKL(p ∣∣ q)=i∑pilog2qipi=i∑pilog2pi−i∑pilog2qi=−H(p)−i∑pilog2qi
移项整理后得到:
− ∑ i p i log 2 q i = H ( p ) + D K L ( p ∣ ∣ q ) -\sum_{i} p_i \log_2 q_i = H(p) + D_{KL}(p\ ||\ q) −i∑pilog2qi=H(p)+DKL(p ∣∣ q)
等式左边就是交叉熵 ,记为 H ( p , q ) H(p,q) H(p,q),因此得到恒等式:
H ( p , q ) = H ( p ) + D K L ( p ∣ ∣ q ) \boldsymbol{H(p,q) = H(p) + D_{KL}(p\ ||\ q)} H(p,q)=H(p)+DKL(p ∣∣ q)
交叉熵的独立定义式为:
H ( p , q ) = − ∑ i = 1 n p ( x i ) ⋅ log 2 q ( x i ) \boldsymbol{H(p,q) = -\sum_{i=1}^n p(x_i) \cdot \log_2\ q(x_i)} H(p,q)=−i=1∑np(xi)⋅log2 q(xi)
4.3 示例验证
沿用上面的例子: p = 0.5 , 0.5 p=0.5,0.5 p=0.5,0.5, q = 0.9 , 0.1 q=0.9,0.1 q=0.9,0.1
真实分布的熵: H ( p ) = 1.0 H(p) = 1.0 H(p)=1.0 比特
KL散度: D K L ( p ∣ ∣ q ) ≈ 0.737 D_{KL}(p||q) ≈ 0.737 DKL(p∣∣q)≈0.737 比特
交叉熵: H ( p , q ) = 1.0 + 0.737 = 1.737 H(p,q) = 1.0 + 0.737 = 1.737 H(p,q)=1.0+0.737=1.737 比特
用独立定义式直接计算验证:
H ( p , q ) = − 0.5 × log 2 0.9 − 0.5 × log 2 0.1 ≈ − 0.5 × ( − 0.152 ) − 0.5 × ( − 3.322 ) ≈ 1.737 比特 \begin{align*} H(p,q) &= -0.5\times\log_20.9 - 0.5\times\log_20.1 \\ &\approx -0.5\times(-0.152) - 0.5\times(-3.322) \\ &\approx 1.737\ \text{比特} \end{align*} H(p,q)=−0.5×log20.9−0.5×log20.1≈−0.5×(−0.152)−0.5×(−3.322)≈1.737 比特
两种方式计算结果完全一致,恒等式成立。
第5步:交叉熵损失 ------ 分类任务的落地应用
5.1 分类任务与概率分布的映射
在图像分类(比如认猫)任务中,两个分布的角色完全对应:
真实分布 p p p :样本的标签分布。硬标签场景下是one-hot分布(比如真实是猫,对应 p = 1 , 0 p=1,\\ 0 p=1, 0),训练全程固定不变。
预测分布 q q q :模型Softmax层输出的各类别概率(比如模型输出猫的概率0.9,非猫的概率0.1,对应 q = 0.9 , 0.1 q=0.9,\\ 0.1 q=0.9, 0.1),是模型要优化的对象。
训练的目标就是:让预测分布 q q q尽可能贴近真实分布 p p p。
5.2 硬标签下的公式简化
分类任务中真实标签通常是one-hot形式:只有真实类别对应的位置概率为1,其余类别全为0。
代入交叉熵公式后,只有真实类别对应的项有数值,其余项全部为0,因此公式可以大幅简化:
H ( p , q ) = − log 2 q t H(p,q) = -\log_2\ q_t H(p,q)=−log2 qt
其中 q t q_t qt是模型对真实类别的预测置信度。
这就是分类任务中最常用的交叉熵损失形式,也叫负对数似然损失。
5.3 示例表格(认猫二分类场景)
真实标签为猫(one-hot分布 p = 1 , 0 p=1,\\ 0 p=1, 0),不同模型预测对应的交叉熵损失:
| 模型预测(猫,非猫) | 真实类别置信度 q t q_t qt | 交叉熵损失(比特) | 直观含义 |
|---|---|---|---|
| 0.99, 0.01 | 0.99 | ≈ 0.014 | 预测极准,损失极小 |
| 0.9, 0.1 | 0.9 | ≈ 0.152 | 预测较准,损失小 |
| 0.5, 0.5 | 0.5 | 1.0 | 完全瞎蒙,损失中等 |
| 0.1, 0.9 | 0.1 | ≈ 3.32 | 预测错误,损失很大 |
| 0.01, 0.99 | 0.01 | ≈ 6.64 | 完全猜错,损失极大 |
真实分布 p p p固定时, H ( p ) H(p) H(p)是常数,因此最小化交叉熵 = 最小化KL散度 = 让预测分布贴近真实分布,完全匹配训练目标。
交叉熵的部分完了,那么开始从交叉熵损失到Focal Loss
从交叉熵损失到Focal Loss
第1步:标准交叉熵损失的痛点
1.1 回顾:硬标签下的交叉熵损失
承接之前的结论,当真实标签为one-hot硬标签时,单个样本的交叉熵损失可简化为仅对真实类别计算:
C E ( p t ) = − log ( p t ) CE(p_t) = -\log(p_t) CE(pt)=−log(pt)
预测越准( p t p_t pt 越接近1),损失越小;
预测越错( p t p_t pt 越接近0),损失越大。
标准交叉熵的默认假设是:所有样本的重要性完全平等,错一分扣一分,不分简单题还是难题。
1.2 两大现实问题
在目标检测、长尾分类等真实任务中,这个假设会直接导致训练失效,是两层不平衡:
(1)难易样本不平衡
样本按分辨难度分为两类:
简单样本 :模型很容易判断正确, p t p_t pt 接近1,单个损失很小;
难分样本 :模型容易判断错误或模棱两可, p t p_t pt 偏低,单个损失较大。
真实数据中,简单样本占绝大多数,难分样本极少。单个简单样本的损失虽小,但海量样本累加后,总损失会远超难分样本,直接主导模型的梯度更新------模型只顾着把简单题做对,却学不会分辨真正的难题。
(2)类别数量不平衡
以认猫目标检测为例:
一张图上会生成数千个候选框,其中99%以上都是纯背景(负样本) ,真正包含猫的正样本可能只有3~5个。
负样本数量远多于正样本,模型只要把大部分背景判断对,总损失就能快速下降,从而偷懒不去学习如何识别猫,最终导致漏检、误判。
1.3 数值示例(认猫目标检测场景)
假设一个批次有10000个候选框:
9900个背景框(负样本):模型99%确定是背景, p t = 0.99 p_t=0.99 pt=0.99,单个交叉熵损失≈0.01
90个简单猫框(正样本):模型90%确定是猫, p t = 0.9 p_t=0.9 pt=0.9,单个交叉熵损失≈0.11
10个难分猫框(正样本):模型50%拿不准, p t = 0.5 p_t=0.5 pt=0.5,单个交叉熵损失≈0.69
计算各类样本的总损失占比:
| 样本类型 | 样本数量 | 单个CE损失 | 该类总损失 | 总损失占比 |
|---|---|---|---|---|
| 背景简单负样本 | 9900 | ≈0.010 | 99.0 | ≈85.3% |
| 简单正样本 | 90 | ≈0.111 | 9.99 | ≈8.6% |
| 难分正样本 | 10 | ≈0.693 | 6.93 | ≈6.0% |
结论非常直观:
决定模型最终性能的难分样本,只贡献了6%的总损失;海量无意义的简单背景样本,却占据了85%的损失主导权。模型优化的重心完全跑偏,训练效率和最终效果都会大打折扣。
第2步:改进 ------ 引入调制因子,解决难易不平衡
2.1 改进思路
针对简单样本权重过高的问题,改造逻辑是:
给每个样本的交叉熵损失,乘一个动态权重系数 :
样本越简单( p t p_t pt 越高),权重越小,损失被大幅压缩;
样本越难分( p t p_t pt 越低),权重越接近1,损失基本全额保留。
这个动态权重系数,就是Focal Loss的创新------调制因子(Modulating Factor)。
2.2 调制因子的设计推导
调制因子必须满足三个特性:
- 当 p t = 1 p_t=1 pt=1(完全正确的简单样本),权重=0,损失被完全消除;
- 当 p t = 0 p_t=0 pt=0(完全错误的难样本),权重=1,损失不受影响;
- 支持通过参数调节压制强度,适配不同难度的任务。
数学上, ( 1 − p t ) γ (1-p_t)^\gamma (1−pt)γ 完美满足以上所有要求,其中 γ ≥ 0 \gamma \geq 0 γ≥0 称为聚焦参数 :
γ \gamma γ 越大,对高置信度简单样本的压制力度越强;
当 γ = 0 \gamma=0 γ=0 时,调制因子恒等于1,公式退化为标准交叉熵。
2.3 基础版Focal Loss公式
将调制因子乘到交叉熵损失上,就得到了基础版焦点损失:
F L ( p t ) = − ( 1 − p t ) γ ⋅ log ( p t ) \boldsymbol{FL(p_t) = -(1-p_t)^\gamma \cdot \log(p_t)} FL(pt)=−(1−pt)γ⋅log(pt)
2.4 数值效果对比(默认 γ = 2 \gamma=2 γ=2)
| 真实类别置信度 p t p_t pt | 样本难度 | 交叉熵损失 C E CE CE | 调制因子 ( 1 − p t ) 2 (1-p_t)^2 (1−pt)2 | Focal Loss F L FL FL | 损失压缩比例 |
|---|---|---|---|---|---|
| 0.99 | 极简单 | ≈0.010 | 0.0001 | ≈0.000001 | 压缩至0.01% |
| 0.9 | 简单 | ≈0.111 | 0.01 | ≈0.0011 | 压缩至1% |
| 0.5 | 中等 | ≈0.693 | 0.25 | ≈0.173 | 压缩至25% |
| 0.1 | 难分 | ≈2.303 | 0.81 | ≈1.865 | 保留81% |
| 0.01 | 极难 | ≈4.605 | 0.9801 | ≈4.513 | 保留98% |
直观结论:
99%置信度的极简单样本,损失被压缩到原来的万分之一,几乎可以忽略;
置信度低于10%的难分样本,损失几乎全额保留,成为模型优化的绝对重心。
2.5 总量级效果验证
还是10000个候选框的场景,取 γ = 2 \gamma=2 γ=2,重新计算总损失占比:
| 样本类型 | 样本数量 | 单个FL损失 | 该类总损失 | 总损失占比 |
|---|---|---|---|---|
| 背景简单负样本 | 9900 | ≈0.000001 | ≈0.01 | ≈0.05% |
| 简单正样本 | 90 | ≈0.0011 | ≈0.099 | ≈0.5% |
| 难分正样本 | 10 | ≈0.173 | ≈1.73 | ≈99.4% |
改造后,难分样本的损失占据了99%以上的比重,模型再也不能靠刷简单背景样本混成绩,优化重心彻底转移到了真正决定性能的难分样本上。
第3步:补充类别平衡 ------ 引入 α \alpha α权重
3.1 为什么还要加 α \alpha α?
调制因子解决了难易样本的权重失衡,让模型关注难样本,但没有解决正负样本的数量失衡。
比如正样本本身数量极少,哪怕全都是难样本,总损失的绝对量依然可能偏低,模型还是会天然偏向数量更多的类别。
因此需要再引入类别平衡权重 α \alpha α:给样本少的类别分配更高的权重,给样本多的类别分配更低的权重,从数量层面平衡不同类别的总贡献。
3.2 完整Focal Loss公式
给损失再乘上对应类别的 α \alpha α权重,就得到了工业界通用的完整焦点损失:
F L ( p t ) = − α t ⋅ ( 1 − p t ) γ ⋅ log ( p t ) \boldsymbol{FL(p_t) = -\alpha_t \cdot (1-p_t)^\gamma \cdot \log(p_t)} FL(pt)=−αt⋅(1−pt)γ⋅log(pt)
其中:
α t \alpha_t αt 是样本真实类别对应的平衡权重;
通常正样本少,就给正样本设更大的 α \alpha α(如0.75),负样本设更小的 α \alpha α(如0.25)。
3.3 多分类场景的通用形式
对于 K K K个类别的多分类任务,完整的向量形式为:
F L = − ∑ i = 1 K α i ⋅ ( 1 − p i ) γ ⋅ y i ⋅ log ( p i ) FL = -\sum_{i=1}^K \alpha_i \cdot (1-p_i)^\gamma \cdot y_i \cdot \log(p_i) FL=−i=1∑Kαi⋅(1−pi)γ⋅yi⋅log(pi)
其中 y i y_i yi 是one-hot标签(真实类别为1,其余为0)。最终只有真实类别对应的项有数值,和二分类形式本质完全一致。
第4步:对应到代码实现
FocalLossWithSmoothing 代码,对应上面的完整公式:
- 取出真实类别概率 p t p_t pt
python
p_t = (probs * targets_one_hot).sum(dim=1, keepdim=True)
对应公式中提取真实类别的预测概率 p t p_t pt,用于计算调制因子。
- 计算调制因子 ( 1 − p t ) γ (1-p_t)^\gamma (1−pt)γ
python
focal_weight = (1 - p_t) ** self.gamma
完全对应调制因子的数学计算,是Focal Loss的逻辑。
- 计算带标签平滑的交叉熵 C E CE CE
python
ce_loss = (-soft_targets * log_probs).sum(dim=1)
对应基础交叉熵部分,额外加入了标签平滑的软标签处理。
- 调制因子动态加权
python
loss = focal_weight.squeeze() * ce_loss
对应公式中调制因子 × 交叉熵的运算,实现难易样本的动态加权。
- α \alpha α 类别平衡加权
python
if self.alpha is not None:
alpha_t = (self.alpha.unsqueeze(0) * targets_one_hot).sum(dim=1)
loss = loss * alpha_t
对应公式中 α t \alpha_t αt 的类别平衡加权,解决正负样本数量不平衡问题。
python
class FocalLossWithSmoothing(nn.Module):
def __init__(self, gamma=2, alpha=None, smoothing=0.0, num_classes=2):
super().__init__()
self.gamma = gamma
self.alpha = torch.tensor(alpha).to(DEVICE) if alpha else None
self.smoothing = smoothing
self.num_classes = num_classes
def forward(self, inputs, targets):
# 1. 生成标签平滑后的软标签
targets_one_hot = torch.zeros_like(inputs).scatter_(1, targets.unsqueeze(1), 1)
soft_targets = targets_one_hot * (1 - self.smoothing) + self.smoothing / self.num_classes
# 2. 计算对数概率
log_probs = torch.nn.functional.log_softmax(inputs, dim=1)
probs = torch.exp(log_probs)
# 3. 标准FocalLoss:仅对真实类别施加调制因子
# 取出每个样本真实类别的概率 p_t
p_t = (probs * targets_one_hot).sum(dim=1, keepdim=True)
focal_weight = (1 - p_t) ** self.gamma
# 4. 计算交叉熵损失,再乘调制因子和alpha
ce_loss = (-soft_targets * log_probs).sum(dim=1)
loss = focal_weight.squeeze() * ce_loss
if self.alpha is not None:
alpha_t = (self.alpha.unsqueeze(0) * targets_one_hot).sum(dim=1)
loss = loss * alpha_t
return loss.mean()
以上交叉熵内容有所简略只是提供一个推导思路,详细请看
深入理解交叉熵损失 CrossEntropyLoss - one-hot 编码
深入理解交叉熵损失 CrossEntropyLoss - 对数
深入理解交叉熵损失 CrossEntropyLoss - 概率基础
深入理解交叉熵损失 CrossEntropyLoss - 概率分布
深入理解交叉熵损失 CrossEntropyLoss - 损失函数
深入理解交叉熵损失 CrossEntropyLoss - 归一化
深入理解交叉熵损失 CrossEntropyLoss - 信息论(交叉熵)
深入理解交叉熵损失 CrossEntropyLoss - Softmax
深入理解交叉熵损失 CrossEntropyLoss - nn.LogSoftmax
深入理解交叉熵损失 CrossEntropyLoss - 似然
深入理解交叉熵损失CrossEntropyLoss - 乘积符号在似然函数中的应用