tf.nn.sparse_softmax_cross_entropy_with_logits 和 tf.nn.softmax_cross_entropy_with_logits分析

一、理论说明

      1、Softmax函数

            softmax函数的公式如下所示:

                                                                             P_{i} = e^{x_{i}}/\sum _{j}e^{x_{j}}

            该函数的作用主要是将输入的向量 X 归一化,使各个分量的和为1。由于这个特性,该函数常常可以用在分类问题上,在最后将输出的每个类别所对应的分量进行归一化,从而得到每个类别所对应的概率大小,实现分类。

      2、交叉熵

             交叉熵是用来衡量两个概率分布之间相似性程度的一个量,常常用在神经网络的损失函数上,来衡量预测结果与真值得差距。具体公式如下:

                                                                           E_{y^{'}}(y) = -\sum _{i}y_{i}^{'}log(y_{i})

其中,y^{'}是真实的值,y是预测输出的经过 softmax 归一化后的值。从上式可以看出,当两者的分布越接近时,E的值就会越小。

二、tf.nn.softmax_cross_entropy_with_logits函数

 该函数是tensorflow中一个常用的用于计算损失函数的方法。先来看官方解释:https://tensorflow.google.cn/api_docs/python/tf/nn/softmax_cross_entropy_with_logits?

这个式子其实是将softmax和交叉熵的计算分装到了一起,进一步提高了运算效率。需要注意的有以下几点:

      1、该函数的输入参数必须带着等式说明进行输入,如只能用logits = logits,而不能只写logits;

      2、输入的参数类型没有限制,labels可以是int型,也可以是float型;

      3、labels与logits的形状大小必须一致,且labels必须是one-hot类型的;

      4、可以处理每个图片同时有两个或者多个正确分类的情况,但是,labels必须服从一个概率分布。比如,假设有5个类别,其中这张图片可以分成第一类或者第三类都是正确的,则labels此时对应的向量就可以是[0.5,0,0.5,0,0],分成第一、第三类的概率相等,整体之和为1,服从概率分布。

      5、反向传播过程只针对logits进行更新,对标签labels不影响。

      6、返回值的类型type与logits一致,形状shape与labels一致。

现在,有一个新的版本 tf.nn.softmax_cross_entropy_with_logits_V2 函数,该函数与上面的函数大体相同,区别就在于这个新版的函数在反向传播时,是对logits和labels都进行更新;若想阻止其对labels进行更新,则在使用这个函数之前,将labels张量通过tf.stop_gradient 函数即可。

三、tf.nn.sparse_softmax_cross_entropy_with_logits 函数

该函数也是tensorflow中一个常用的计算损失函数的方法,参见官方文档:https://tensorflow.google.cn/api_docs/python/tf/nn/sparse_softmax_cross_entropy_with_logits

这个函数也是将softmax和交叉熵的计算整合在了一起,与上面的另一个函数相似,但是,这个函数是为了进一步提高运算效率而单独提出来的。主要注意以下几点:

      1、该函数的输入参数必须带着等式说明进行输入,如只能用logits = logits,而不能只写logits;

      2、输入的参数类型有严格限制,logits必须为浮点型,labels必须为 int 型;

      3、labels的维度应该比logits的维度少一维,且labels不能是 one-hot 类型

      4、该函数只能处理每一个图片有且只有一个正确分类的情况,因此labels采用的是稀疏编码形式。也就是说,假设有5个类别,每张图片只能是其中的某一类,若是第3类,则labels就是 2 。labels的取值范围就是 [0, num_class)。

      5、反向传播过程仅对logits进行更新。

      6、返回值的类型type与logits一致,形状shape与labels一致。

       还有一点要注意的是,这三个函数返回的只是在每一个对应位置处计算得到的值组成的向量或者矩阵,并不是一个数值。所以要想计算得到交叉熵,还要用 tf.reduce_sum() 函数对返回的张量进行处理;若想得到损失值loss,则要用 tf.reduce_mean() 函数进行处理。

四、代码演示

import tensorflow as tf

logits = tf.constant([[[0.9,0.5],[4,10]],[[2,7],[3,0.9]]])
label = tf.constant([[0,1],[1,0]])                            # 不是one-hot
label_ = tf.constant([[[1,0],[0,1]],[[0,1],[1,0]]],dtype=tf.float32)           # one-hot类型

cc = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,labels=label)
ccc = tf.reduce_sum(cc)

soft_cross = tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=label_)
soft_cr = tf.reduce_sum(soft_cross)

soft = tf.nn.softmax(logits=logits,axis=-1)        # 使用公式拆成两部分计算
dd = -tf.reduce_sum(label_*tf.log(soft))

with tf.Session() as sess:
    a = sess.run(cc)
    print("sparse_softmax 返回值:\n",a)
    c = sess.run(ccc)
    print("sparse_softmax 交叉熵:",c)
    print("---------------------------")
    g = sess.run(soft_cross)
    print("softmax 返回值:\n",g)
    f = sess.run(soft_cr)
    print("softmax 交叉熵:",f)
    print("---------------------------")
    b = sess.run(soft)
    print("分开计算第一步softmax之后的值:\n",b)
    e = sess.run(dd)
    print("分开计算最终的交叉熵:",e)

最终输出结果如下所示:

sparse_softmax 返回值:
 [[0.5130153  0.00247565]
 [0.00671535 0.11551952]]
sparse_softmax 交叉熵: 0.63772583
---------------------------
softmax 返回值:
 [[0.5130153  0.00247565]
 [0.00671535 0.11551952]]
softmax 交叉熵: 0.63772583
---------------------------
分开计算第一步softmax之后的值:
 [[[0.59868765 0.40131232]
  [0.00247262 0.9975274 ]]

 [[0.00669285 0.9933072 ]
  [0.8909032  0.10909683]]]
分开计算最终的交叉熵: 0.6377258

可以发现,三种方式计算得到的交叉熵是一样的,进一步说明了那三个函数的内部原理就是拆分成了两部分。而且,注意到tensorflow中的两个函数的返回值矩阵也是一样的,进一步证实了两个函数功能是完全相同的,只是为了提高运算效率,单独抽出来了一个用于单类问题的计算函数。      

 

猜你喜欢

转载自blog.csdn.net/qq_37691909/article/details/88291672