我遵循以下问题的答案,以便在 Keras 中构建一个仅考虑前 20 个预测的自定义损失函数。
如何对自定义 Keras / Tensorflow 损失函数中的值进行排序?
但是,当我尝试使用此代码编译模型时,我收到以下有关尺寸的错误:
InvalidArgumentError: input must have last dimension >= k = 20 but is 1 for 'loss_21/dense_65_loss/TopKV2' (op: 'TopKV2') with input shapes: [?,1], [] and with computed input tensors: input[1] = <20>.
重现错误的代码的简化版本如下。
import tensorflow as tf
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.optimizers import SGD
top = 20
def top_loss(y_true, y_pred):
y_pred_top_k, y_pred_ind_k = tf.nn.top_k(y_pred, top)
loss_per_sample = tf.reduce_mean(tf.reduce_sum(y_pred_top_k,
axis=-1))
return loss_per_sample
model = Sequential()
model.add(Dense(50, input_dim=201))
model.add(Dense(1))
sgd = SGD(lr=0.01, decay=0, momentum=0.9)
model.compile(loss=top_loss, optimizer=sgd)
并且在编译模型时,会在
top_loss
函数的以下行抛出错误。
y_pred_top_k, y_pred_ind_k = tf.nn.top_k(y_pred, top)
似乎编译时的
y_pred
默认形状为[?,1]
,而tf.nn.top_k
函数期望维度至少高于'k`(即20)。
我是否必须将
y_pred
投射到某物上,以便 tf.nn.top_k
知道它具有正确的尺寸?
用途:
y_pred_top_k, y_pred_ind_k = tf.nn.top_k(y_pred[:,0], top)
y_pred[:,0]
获取整个批次的预测值作为 1 级张量。
另一个问题:
但是,最后一批您仍然会遇到问题。假设您的批次大小为 32,训练数据大小为 100,那么最后一个批次的大小将小于 20,因此
tf.nn.top_k
将导致最后一个批次出现运行时错误。只需确保您的最后一批大小 >= 20 即可避免此问题。然而,更好的方法是检查当前批次是否小于 20,如果是,则调整要在 k
中使用的
top_k
值
代码
import tensorflow as tf
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.optimizers import SGD
top = tf.constant(20)
def top_loss(y_true, y_pred):
result = tf.cond(tf.math.greater(top_, tf.shape(y_true)[0]),
lambda: tf.shape(y_true)[0], lambda: top)
y_pred_top_k, y_pred_ind_k = tf.nn.top_k(y_pred[:,0], result)
loss_per_sample = tf.reduce_mean(tf.reduce_sum(y_pred_top_k,
axis=-1))
return loss_per_sample
model = Sequential()
model.add(Dense(50, input_dim=201))
model.add(Dense(1))
sgd = SGD(lr=0.01, decay=0, momentum=0.9)
model.compile(loss=top_loss, optimizer=sgd)