其他
Focal Loss --- 从直觉到实现
CV的目标检测问题: 绝大多数检测框里都是 backgroud NLP的异常文本检测: 绝大多数文本都是 normal
升/降采样, 或者调整样本权重 换个更鲁棒的loss函数 ,或者加正则 集成模型: Bagging, RandomForest ... 利于外部先验知识: 预训练+微调 多任务联合学习 ...
现状
解决办法
方法一、分科复习
每个【科目】的难度是不同的;你要花 30%的精力在四则运算,70%的精力在三角函数。--- 老师告诉CE同学 第一个技巧
方法二、刷题战术
每道【题目】的难度是不同的;你要根据以往刷类似题时候的正确率来合理分配精力。
--- 老师告诉CE同学 第二个技巧
横轴是 , 纵轴是 总体来说,所有曲线都是单调下降的,即 “掌握越好的知识点越省力” 当 时,FL退化成CE,即蓝色线条 当 很大时,线条逐步压低到绿色位置,即各样本对于总loss的贡献受到打压;中间靠右区段承压尤其明显
方法三、综合上述两者
代码
from keras import backend as K
def focal_loss(alpha=0.75, gamma=2.0):
""" 参考 https://blog.csdn.net/u011583927/article/details/90716942 """
def focal_loss_fixed(y_true, y_pred):
# y_true 是个一阶向量, 下式按照加号分为左右两部分
# 注意到 y_true的取值只能是 0或者1 (假设二分类问题),可以视为“掩码”
# 加号左边的 y_true*alpha 表示将 y_true中等于1的槽位置为标量 alpha
# 加号右边的 (ones-y_true)*(1-alpha) 则是将等于0的槽位置为 1-alpha
ones = K.ones_like(y_true)
alpha_t = y_true*alpha + (ones-y_true)*(1-alpha)
# 类似上面,y_true仍然视为 0/1 掩码
# 第1部分 `y_true*y_pred` 表示 将 y_true中为1的槽位置为 y_pred对应槽位的值
# 第2部分 `(ones-y_true)*(ones-y_pred)` 表示 将 y_true中为0的槽位置为 (1-y_pred)对应槽位的值
# 第3部分 K.epsilon() 避免后面 log(0) 溢出
p_t = y_true*y_pred + (ones-y_true)*(ones-y_pred) + K.epsilon()
# 就是公式的字面意思
focal_loss = -alpha_t * K.pow((ones-p_t),gamma) * K.log(p_t)
return focal_loss_fixed
model = ...
model.compile(..., loss=focal_loss(gamma=3, alpha=0.5))
调参经验
反映了“方法一、分科复习”时,各科目的难度比率
二分类场景下,类似于正例的sample_weight概念,可以按照样本占比,适度加权 e.g. 设有5条正例、95条负例,则建议 取 相当于关掉该功能 反映了 “方法二、刷题战术”时,对于难度的区分程度
取 相当于关掉该功能; 即不考虑难度区别,一视同仁 越大,则越重视难度,即专注于比较困难的样本。建议在 范围尝试
总结
机器学习分类问题中,各类别样本数差距悬殊是很常见的情况;这会干扰模型效果
通过将CrossEntropyLoss替换为综合版的FocalLoss,可以有效缓解上述问题
具体思路就是引入两个额外的变量来区分对待每个样本
根据类别加权 根据难度加权 代码实现很简单、调参也不复杂,详见上文
参考文献
Focal Loss for Dense Object Detection Demystifying Focal Loss I: A More Focused Cross Entropy Loss Focal loss论文详解 Focal loss 原理及keras实战