tensorflow中常见的loss函数

       损失函数(loss/cost)用于描述模型预测值与真实值的差距大小.

       一般常见的有两种算法----均值平方差(MSE) 和 交叉熵。

       参考:https://blog.csdn.net/qq_42413820/article/details/80936092

1)均值平方差

    在tensorflow中没有独立的MSE函数,不过可以自己组合:

    MSE = tf.reduce_mean(tf.pow(tf.sub(logits, labels), 2.))

    MSE = tf.reduce_mean(tf.square(tf.sub(logits, labels)))

    MSE = tf.reduce_mean(tf.square(logits, labels))

    labels代表标签值,logits代表预测值

2)交叉熵

  在 tensorflow 中常见的交叉熵函数有:

  1. sigmoid 交叉熵

  2. softmax 交叉熵

  3. spares 交叉熵

  4. 加权sigmoid 交叉熵

tf.nn.weighted_cross_entropy_with_logits(logits, targets,pos_weight,name=None) 在交叉熵的基础上给第一项乘以一个系数(加权),是增加或减少正样本在计算交叉熵时的损失值
tf.nn.sigmoid_cross_entropy_with_logits(logits, targets,name=None) 计算输入logits与targets的交叉熵
tf.nn.softmax_cross_entropy_with_logits(logits, labels,name=None)

计算输入logits与labels的softmax交叉熵

logits与labels必须是相同shape的数据类型

tf.nn.spares_softmax_cross_entropy_with_logits(logits, labels,name=None)

计算输入logits与labels的softmax交叉熵

与softmax_cross_entropy_with_logits功能一样,区别是spares_softmax_cross_entropy_with_logits的样本真实值与预测值结果不要one_hot编码,但是要求分类的个数一定要从0开始。假如是5类,就是0,1,2,3,4这5个数

3)softmax算法与损失函数实验

import tensorflow as tf

'''
交叉熵实验
有一个便签值 labels 和一个网络输出值 logits
1)两次 softmax 实验: 将输出值 logits 分别进行1次和2次softmax,观察两次的区别及意义
2)观察交叉熵:将 1)中的两个值分别进行 softmax_cross_entropy_with_logits 观察他们的区别
3)自建公式实验:将做2次softmax的值放到自建组合的公式中得到正确的值
'''
labels = [[0, 0, 1], [0, 1, 0]]
logits = [[2, 0.5, 6], [0.1, 0, 3]]

logits_scaled = tf.nn.softmax(logits)
logits_scaled2 = tf.nn.softmax(logits_scaled)

result1 = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels)
result2 = tf.nn.softmax_cross_entropy_with_logits(logits=logits_scaled, labels=labels)
result3 = -tf.reduce_sum(labels*tf.log(logits_scaled), 1)

with tf.Session() as sess:
    print('scaled= ', sess.run(logits_scaled))
    # scaled=  [[0.01791432 0.00399722 0.97808844] [0.04980332 0.04506391 0.90513283]]

    # 经过第二次的 softmax 后,分布概率会有变化
    print('scaled2= ', sess.run(logits_scaled2))
    # scaled2 = [[0.21747023 0.21446465 0.56806517] [0.2300214  0.22893383 0.5410447]]

    # 正确方式
    print('result1', sess.run(result1), '\n')   # result1 [0.02215516 3.0996735 ]

    # 如果将 softmax 变换完的值放进去,就相当于第二次 softmax 的loss, 所以会出错
    print('result2', sess.run(result2), '\n')   # result2 [0.56551915 1.4743223 ]

    print('result3', sess.run(result3), '\n')   # result3 [0.02215518 3.0996735 ]
'''
1)可以看到 logits 中的值原本加和都是大于1的,经过 softmax 之后, 总和为1
2)样本中第一个与分类标签相符,第二个不相符,所以 resulrt1 结果是 第一个的交叉熵比较小,第二个比较大
3)从 result1 和 result2 可以看出,传入 softmax_cross_entropy_with_logits 的 logits 是不需要进行softmax
   如果将softmax后得scaled传入softmax_cross_entropy_with_logits就等于进行了两次softmax转化 
   也就是说 tf 中的 softmax_cross_entropy_with_logits 函数会进行一次 softmax 操作
4)对于用 softmax 转化后得scaled, 在计算时就不能再用tf里面的softmax_cross_entropy_with_logits了,
  可以自己组合 例如: result3 也可以得到正确结果 
'''

'''
one_hot实验
对非 one_hot 编码为标签的数据进行交叉熵运算,比较其与one_hot编码的交叉熵之间的差别
'''
# 标签总概率为1
labels = [[0.4, 0.1, 0.5], [0.3, 0.6, 0.1]]
result4 = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels)
with tf.Session() as sess:
    # result4:  [2.1721554 2.7696736]   对于正确分类的交叉熵与错误分类的交叉熵,二者差别没有 one_hot 编码那么明显
    print('result4: ', sess.run(result4), '\n')

'''
sparse交叉熵的使用
使用 sparse_softmax_cross_entropy_with_logits 函数,
对于非 one_hot 的标签进行交叉熵计算,比较其与 one_hot 标签在使用上的区别
'''
# sparse 标签
labels = [2, 1]  # 表明 lables 中一共分为3个类: 0, 1, 2. [2, 1] == one_hot编码中的 001 和 010
result5 = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels)
with tf.Session() as sess:
    print('result5: ', sess.run(result5), '\n')  # result5:  [0.02215516 3.0996735 ] 与 result1 完全一样
'''
计算loss值
1)对于 softmax_cross_entropy_with_logits 后得结果求loss直接取均值
2)对于 softmax 后的结果使用 -tf.reduce_sum(labels*tf.log(logits_scaled)) 求均值
3)对于 softmax 后的结果使用 -tf.reduce_sum(labels*tf.log(logits_scaled), 1) 
   等同于 softmax_cross_entropy_with_logits 结果
4)由1)和3 )可以推出对3)进行求均值也可以得出正确的loss值,
   tf.reduce_mean(-tf.reduce_sum(labels*tf.log(logits_scaled), 1)) = loss
'''
loss = tf.reduce_mean(result1)
labels = [[0, 0, 1], [0, 1, 0]]
loss2 = tf.reduce_mean(-tf.reduce_sum(labels*tf.log(logits_scaled), 1))
with tf.Session() as sess:
    print('loss: ', sess.run(loss))
    print('loss2: ', sess.run(loss2))


猜你喜欢

转载自blog.csdn.net/qq_42413820/article/details/80939494