【问题标题】:One Hot Encoding in Loss Function损失函数中的一种热编码
【发布时间】:2021-02-21 19:37:58
【问题描述】:

我正在尝试在我的损失函数中对预测进行一个热编码。

def loss(y_true, y_pred, smooth=1e-7):
    y_true = K.flatten(y_true)
    y_true = one_hot(y_true, n_classes)
    y_pred = softargmax(y_pred)
    y_pred = K.flatten(y_pred)
    y_pred = one_hot(y_pred, n_classes)
    
    intersect = K.sum(y_true * y_pred, axis=-1)
    denom = K.sum(y_true + y_pred, axis=-1)
    return K.mean((2. * intersect / (denom + smooth)))

但是将y_pred 转换为int32 以便使用内置的K.one_hot 导致

 ValueError: No gradients provided for any variable:

错误。所以我编写了自己的 one_hot 编码方法,避免将y_pred 转换为int32

def one_hot(xs, n_classes):
    table = tf.eye(n_classes, dtype=tf.dtypes.float32)
    return tf.map_fn(lambda x: table[tf.raw_ops.Cast(x=x, DstT=tf.int32)], xs)

one_hot(tf.constant([0.0, 1.0, 2.0]), 3)

我的问题如下。使用tf.gather/gatner_nd 会导致相同的梯度错误,我能找到的唯一能在不导致梯度错误的情况下工作的函数是tf.map_fn,它非常缓慢地切换到vectorized_map,再次导致梯度错误。是否有另一种方法可以对具有渐变的热编码?

【问题讨论】:

  • 为什么不直接使用tf.one_hot()
  • @gobrewers14 正如我在 one_hot 工作的问题中所写 y_pred 必须强制转换为 int32 操作没有渐变,因此不起作用

标签: python tensorflow machine-learning deep-learning tensor


【解决方案1】:

您可以通过将最大 logit 设置为 1.0 并屏蔽来创建 one_hot 的数值稳定版本。

import tensorflow as tf


def stable_one_hot(vec):
    """
    Args:
        vec: tf.Tensor, a batch of logits to be encoded
    
    Returns:
        tf.Tensor, a batch of numerically stable one-hot encoded logits
    """
    m = tf.math.reduce_max(vec, axis=1, keepdims=True)
    e = tf.math.exp(vec - m)
    mask = tf.cast(tf.math.not_equal(e, 1.0), tf.float32)
    vec -= 1e9 * mask
    return tf.nn.softmax(vec, axis=1)

# dummy data w/batch of size 32
X = tf.random.normal([32, 100])

# dummy labels w/10 possibilities
y = tf.random.uniform(shape=[32], minval=0, maxval=10, dtype=tf.int32)
# one-hot them
y_true = tf.one_hot(y, 10)

# simple network
nn = tf.keras.layers.Dense(10)

# forward pass
with tf.GradientTape() as tape:
    y_pred = nn(X)
    y_pred = stable_one_hot(y_pred)
    intersect = tf.math.reduce_sum(y_true * y_pred, -1)
    denom = tf.math.reduce_sum(y_true + y_pred, -1)
    loss = 2.0 * intersect / (denom + 1e-7)
    loss = tf.math.reduce_mean(loss)

grads = tape.gradient(loss, nn.trainable_variables)
assert grads != [None, None]

print(f"loss: {loss.numpy():.4f}")
# loss: 0.1250

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 2021-09-07
    • 2021-03-11
    • 2021-04-28
    • 2021-12-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    相关资源
    最近更新 更多