這篇屬於經典的一圖賽千言。再多的文字也不如一張直觀的圖更通俗易懂。
如果你正在訓練一個二分類器,很有可能你正在使用的損失函數是二值交叉熵/對數(binary cross-entropy / log)。
你是否想過使用此損失函數到底意味著什麼?問題是,鑑於如今庫和框架的易用性,很容易讓人忽略所使用損失函數的真正含義。
動機我一直在尋找一個可以向學生展示的以清晰簡潔可視化的方式解釋二值交叉熵/對數損失背後概念的博客文章。但由於我實在找不到,只好自己承擔了編寫的任務:-)
一個簡單的分類問題讓我們從10個隨機點開始:
x = [-2.2, -1.4, -0.8, 0.2, 0.4, 0.8, 1.2, 2.2, 2.9, 4.6]
這是唯一的特徵:x
▲ 圖0:特徵
現在,讓我們為點分配一些顏色:紅色和綠色。這些是我們的標籤。
▲ 圖1:數據
因此,我們的分類問題非常簡單:給定特徵x,我們需要預測其標籤:紅或綠。
由於這是二分類,我們還可以提出以下問題:「該點是綠色嗎? 」,或者更好的問法,「 該點是綠色的概率是多少?」 理想情況下,綠點的概率為1.0(為綠色),而紅點的概率為0.0(為綠色)。
在此設置中,綠點屬於正類(是,它們是綠色),而紅點屬於負類(否,它們不是綠色)。
如果我們擬合模型來執行此分類,它將預測每個點是綠色的概率。假定我們了解點的顏色,我們如何評估預測概率的好壞?這就是損失函數的全部目的!對於錯誤的預測,它應該返回高值,對於良好的預測,它應該返回低值。
對於像我們的示例這樣的二分類,典型的損失函數是binary cross-entropy / log。
損失函數:二值交叉熵/對數(Binary Cross-Entropy / Log )損失如果您查看此損失函數,就會發現:
▲ 二值交叉熵/對數
其中y是標籤(綠色點為1 , 紅色點為0),p(y)是N個點為綠色的預測概率。
這個公式告訴你,對於每個綠點(y = 1),它都會將log(p(y))添加到損失中,即,它為綠色的對數概率。相反,它為每個紅點(y = 0)添加log(1-p(y)),即它為紅色的對數概率。看起來不難,但好像不大直觀……
此外,熵與這一切有什麼關係?我們為什麼首先要對數概率?這些是有意義的問題,我希望在下面的「 向我展示數學 」部分中回答。
但是,在介紹更多公式之前,讓我向你展示上述公式的直觀表示 ...
計算損失-可視化方式首先,讓我們根據它們的類(正或負)分開所有點,如下圖所示:
▲ 圖2:拆分數據!
現在,讓我們訓練一個Logistic回歸來對我們的點進行分類。擬合回歸是一個sigmoid曲線,代表對於任何給定的x,一個點是綠色的概率。看起來像這樣:
▲ 圖3:擬合Logistic回歸
那麼,對於屬於正類(綠色)的所有點,我們的分類器給出的預測概率是多少?看sigmoid曲線下對應點x坐標上的綠色條。
▲ 圖4:正確分類正類中的點的概率
OK,到目前為止還不錯!那負類的點又如何呢?請記住,sigmoid曲線下方的綠色條表示給定點為綠色的概率。那麼,給定點為紅色的概率是多少呢?當然是sigmoid曲線以上的紅色條啦 :-)
▲ 圖5:正確分類負類中的點的概率
放在一起,我們最終得到這樣的結果:
▲ 圖6:所有概率加在一起!
條形圖表示與每個點的對應真實類別相關的預測概率!
好的,我們有了預測的概率…是時候通過計算二值交叉熵/對數損失來評估它們了!
這些概率就是我們要的,因此,讓我們去掉x軸,將各個方條彼此相鄰:
▲ 圖7:所有點的概率
這樣,吊起來的方條不再有意義,所以讓我們重新定位一下:
▲ 圖8:所有點的概率—看起來好多了 :-)
由於我們正在嘗試計算損失,因此我們需要對錯誤的預測進行懲罰,對吧?如果實際的類的概率是1.0,我們需要它的損失是零。相反,如果概率低,比如0.01,我們需要它的損失是巨大的!
事實證明,對於這個目的,採用概率的(負)對數非常適合(由於0.0和1.0之間的值的對數為負,因此我們採用負對數以獲得損失的正值)。
實際上,我們為此使用對數的原因是由於交叉熵的定義,請查看下面的「 告訴我數學 」部分,以獲取更多詳細信息。
下面的圖給了我們一個清晰的展示 - 實際的類的預測概率越來越接近於零,則損失指數增長:
▲ 圖9:不同概率的對數丟失
很公平!讓我們取概率的(負)log -這些是每個點相應的損失。
最後,我們計算所有這些損失的平均值。
▲ 圖10:最後,損失!
瞧!我們已經成功地計算了這個玩具示例的二值交叉熵/對數損失。是0.3329!
如果你想仔細檢查我們得到的值,只需運行下面的代碼 :-)
from sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import log_lossimport numpy as np
x = np.array([-2.2, -1.4, -.8, .2, .4, .8, 1.2, 2.2, 2.9, 4.6])y = np.array([0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
logr = LogisticRegression(solver='lbfgs')logr.fit(x.reshape(-1, 1), y)
y_pred = logr.predict_proba(x.reshape(-1, 1))[:, 1].ravel()loss = log_loss(y, y_pred)
print('x = {}'.format(x))print('y = {}'.format(y))print('p(y) = {}'.format(np.round(y_pred, 2)))print('Log Loss / Cross Entropy = {:.4f}'.format(loss))告訴我數學(真的嗎?!)這篇文章並不傾向於從數學上解釋……但是對於一些的讀者,希望了解熵,對數在所有方面的作用,好, 我們開始吧:-)
分布讓我們從點的分布開始。y代表我們點的類別(我們有3個紅點和7個綠點),這是它的分布,我們稱其為q(y),如下所示:
▲ 圖11:q(y),我們的點的分布
熵(Entropy)熵是一個與給定的分布q(y)相關的不確定性的量度。
如果我們所有的點都是綠色的,這種分布的不確定性是什麼?零,對嗎?畢竟,毫無疑問,點的顏色:它總是綠色!因此,熵為零!
另一方面,如果我們確切知道該點的一半是綠色和另一半是紅色?那是最壞的情況,對吧?我們絕對不可能猜到一個點的顏色:它是完全隨機的!在這種情況下,熵由下面的公式給出(我們有兩個類(顏色)–紅色或綠色-因此為2):
▲ 一半一半分布的熵
對於介於兩者之間的所有其它情況,我們可以用以下公式計算分布的熵,例如q(y),其中C是類的數量:
▲ 熵
因此,如果我們知道隨機變量的真實分布,則可以計算其熵。但是,如果是這樣的話,為什麼還要訓練分類器呢?畢竟,我們知道真正的分布…
但是,如果我們不知道真實分布呢?我們可以嘗試用其他一些分布(例如p(y))來近似真實分布嗎?我們當然可以!:-)
交叉熵(Cross-Entropy)假設我們的點遵循這個其它分布p(y) 。但是,我們知道它們實際上來自真(未知)分布q(y) ,對吧?
如果我們這樣計算熵,我們實際上是在計算兩個分布之間的交叉熵:
▲ 交叉熵
如果我們奇蹟般地將p(y)與q(y)完美匹配,則交叉熵和熵的計算值也將匹配。
由於這可能永遠不會發生,因此交叉熵將比在真實分布上計算出的熵具有更大的值。
▲ 交叉熵減去熵
事實上,交叉熵和熵之間的差還有個名字……
KL散度(Kullback-Leibler Divergence)Kullback-Leibler Divergence,簡稱「 KL散度 」,是兩個分布之間差異的一種度量:
▲ KL散度
這意味著,p(y)越接近q(y) ,差異越少,因此交叉熵也越小。
因此,我們需要找到一個合適的p(y)……但是,這不就是我們的分類器應該做的嗎?確實如此!它尋找可能的最佳p(y),以最小化交叉熵的值。
損失函數在訓練過程中,分類器使用其訓練集中的N個點中的每一個來計算交叉熵損失,從而有效地擬合分布p(y)!由於每個點的概率為1 / N,因此交叉熵的計算公式為:
▲ 交叉熵 —— 點對點
還記得上面的圖6至圖10嗎?我們需要在與每個點的實際類相關的概率上計算交叉熵。這意味著對正類(y = 1)中的點使用綠色條,對負類(y = 0)中的點使用紅色的懸掛條,或者從數學角度看:
▲ 對應於圖10的數學表達式 :-)
最後一步是計算兩個正負類所有點的平均
▲ 二進位交叉熵 —— 在正負類上計算
最後,我們通過一點小處理,正類或負類中任何一點都可以用相同的公式:
▲ 二進位交叉熵 —— 通用公式
瞧!我們回到了二進位交叉熵/對數損失的原始公式 :-)
最後我真的希望這篇文章能夠為一個常被認為是理所當然的概念- 二值交叉熵作為損失函數的概念-提供新的思路。此外,我也希望它能向您展示一些機器學習和資訊理論如何聯繫在一起的。
來源:https://towardsdatascience.com/understanding-binary-cross-entropy-log-loss-a-visual-explanation-a3ac6025181a