在分类问题中,会碰到样本类别不均衡的情况。此时,模型为了能够降低损失,会去尽量学习多数样本,导致对少数类别样本的学习减弱。
举个不太恰当的例子,我们有数学和语文两个科目,其中数学的学习资料特别多,而语文的学习资料特别少。为了使得考试的总分较多,在更多学习资料的前提下,提升数学成绩要更为容易一些,所以会优先去学习数学,而语文的学习就会减弱。
但是,虽然我们希望总分较高,但是不希望同学偏科。咋办?老师,就给两个科目设置了得分权重,比如:语文的学习资料较少,我们给其权重大一些。数学学习资料较多,相对容易学习,我们就给其权重小一些。同学这时就有了动力,做对一个语文的题目得分相当于做对两个数学题的得分。此时,就一定程度上解决了由于样本类别不均衡带来的学习偏科问题。
我们看下,PyTorch 中对于交叉熵损失损失的公式如下:

在公式中,w 就是类别的权重。该权重可以通过 API 的 weight 参数来指定。假设:0、1 样本的数量为 20、80,则 0 类别的样本可以设置为 0.8, 类别 1 的权重可以设置为 0.2。
Focal Loss 是对前面带类别权重的交叉熵损失的一个改进,其改进的思路是这样的。我们给不同类别增加权重,目的是希望模型能够更好的学习所有的样本。前面提到的思路是机械的给少数类别样本高权重,多数类别样本高权重,忽略了一个情况:
如果少数类别样本很好学习,那没有必要给其增加高权重。如果多数类别中,一部分样本较难学习,也不能机械的给其较小的权重,而应该根据模型对样本的学习情况,再确定其权重。
也就是说,Focal Loss 将所有样本归为两类:难学习的,容易学习的。这有点像 AdaBoost 中,动态给样本设定权重一样。难易怎么界定呢?一般也得设置一个阈值。比如:模型在预测某个 1 类别样本的时候,总是能够将其预测到 0.6 以上,我们就认为它是容易分类的,对于 0 类别样本,模型总能将其预测到 0.3 以下,我们就认为该样本也是容易分类的,此时给与其较小的权重。反之,则认为其较难分类。给与其较大的权重。
这里面还有一个细节,难易样本并不是固定的,而是在训练过程中,样本的难易是会发生变化,对应的权重也会发生变化,可能会出现震荡。所以,训练时可以先使用较小的学习率进行训练,而后调整为较大的学习率。

\(y^{‘}\) 表示预测的概率值,α 先忽略。
- 如果样本为 1 类别:预测概率为 0.7,γ=2,则第一个样本损失的系数为:(1-0.7)**2 = 0.09
- 如果样本为 1 类别:预测概率为 0.3,γ=2,则第一个样本损失的系数为:(1-0.3)**2 = 0.49
从这里可以看到,对于 1 类别预测的概率越高,则损失乘以的系数就越小。也说明了,容易分类的样本带来损失就较小,而较难分类的样本带来的损失就较大一些。
- 如果样本为 0 类别:预测概率为 0.3,γ=2,则第一个样本损失的系数为:0.3**2 = 0.09
- 如果样本为 0 类别:预测概率为 0.7,γ=2,则第一个样本损失的系数为:0.3**2 = 0.49
从这里可以看到,对于 0 类别预测的概率越低,则损失乘以的系数就越小。预测的概率越高,损失乘以的系数就越高。也说明了,较难预测的样本的损失就大,容易分类样本带来的损失相对就小。
回到前面 α,它其实就是最开始我们提到的根据类别样本数量设定的样本的权重。Focal Loss 在此基础上调整损失的系数。