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

關於categorical cross entropy 和 binary cross entropy的比較,差別通常體如今不一樣的分類(二分類、多分類等)任務目標,能夠參考文章keras中兩種交叉熵損失函數的探討,其結合keras的API討論了二者的計算原理和應用原理。python

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

1、二分類交叉熵

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

原理介紹

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

       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))spa

綜合x>0和x<0的狀況,並防止溢出咱們使用以下公式,code

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]]

2、多分類交叉熵

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

原理介紹

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()連用。

相關文章
相關標籤/搜索