我目前正在实现自定义丢失层,在此过程中,我偶然发现了objectives.py文件[1]中均方误差的实现。我知道我在理解这种损失计算时遗漏了一些东西,因为我一直认为平均值是在每个小批量(张量轴0)的每个输出的样本中单独完成的,但看起来平均值实际上是在最后一个轴上完成,在一个向量中,意味着它在输出中完成。我在处理自定义丢失层时偶然发现了这个问题,因为它需要对特定位置的训练输出中的一些输出的丢失进行折扣。无论如何,我对均方误差的理解是不正确的?为什么Keras会使用最后一个轴,从而将1xn输出向量转换为1x1输出向量?
感谢。
[1] https://github.com/fchollet/keras/blob/master/keras/objectives.py#L7
答案 0 :(得分:7)
有关MSE损失的问题是:
def mean_squared_error(y_true, y_pred):
return K.mean(K.square(y_pred - y_true), axis=-1)
首先减去y_pred和y_true,然后将结果传递给K.square,按预期方式返回其参数的平方,然后将结果赋予K.mean,计算均值。
所以代码显然正在做它应该做的事情。关于为什么操作最后一个轴,这与类无关,它只是一个约定。请注意,通常,MSE定义中没有类。
答案 1 :(得分:3)
让我们详细说明如何在Keras中计算损失的步骤,以显示所有损失计算中的axis=-1
是正确的:
因此,我们会在losses.py中选择一个我们将传递给模型的compile
方法的损失。
在compile
中,计算总损失。它分几步执行:The first step创建一个损失列表,每个输出一个模型。
_weighted_masked_objective
会返回一个新的目标函数,该函数会考虑用户在使用weights
方法时提供的mask
和fit
参数。 如果我将代码剪切为仅包含对问题重要的行,我们就会得到类似的东西。
def _weighted_masked_objective(fn):
def weighted(y_true, y_pred, weights, mask=None):
score_array = fn(y_true, y_pred) # Compute loss as in losses.py
return K.mean(score_array) # Average over all axis
class Model(Container):
def compile(self, optimizer, loss, metrics=None, loss_weights=None,
sample_weight_mode=None, weighted_metrics=None,
target_tensors=None, **kwargs):
weighted_losses = [_weighted_masked_objective(fn) for fn in loss_functions]
所以最后,损失确实是在每个维度上的平均值,并且使用axis=-1
只是一种优雅的方法,可以在代码中的另一点启用屏蔽和加权损失
注意:我没有解释其他步骤,因为他们没有帮助回答这个问题。
答案 2 :(得分:2)
我相信,经过与同事的一些对话后,我了解了这种情况并找到了解决问题的正确方法。虽然我知道Theano正在提供懒惰评估的张量函数,这些函数在GPU上运行矩阵运算,但我没有意识到Keras的损失函数实际上是以编译的theano执行图是智能的方式编写的足以缓存某些值,以便在整个网络中正确地反向传播损失值。由于我创建的网络类型,我潜心编写自己的自定义损失函数,而没有完全理解Theano在函数计算后如何处理损失。
据我所知,我的担忧是正确的,Keras'使用最后一个轴是一个问题。在我的例子中,我有一个完全卷积的深度神经网络,损失函数的输入是(x,7,16,16),其中x是小批量的大小。通常,神经网络输出矩阵,其中第一维是小批量大小,第二维(通常是最后)维是输出向量的实际大小。因此,使用输出张量中的最后一个轴来做实际的"意味着"均方误差的一部分是不正确的。相反,轴应该是1(在基于零的索引的情况下),因为它是需要区分用于反向传播的7个实际回归输出特征。
我原本知道轴= -1可能不正确,我发布这个问题的原因是因为我无法解释原因。已经很长一段时间了,因为我不得不深入研究神经网络背后的数学,但是当我最终做到这一点时,我能够解决这些差距(我认为)。我在这里发布这个回复,以便将来可能会遇到同样的问题或者他们对Theano的张量框架理解上的差距。