寫在前面
以下是個人在學習過程中的記錄,如有侵權聯系刪除。
參考:
https://zhuanlan.zhihu.com/p/21102293?refer=intelligentunit
https://cs231n.github.io/linear-classify/
https://blog.csdn.net/SongGu1996/article/details/99056721
引
SVM將輸出作為每個分類的評分,svm分類時輸出每個分類的得分,這個分數不太好解釋
softmax中函數映射保持不變,但將這些評分值視為每個分類的未歸一化的對數概率
但是softmax的輸出值時歸一化的,可以用概率加以解釋,也就是每個分類的概率,越接近1的概率就越高
svm中損失是折葉損失,而softmax的是交叉熵損失
何為交叉熵
交叉熵:用於度量兩個概率分布間的差異性信息。交叉熵可在神經網絡(機器學習)中作為損失函數,
p表示真實標記的分布,q則為訓練后的模型的預測標記分布,交叉熵損失函數可以衡量p與q的相似性。
按照真實分布p來衡量
p(X) 是隨機變量X的分布, q(X) 是隨機變量的近似分布。兩者之間有差異
如果采用錯誤的分布q來表示來自真實分布p


softmax的交叉熵損失
等價於
相當於信息論交叉熵的一個個體
softmax函數
被稱作softmax 函數:其輸入值是一個向量,向量中元素為任意實數的評分值(
中的),
函數對其進行壓縮,輸出一個向量,其中每個元素值在0到1之間,且所有元素之和為1。 (也就是返回的也是一個向量?)
Softmax分類器所做的就是最小化在估計分類概率和“真實”分布之間的交叉熵
概率論解釋
可以解釋為是給定圖像數據,以
為參數,分配給正確分類標簽
的歸一化概率。
Softmax分類器將輸出向量中的評分值解釋為沒有歸一化的對數概率。
那么以這些數值做指數函數的冪就得到了沒有歸一化的概率,而除法操作則對數據進行了歸一化處理
由於上式是指數函數,所以會非常大,可能會產生溢出,所以一般會給分子分母乘以一個系數C
通過使用這個技巧可以提高計算中的數值穩定性。通常將設為
import numpy as np
f = np.array([123, 456, 789])
p = np.exp(f) / np.sum(np.exp(f))
# 如果單單這么計算,會產生數值爆炸
# 添加一個系數C, 根據本例f 得logC = - 789
f -= np.max(f) # f中每個元素減去中的最大值
p = np.exp(f) / np.sum(np.exp(f))
說明:softmax函數是一個歸一函數與交叉熵沒有任何關系,只是用於稱呼這個分類器
SVM同Softmax的比較
針對一個數據點,SVM和Softmax分類器的不同處理方式的例子。兩個分類器都計算了同樣的分值向量f(本節中是通過矩陣乘來實現)。不同之處在於對f中分值的解釋:SVM分類器將它們看做是分類評分,它的損失函數鼓勵正確的分類(本例中是藍色的類別2)的分值比其他分類的分值高出至少一個邊界值。Softmax分類器將這些數值看做是每個分類沒有歸一化的對數概率,鼓勵正確分類的歸一化的對數概率變高,其余的變低。SVM的最終的損失值是1.58,Softmax的最終的損失值是0.452,但要注意這兩個數值沒有可比性。只在給定同樣數據,在同樣的分類器的損失值計算中,它們才有意義。
Softmax分類器為每個分類提供了“可能性”:SVM的計算是無標定的,而且難以針對所有分類的評分值給出直觀解釋。Softmax分類器則不同,它允許我們計算出對於所有分類標簽的可能性。舉個例子,針對給出的圖像,SVM分類器可能給你的是一個[12.5, 0.6, -23.0]對應分類“貓”,“狗”,“船”。而softmax分類器可以計算出這三個標簽的”可能性“是[0.9, 0.09, 0.01],這就讓你能看出對於不同分類准確性的把握。為什么我們要在”可能性“上面打引號呢?這是因為可能性分布的集中或離散程度是由正則化參數λ直接決定的,λ是你能直接控制的一個輸入參數。舉個例子,假設3個分類的原始分數是[1, -2, 0],那么softmax函數就會計算:
現在,如果正則化參數λ更大,那么權重W就會被懲罰的更多,然后他的權重數值就會更小。這樣算出來的分數也會更小,假設小了一半吧[0.5, -1, 0],那么softmax函數的計算就是:
現在看起來,概率的分布就更加分散了。還有,隨着正則化參數λ不斷增強,權重數值會越來越小,最后輸出的概率會接近於均勻分布。這就是說,softmax分類器算出來的概率最好是看成一種對於分類正確性的自信。和SVM一樣,數字間相互比較得出的大小順序是可以解釋的,但其絕對值則難以直觀解釋。
在實際使用中,SVM和Softmax經常是相似的:通常說來,兩種分類器的表現差別很小,不同的人對於哪個分類器更好有不同的看法。相對於Softmax分類器,SVM更加“局部目標化(local objective)”,這既可以看做是一個特性,也可以看做是一個劣勢。考慮一個評分是[10, -2, 3]的數據,其中第一個分類是正確的。那么一個SVM()會看到正確分類相較於不正確分類,已經得到了比邊界值還要高的分數,它就會認為損失值是0。SVM對於數字個體的細節是不關心的:如果分數是[10, -100, -100]或者[10, 9, 9],對於SVM來說沒設么不同,只要滿足超過邊界值等於1,那么損失值就等於0。
對於softmax分類器,情況則不同。對於[10, 9, 9]來說,計算出的損失值就遠遠高於[10, -100, -100]的。換句話來說,softmax分類器對於分數是永遠不會滿意的:正確分類總能得到更高的可能性,錯誤分類總能得到更低的可能性,損失值總是能夠更小。但是,SVM只要邊界值被滿足了就滿意了,不會超過限制去細微地操作具體分數。這可以被看做是SVM的一種特性。舉例說來,一個汽車的分類器應該把他的大量精力放在如何分辨小轎車和大卡車上,而不應該糾結於如何與青蛙進行區分,因為區分青蛙得到的評分已經足夠低了。
代碼實現
from builtins import range
import numpy as np
from random import shuffle
from past.builtins import xrange
def softmax_loss_naive(W, X, y, reg):
"""
Softmax loss function, naive implementation (with loops)
Inputs have dimension D, there are C classes, and we operate on minibatches
of N examples.
Inputs:
- W: A numpy array of shape (D, C) containing weights.
- X: A numpy array of shape (N, D) containing a minibatch of data.
- y: A numpy array of shape (N,) containing training labels; y[i] = c means
that X[i] has label c, where 0 <= c < C.
- reg: (float) regularization strength
Returns a tuple of:
- loss as single float
- gradient with respect to weights W; an array of same shape as W
"""
# Initialize the loss and gradient to zero.
loss = 0.0
dW = np.zeros_like(W)
#############################################################################
# TODO: Compute the softmax loss and its gradient using explicit loops. #
# Store the loss in loss and the gradient in dW. If you are not careful #
# here, it is easy to run into numeric instability. Don't forget the #
# regularization! #
#############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
for i in range(X.shape[0]):
scores = X[i].dot(W)
scores -= np.max(scores)
p = np.exp(scores) / np.sum(np.exp(scores))
for j in range(W.shape[1]):
if j == y[i]:
dW[:, j] += (p[j] - 1) * X[i]
else:
dW[:, j] += p[j] * X[i]
loss += -np.log(p[y[i]])
loss /= X.shape[0]
loss += reg * np.sum(W ** 2)
dW /= X.shape[0]
dW += 2.0 * reg * W
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss, dW
def softmax_loss_vectorized(W, X, y, reg):
"""
Softmax loss function, vectorized version.
Inputs and outputs are the same as softmax_loss_naive.
"""
# Initialize the loss and gradient to zero.
loss = 0.0
dW = np.zeros_like(W)
#############################################################################
# TODO: Compute the softmax loss and its gradient using no explicit loops. #
# Store the loss in loss and the gradient in dW. If you are not careful #
# here, it is easy to run into numeric instability. Don't forget the #
# regularization! #
#############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
scores = X.dot(W)
scores -= np.max(scores, axis=1, keepdims=True)
p = np.exp(scores) / np.sum(np.exp(scores), axis=1, keepdims=True)
loss = np.sum(-np.log(p[np.arange(X.shape[0]), y])) / X.shape[0]
p[np.arange(X.shape[0]), y] = p[np.arange(X.shape[0]), y] - 1
dW = np.dot(X.T, p)
loss += reg * np.sum(W ** 2)
dW = dW / X.shape[0] + 2.0 * reg * W
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss, dW