在前文斯坦福CS231n assignment1:SVM圖像分類原理及實(shí)現(xiàn)中我們講解了利用SVM模型進(jìn)行圖像分類的方法秃殉,本文我們講解圖像分類的另一種實(shí)現(xiàn)免绿,利用softmax進(jìn)行圖像分類。
softmax和svm模型網(wǎng)絡(luò)結(jié)構(gòu)很相似零渐,區(qū)別在于softmax會(huì)對(duì)svm的輸出分量進(jìn)行歸一化處理窒舟,使得每一個(gè)輸出分量變成一個(gè)概率值,所有輸出分量的概率之和為1诵盼。
同時(shí)損失函數(shù)也發(fā)生了變化辜纲,svm的損失函數(shù)折葉損失(hinge loss)是針對(duì)樣本的標(biāo)記類別之外的其他類別進(jìn)行損失計(jì)算的,也就是說標(biāo)記類別不計(jì)入損失拦耐,其他類別計(jì)算損失并累加作為某個(gè)樣本的損失。而softmax的損失函數(shù)交叉熵?fù)p失(cross-entropy loss)只跟某個(gè)樣本的標(biāo)記類別相關(guān)见剩,根據(jù)該標(biāo)記類別的概率計(jì)算損失值杀糯,而不考慮標(biāo)記類別之外的其他類別。
svm得出的每個(gè)輸出節(jié)點(diǎn)的得分苍苞,比如[98, 33, 15]是無標(biāo)定的固翰,也就是只是一個(gè)相對(duì)的大小,難以進(jìn)行直觀的解釋羹呵。而softmax可以解釋為實(shí)例被劃分為某個(gè)類別的可能性骂际,或者概率。
下面是softmax的損失函數(shù):
也可以等價(jià)成:
加入正則化損失項(xiàng)后冈欢,批處理過程中N個(gè)樣本的平均損失變成:
這里我們使用L2正則化損失:
在此基礎(chǔ)上我們來推導(dǎo)損失函數(shù)L對(duì)權(quán)重Wij的偏導(dǎo)數(shù)歉铝,推導(dǎo)過程如下:
在這個(gè)推導(dǎo)過程中需要注意的是,直接跟標(biāo)記類對(duì)應(yīng)的輸出節(jié)點(diǎn)相連的權(quán)重和不跟標(biāo)記類節(jié)點(diǎn)相連的權(quán)重的偏導(dǎo)數(shù)格式是不一樣的凑耻,對(duì)應(yīng)于推導(dǎo)過程中的if/else判別太示。
對(duì)應(yīng)的代碼如下:
def softmax_loss_naive(W, X, y, reg):
"""
:param X: 200 X 3073
:param Y: 200
:param W: 3073 X 10
:return: reg: 正則化損失系數(shù)(無法通過拍腦袋設(shè)定,需要多試幾個(gè)值香浩,然后找個(gè)最優(yōu)的)
"""
dW = np.zeros(W.shape) # initialize the gradient as zero
# compute the loss and the gradient
num_classes = W.shape[1]
num_train = X.shape[0]
loss = 0.0
for k in xrange(num_train):
origin_scors = X[k].dot(W)
probabilities = np.zeros(origin_scors.shape)
logc = -np.max(origin_scors)
total_sum = np.sum(np.exp(origin_scors - logc))
for i in xrange(num_classes):
probabilities[i] = np.exp(origin_scors[i] - logc) / total_sum
for i in xrange(num_classes):
if i == y[k]:
dW[:, i] += - X[k] * (1 - probabilities[i]) # dW[:, i]:3073X1 X[k]: 3073 X 1
else:
dW[:, i] += X[k] * probabilities[i]
loss += -np.log(probabilities[y[k]])
# Right now the loss is a sum over all training examples, but we want it
# to be an average instead so we divide by num_train.
loss /= num_train
dW /= num_train
dW += reg*W # regularize the weights
# Add regularization to the loss.
loss += 0.5 * reg * np.sum(W * W)
return loss, dW