『TensorFlow』分類問題與兩種交叉熵


關於categorical cross entropy 和 binary cross entropy的比較,差異一般體現在不同的分類(二分類、多分類等)任務目標,可以參考文章keras中兩種交叉熵損失函數的探討,其結合keras的API討論了兩者的計算原理和應用原理。

本文主要是介紹TF中的接口調用方式。

一、二分類交叉熵

對應的是網絡輸出單個節點,這個節點將被sigmoid處理,使用閾值分類為0或者1的問題。此類問題logits和labels必須具有相同的type和shape

原理介紹

x = logits, z = labels.
logistic loss 計算式為: 其中交叉熵(cross entripy)基本函數式

       z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x))
    = z * -log(1 / (1 + exp(-x))) + (1 - z) * -log(exp(-x) / (1 + exp(-x)))
    = z * log(1 + exp(-x)) + (1 - z) * (-log(exp(-x)) + log(1 + exp(-x)))
    = z * log(1 + exp(-x)) + (1 - z) * (x + log(1 + exp(-x))
    = (1 - z) * x + log(1 + exp(-x))
    = x - x * z + log(1 + exp(-x))

對於x<0時,為了避免計算exp(-x)時溢出,我們使用以下這種形式表示

       x - x * z + log(1 + exp(-x))
    = log(exp(x)) - x * z + log(1 + exp(-x))
    = - x * z + log(1 + exp(x))

綜合x>0和x<0的情況,並防止溢出我們使用如下公式,

max(x, 0) - x *z + log(1 + exp(-abs(x)))

接口介紹

import numpy as np
import tensorflow as tf

input_data = tf.Variable(np.random.rand(1, 3), dtype=tf.float32)
# np.random.rand()傳入一個shape,返回一個在[0,1)區間符合均勻分布的array

output = tf.nn.sigmoid_cross_entropy_with_logits(logits=input_data, labels=[[1.0, 0.0, 0.0]])
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    print(sess.run(output))
    # [[ 0.5583781   1.06925142  1.08170223]]

二、多分類交叉熵

對應的是網絡輸出多個節點,每個節點表示1個class的得分,使用Softmax最終處理的分類問題。

原理介紹

cross_entropy = -tf.reduce_mean(y * tf.log(tf.clip_by_value(y_pre, 1e-10, 1.0))

調用一下:

import tensorflow as tf
 
input_data = tf.Variable([[0.2, 0.1, 0.9], [0.3, 0.4, 0.6]], dtype=tf.float32)
labels=tf.constant([[1,0,0], [0,1,0]], dtype=tf.float32)

cross_entropy = -tf.reduce_mean(labels * tf.log(tf.clip_by_value(input_data, 1e-10, 1.0)))
                                
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    print(sess.run(output))

接口介紹

softmax之后,計算輸出層全部節點各自的交叉熵(輸出向量而非標量)

cross_entropy_mean = tf.reduce_mean(
    tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=tf.argmax(labels,1), logits=logits), name='cross_entropy')
 
cross_entropy_mean = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(
        logits=logits, labels=labels), name='cross_entropy')

tf.nn.softmax_cross_entropy_with_logits()

函數的參數label是稀疏表示的,比如表示一個3分類的一個樣本的標簽,稀疏表示的形式為[0,0,1]這個表示這個樣本為第3個分類,而非稀疏表示就表示為2,同理[0,1,0]就表示樣本屬於第2個分類,而其非稀疏表示為1。

import tensorflow as tf
 
input_data = tf.Variable([[0.2, 0.1, 0.9], [0.3, 0.4, 0.6]], dtype=tf.float32)
output = tf.nn.softmax_cross_entropy_with_logits(logits=input_data, labels=[[1,0,0],
                                                                            [0,1,0]])
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    print(sess.run(output))

tf.nn.sparse_softmax_cross_entropy_with_logits()

此函數大致與tf.nn.softmax_cross_entropy_with_logits的計算方式相同,
適用於每個類別相互獨立且排斥的情況,一幅圖只能屬於一類,而不能同時包含一條狗和一只大象

但是在對於labels的處理上有不同之處,labels從shape來說此函數要求shape為[batch_size],
labels[i]是[0,num_classes)的一個索引, type為int32或int64,即labels限定了是一個一階tensor,
並且取值范圍只能在分類數之內,表示一個對象只能屬於一個類別

import tensorflow as tf

input_data = tf.Variable([[0.2, 0.1, 0.9], [0.3, 0.4, 0.6]], dtype=tf.float32)
output = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=input_data, labels=[0, 2])
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    print(sess.run(output))
# [ 1.36573195  0.93983102]

比tf.nn.softmax_cross_entropy_with_logits多了一步將labels稀疏化的操作。因為深度學習中,圖片一般是用非稀疏的標簽的,所以tf.nn.sparse_softmax_cross_entropy_with_logits()的頻率比tf.nn.softmax_cross_entropy_with_logits高。

不過兩者輸出尺寸等於輸入shape去掉最后一維(上面輸入[2*3],輸出[2]),所以均常和tf.reduce_mean()連用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM