我正在尝试创建一个自定义损失函数,该函数具有整数输出(在损失函数中将其转换为一种热编码)。
但是问题是one_hot没有可区分的梯度。 有解决方法吗?
def new_loss(hidden, output, random_size=20):
output1 = tf.cast(
output,
dtype=tf.int32,
)
one_hot = tf.one_hot(output1, num_words, dtype=tf.int32,)
one_hot = tf.cast(
one_hot,
dtype=tf.float32
)
score = K.dot(hidden, one_hot)
random_words = tf.random.uniform((random_size,), maxval=num_words, dtype=tf.dtypes.int32)
random_words_1_hot = tf.one_hot(random_words, num_words, dtype=tf.float32)
scores = K.dot(random_words_1_hot, hidden)
average = K.sum(K.log (1 - K.sigmoid(scores)) / random_size)
return (-1 * K.log (K.sigmoid(score)) - average)
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.
答案 0 :(得分:0)
问题不在于one_hot编码本身,而在于一系列强制转换操作。更具体地说,TensorFlow不会通过整数传播。假设hidden
和output
均为float类型,如果您对此进行更改
output1 = tf.cast(output, dtype=tf.int32,)
one_hot = tf.one_hot(output1, num_words, dtype=tf.int32,)
one_hot = tf.cast(one_hot, dtype=tf.float32)
对此
one_hot = tf.one_hot(tf.cast(output, tf.int32), num_words, dtype=tf.float32)
您将获得渐变。
更详细的示例:
one_hot1 = tf.one_hot(tf.cast(np.random.rand(2), tf.int32), num_words, dtype=tf.float32)
hidden = tf.constant([1.,2.,3.,4.], shape=(2,2))
one_hot = tf.cast(one_hot1, dtype=tf.float32)
hidden1 = tf.cast(hid, tf.float32)
score = tf.matmul(hidden, one_hot)
random_words = tf.random.uniform((random_size,), maxval=num_words, dtype=tf.float32)
random_words_1_hot = tf.one_hot(tf.cast(random_words, tf.int32), num_words, dtype=tf.float32)
scores = tf.matmul(random_words_1_hot, hidden)
average = tf.reduce_sum(tf.log(1 - tf.sigmoid(scores)) / random_size)
res = -1 * tf.log(tf.sigmoid(score)) - average
grads = tf.gradients(res, [hidden1, one_hot1])
sess = tf.Session()
print(sess.run(res))
print(sess.run(grads))
仅出于一致性考虑,我使用了核心TF操作。您可以看到,如果one_hot1
最初将创建为tf.int
,然后重铸到float
,则不会出现渐变。有关更多信息,请点击此处https://github.com/tensorflow/tensorflow/issues/20524
还有