我正在尝试在具有多个类的keras / tensorflow中使用散焦,这导致我猜想使用分类散焦。我发现了一些实现here和there或there。
据我所知,焦点损失中的参数a
主要用于二进制焦点损失情况下,其中存在2个类别,一个类别作为权重获得a
,另一种作为权重获得1-a
。对于分类焦点损失,我发现所有实现都仅在每个类损失前面使用权重a
,例如:
# Calculate weight that consists of modulating factor and weighting factor
weight = alpha * y_true * K.pow((1-y_pred), gamma)
# Calculate focal loss
loss = weight * cross_entropy
要么
# Calculate Cross Entropy
cross_entropy = -y_true * K.log(y_pred)
# Calculate Focal Loss
loss = alpha * K.pow(1 - y_pred, gamma) * cross_entropy
因此,我的问题是,为什么这样的权重因素会对训练过程产生影响?当然,损失通常用于计算每次迭代后增加的权重(乘以当然的学习率)。但这只是意味着每个类别在损失之前都具有相同的系数,因此没什么大不了的。这意味着我可以调整学习速度,并且具有完全相同的效果吗?我在这里想念什么?
参数
a
的确切目的是什么?我还发现了这种实现方式here,尽管它们将值传递给
(1-a)
,但它们似乎也将keras.backend.binary_crossentropy
用于底片示例,我想这会使情况变得更加复杂。知道哪个是正确的实现?
最佳答案
TL;博士
他们是一样的。因此,只需使用较简单的一种即可。
较长版本:
(玩具示例中的计算已以numpy进行,我认为相同的功能也适用于tensorflow)
在对该问题进行了一些研究之后,我得出以下结论:
在a
系数上使用固定方法的方法的确在某种程度上适用了焦点损失,因为它们将置信度得分和幂与gamma取反,但这与原始论文中提到的焦点损失不完全相同。
第二种方法似乎比原始方法更准确,尽管它们本质上是同一件事(至少在那些实现中看起来是这样)。
我用一个玩具示例对这些损失进行了一些实验。例如,使用2个前景类中的8个样本加上背景,我们得到:
gamma = 2
alpha2 = 0.25
preds = np.array(
[[0.3, 0.2, 0.5], [0.1, 0.4, 0.4], [0.1, 0.8, 0.1],
[0.7, 0.2, 0.1], [0.75, 0.15, 0.1], [0.9, 0.05, 0.05],
[0.72, 0.18, 0.1], [0.8, 0.1, 0.1]])
gt = np.array([[1, 0, 0], [0, 1, 0], [0, 1, 0],
[1, 0, 0], [1, 0, 0], [1, 0, 0],
[1, 0, 0], [1, 0, 0]]).astype(float)
而两个焦点损失将是:
focal_log_loss_v1 = -np.sum(alpha2 * gt * np.power((1 - preds), gamma) * np.log(preds), axis=-1)
alpha_factor = np.ones_like(gt) * alpha2
alpha_factor = np.where(gt == 1, alpha_factor, 1 - alpha_factor)
focal_weight2 = np.where(gt == 1, 1 - preds, preds)
focal_weight2 = alpha_factor * np.power(focal_weight2, gamma)
focal_log_loss_v2 = -np.sum(focal_weight2 * gt * np.log(preds), axis=-1)
结果表明:
focal_log_loss_v1
数组([0.14748667、0.08246617、0.00223144、0.00802519、0.00449503,
0.0002634、0.00643868、0.00223144])
focal_log_loss_v3
数组([0.14748667、0.08246617、0.00223144、0.00802519、0.00449503,
0.0002634、0.00643868、0.00223144])
这两种方法是等效的(!)。那是出乎意料的(至少在我这边)。
无论如何,对此的解释在此命令中:
gt * np.log(preds)
数组([[-1.2039728,-0。,-0。],
[-0。 ,-0.91629073,-0。 ],
[-0。 ,-0.22314355,-0。 ],
[-0.35667494,-0。 ,-0。 ],
[-0.28768207,-0。 ,-0。 ],
[-0.10536052,-0。 ,-0。 ],
[-0.32850407,-0。 ,-0。 ],
[-0.22314355,-0。 ,-0。 ]])
这基本上消除了所有非地面事实样本的所有贡献(意味着所有置信度得分不属于地面事实之一)。因此,即使
focal_weight2
对于非gt样本包含非零值,它们也会在之后被消除。focal_weight2
数组([[0.1225,0.03,0.1875],
[0.0075、0.09、0.12],
[0.0075,0.01,0.0075],
[0.0225、0.03、0.0075],
[0.015625、0.016875、0.0075],
[0.0025,0.001875,0.001875],
[0.0196、0.0243、0.0075],
[0.01,0.0075,0.0075]])
这就是为什么此代码会产生相同的损失:
alpha_factor = np.ones_like(gt) * alpha2
alpha_factor = np.where(gt == 1, alpha_factor, 0)
focal_weight2 = np.where(gt == 1, 1 - preds, 0)
focal_weight2 = alpha_factor * np.power(focal_weight2, gamma)
focal_log_loss_v3 = -np.sum(focal_weight2 * gt * np.log(preds), axis=-1)
focal_log_loss_v3
数组([0.14748667、0.08246617、0.00223144、0.00802519、0.00449503,
0.0002634、0.00643868、0.00223144])
我不确定背景样本和前景样本之间是否应该有任何区别(这是另一个主题问题)。