多个类的 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项目-单元测试失败