我正在尝试在具有多个类的keras / tensorflow中使用散焦,这导致我猜想使用分类散焦。我发现了一些实现heretherethere

据我所知,焦点损失中的参数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])


我不确定背景样本和前景样本之间是否应该有任何区别(这是另一个主题问题)。

07-24 09:52