在Keras中实现自定义损失函数时,我需要一个tf.Variable
,其形状为输入数据(y_true, y_pred)
的批量大小。
def custom_loss(y_true, y_pred):
counter = tf.Variable(tf.zeros(K.shape(y_true)[0], dtype=tf.float32))
...
但是,这会产生错误:
You must feed a value for placeholder tensor 'dense_17_target' with dtype float and shape [?,?]
如果我将batch_size修复为一个值:
def custom_loss(y_true, y_pred):
counter = tf.Variable(tf.zeros(batch_size, dtype=tf.float32))
...
这样|training_set| % batch_size
和|val_set| % batch_size
等于零,一切正常。
有什么建议,为什么基于输入形状(y_true
和y_pred
)的批量大小的变量赋值不起作用?
解
我找到了一个令人满意的解决方案。我使用max batch_size初始化变量(在模型构建时指定)并仅使用K.shape(y_true)[0]
对变量进行切片。这样它完美地运作。这里的代码:
def custom_loss(y_true, y_pred):
counter = tf.Variable(tf.zeros(batch_size, dtype=tf.float32))
...
true_counter = counter[:K.shape(y_true)[0]]
...
它不起作用,因为K.shape
返回一个符号形状,这是一个张量本身,而不是int值的元组。要从张量中获取值,您必须在会话下对其进行评估。请参阅documentation。要在评估时间之前获得实际值,请使用K.int_shape
:https://keras.io/backend/#int_shape
但是,K.int_shape
也不会在这里工作,因为它只是一些静态元数据,通常不会反映当前的批量大小,但有一个占位符值None
。
您找到的解决方案(可以控制批量大小并在损失中使用它)确实是一个很好的解决方案。
我认为问题是因为您需要在定义时知道批量大小以构建变量,但只有在会话运行时才会知道。
如果你像张量一样使用它,它应该没问题,看看这个example。
另一种解决方案是使用tf.assign
和validate_shape=False
创建变量并动态更改其形状:
counter = tf.Variable(0.0)
...
val = tf.zeros(tf.shape(y_true)[:1], 0.0)
counter = tf.assign(counter, val, validate_shape=False)