首先,从方法论的角度,我理解为什么损失函数必须依赖于神经网络的输出。这个问题更多地源于我试图更好地理解Keras和TensorFlow时进行的一项实验。请考虑以下内容:
input_1 = Input((5,))hidden_a = Dense(2)(input_1)output = Dense(1)(hidden_a)m3 = Model(input_1, output)def myLoss (y_true, y_pred): return K.sum(hidden_a) # (A) #return K.sum(hidden_a) + 0*K.sum(y_pred) # (B)m3.compile(optimizer='adam', loss=myLoss)x = np.random.random(size=(10,5))y = np.random.random(size=(10,1))m3.fit(x,y, epochs=25)
这段代码会引发以下错误:
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.
但是,如果你将A
行替换为B
行,尽管数值上没有任何变化,代码仍然可以运行。
前一种情况在我看来应该是完全可以接受的。计算图是明确定义的,所有内容在损失方面应该是可微分的。但似乎Keras要求y_pred
以某种方式包含在损失函数中,无论它是否有任何影响。
谢谢!
回答:
事实证明,这有点棘手。实际上,Keras并不需要y_pred
包含在损失函数中。然而,它需要损失函数中引用所有可训练的变量。
当你调用m3.fit()
时,Keras将在你的损失函数和你的层的可训练权重之间进行梯度计算。如果你的损失函数没有引用可训练变量集合中的相同元素,那么一些梯度计算操作将无法进行。
那么如何避免这种情况呢? 你可以引用y_pred
,即使它不做任何事情。或者,你可以冻结那些不会受到优化器影响的层(因为你无论如何都不计算它们的损失)
所以在你的情况下,你只需要冻结输出层:
output = Dense(1, trainable = False)(hidden_a)