多个类的 tf.losses.logloss

Posted

技术标签:

【中文标题】多个类的 tf.losses.logloss【英文标题】:tf.losses.log_loss for multiply classes 【发布时间】:2019-04-01 08:11:25 【问题描述】:

我已经测试了 tf.losses.log_loss 的二进制分类问题,与 numpy 实现和 sklearn 实现相比,它看起来不错:

# Array of samples
y_pred_arr = np.array([0.6,0.3,0.9], np.float32)
y_true_arr = np.array([1,0,1], np.float32)

print('y_pred_arr.shape', y_pred_arr.shape)
print('y_true_arr.shape', y_true_arr.shape)

# 1 : Implemented in numpy
def cross_entropy_loss(y_pred_arr, y_true_arr, eps=1e-6):
    p_arr = np.clip(y_pred_arr, eps, 1 - eps)
    n_samples = p_arr.shape[0]
    loss_arr = np.zeros((n_samples,), np.float32)
    for i in range(n_samples):        
        if y_true_arr[i] == 1:
            loss_arr[i] = -np.log(p_arr[i])
        else:
            loss_arr[i] = -np.log(1 - p_arr[i])
    loss = np.mean(loss_arr)
    return loss
loss = cross_entropy_loss(y_pred_arr, y_true_arr)
print(loss)

# 2 : Implemented in sklearn
from sklearn.metrics import log_loss
loss = log_loss(y_true_arr, y_pred_arr, labels=[0,1], eps=1e-6)
print(loss)

# 3 : Impemented in tensorflow using tf.losses.log_loss
y_pred_tf = tf.convert_to_tensor(y_pred_arr, np.float32)
y_true_tf = tf.convert_to_tensor(y_true_arr, np.float32)
loss_tf = tf.losses.log_loss(labels=y_true_tf, predictions=y_pred_tf, epsilon=1e-6)
with tf.Session() as sess:
    loss = sess.run(loss_tf)
    print(loss)

输出:

y_pred_arr.shape (3,)
y_true_arr.shape (3,)
0.32428703
0.3242870296041171
0.32428563

但是对于多类问题结果是不同的:

# Array of samples
y_pred_arr = np.array([[0.4,0.3,0.3], [1.0,0.0,0.0], [0.0,0.0,1.0]], np.float32)
y_true_arr = np.array([[1,0,0], [1,0,0], [0,0,1]], np.float32)

print('y_pred_arr.shape', y_pred_arr.shape)
print('y_true_arr.shape', y_true_arr.shape)

# 1 : Implemented in numpy
def cross_entropy_loss(y_pred_arr, y_true_arr, eps=1e-6):
    p_arr = np.clip(y_pred_arr, eps, 1 - eps)
    n_samples = p_arr.shape[0]
    n_classes = p_arr.shape[1]
    loss_arr = np.zeros((n_samples,), np.float32)
    for i in range(n_samples):
        for c in range(n_classes):
            loss_arr[i] += -y_true_arr[i][c] * np.log(p_arr[i][c])
    loss = np.mean(loss_arr)
    return loss
loss = cross_entropy_loss(y_pred_arr, y_true_arr)
print(loss)

# 2 : Implemented in sklearn
from sklearn.metrics import log_loss
loss = log_loss(np.argmax(y_true_arr,axis=1), y_pred_arr, labels=[0,1,2], eps=1e-6)
print(loss)

# 3 : Impemented in tensorflow using tf.losses.log_loss
y_pred_tf = tf.convert_to_tensor(y_pred_arr, np.float32)
y_true_tf = tf.convert_to_tensor(y_true_arr, np.float32)
loss_tf = tf.losses.log_loss(labels=y_true_tf, predictions=y_pred_tf, epsilon=1e-6)
with tf.Session() as sess:
    loss = sess.run(loss_tf)
    print(loss)

输出:

y_pred_arr.shape (3, 3)
y_true_arr.shape (3, 3)
0.30543092
0.30543154478209544
0.18106996

【问题讨论】:

【参考方案1】:

就像@functor 提到的tf.losses.log_loss 是二进制交叉熵,你可以在这里查看源代码: https://github.com/tensorflow/tensorflow/blob/r1.1/tensorflow/python/ops/losses/losses_impl.py#L309

还有https://github.com/tensorflow/tensorflow/issues/2462

示例如下:

# Array of samples
y_pred_arr = np.array([[0.4,0.3,0.3], [1.0,0.0,0.0], [0.0,0.0,1.0]], np.float32)
y_true_arr = np.array([[1,0,0], [1,0,0], [0,0,1]], np.float32)

print('y_pred_arr.shape', y_pred_arr.shape)
print('y_true_arr.shape', y_true_arr.shape)

# 1 : Implemented in numpy
def cross_entropy_loss(y_pred_arr, y_true_arr, eps=1e-6):
    p_arr = np.clip(y_pred_arr, eps, 1 - eps)
    n_samples = p_arr.shape[0]
    n_classes = p_arr.shape[1]
    loss_arr = np.zeros((n_samples,), np.float32)
    for i in range(n_samples):
        for c in range(n_classes):
            loss_arr[i] += -y_true_arr[i][c] * np.log(p_arr[i][c])
    loss = np.mean(loss_arr)
    return loss
loss = cross_entropy_loss(y_pred_arr, y_true_arr)
print(loss)

# 2 : Implemented in sklearn
from sklearn.metrics import log_loss
loss = log_loss(np.argmax(y_true_arr,axis=1), y_pred_arr, labels=[0,1,2], eps=1e-6)
print(loss)

# 3 : Implemented in tensorflow
y_pred_tf = tf.convert_to_tensor(y_pred_arr, np.float32)
y_true_tf = tf.convert_to_tensor(y_true_arr, np.float32)
eps = 1e-6
cliped_y_pref_tf = tf.clip_by_value(y_pred_tf, eps, 1-eps)
loss_tf = tf.reduce_mean(-tf.reduce_sum(y_true_tf * tf.log(cliped_y_pref_tf), axis=1))
with tf.Session() as sess:
    loss = sess.run(loss_tf)
    print(loss)

输出:

y_pred_arr.shape (3, 3)
y_true_arr.shape (3, 3)
0.30543092
0.30543154478209544
0.30543092

【讨论】:

【参考方案2】:

tf.losses.log_loss 仅适用于二进制类。对于多类损失,需要手动计算,

喜欢:

cliped_y_pref_tf = tf.clip_by_value(y_pred_tf, eps, 1-eps)
loss_tf = tf.reduce_sum(tf.multiply(-y_true_tf,tf.log(cliped_y_pref_tf )))/len(y_pred_arr)

【讨论】:

以上是关于多个类的 tf.losses.logloss的主要内容,如果未能解决你的问题,请参考以下文章

具有多个模块和多个主类的spring boot项目-单元测试失败

编码的 UI 测试:创建多个单独的 UIMap 类而不只是多个部分 UIMap 类的原因是啥?

同一个类函数的多个定义取决于同一个继承类的多个类型?

具有多个类的 Scrapy 抓取 div?

避免 Sequelize 类的多个实例

jQuery选择具有多个类的输入[重复]