1. 基本概念
1.1 Softmax
Softmax回歸與線(xiàn)性回歸差別不大毡琉,對(duì)應(yīng)的是分類(lèi)問(wèn)題邦鲫,主要區(qū)別在于輸出層是否使用了softmax運(yùn)算符。為了方便各類(lèi)別輸出的不定范圍值域進(jìn)行比較妇多,并直接得到概率意義的輸出壳快,使用softmax函數(shù)將不確定范圍的輸出值非線(xiàn)性映射到0-1之間,對(duì)應(yīng)其分為該類(lèi)別的概率贞绵。
容易推導(dǎo)厉萝,softmax操作具有常數(shù)不變性,即榨崩,在計(jì)算softmax概率的時(shí)候谴垫,為了保證數(shù)值穩(wěn)定性(numerical stability),我們可以選擇給輸入項(xiàng)減去一個(gè)常數(shù)母蛛,比如x的每個(gè)元素都要減去一個(gè)x中的最大元素翩剪。當(dāng)輸入項(xiàng)很大的時(shí)候,如果不減這樣一個(gè)常數(shù)彩郊,取指數(shù)之后結(jié)果會(huì)變得非常大前弯,發(fā)生溢出的現(xiàn)象,導(dǎo)致結(jié)果出現(xiàn)inf秫逝。
問(wèn)題:為什么選擇softmax函數(shù)來(lái)壓縮輸出恕出?softmax和sigmoid函數(shù)有什么區(qū)別和聯(lián)系?
來(lái)自討論區(qū)凌云峰的回答:
相同點(diǎn)
- 都具有良好的數(shù)據(jù)壓縮能力是實(shí)數(shù)域R→[ 0 , 1 ]的映射函數(shù),可以將雜亂無(wú)序沒(méi)有實(shí)際含義的數(shù)字直接轉(zhuǎn)化為每個(gè)分類(lèi)的可能性概率违帆。
- 都具有非常漂亮的導(dǎo)數(shù)形式浙巫,便于反向傳播計(jì)算。
- 它們都是 soft version of max ,都可以將數(shù)據(jù)的差異明顯化的畴。
- 相同的渊抄,他們具有著不同的特點(diǎn),sigmoid函數(shù)可以看成softmax函數(shù)的特例丧裁,softmax函數(shù)也可以看作sigmoid函數(shù)的推廣护桦。
不同點(diǎn)
- sigmoid函數(shù)前提假設(shè)是樣本服從伯努利 (Bernoulli) 分布的假設(shè),而softmax則是基于多項(xiàng)式分布渣慕。首先證明多項(xiàng)分布屬于指數(shù)分布族嘶炭,這樣就可以使用廣義線(xiàn)性模型來(lái)擬合這個(gè)多項(xiàng)分布,由廣義線(xiàn)性模型推導(dǎo)出的目標(biāo)函數(shù)即為Softmax回歸的分類(lèi)模型逊桦。
- sigmoid函數(shù)用于分辨每一種情況的可能性眨猎,所以用sigmoid函數(shù)實(shí)現(xiàn)多分類(lèi)問(wèn)題的時(shí)候,概率并不是歸一的强经,反映的是每個(gè)情況的發(fā)生概率睡陪,因此非互斥的問(wèn)題使用sigmoid函數(shù)可以獲得比較漂亮的結(jié)果;softmax函數(shù)最初的設(shè)計(jì)思路適用于首先數(shù)字識(shí)別這樣的互斥的多分類(lèi)問(wèn)題匿情,因此進(jìn)行了歸一化操作兰迫,使得最后預(yù)測(cè)的結(jié)果是唯一的。
1.2 損失函數(shù)
平方損失()
交叉熵(cross entropy)損失
在分類(lèi)任務(wù)中炬称,平方損失過(guò)于嚴(yán)格汁果,且不適用于多分類(lèi)任務(wù);交叉熵只關(guān)心正確分類(lèi)的預(yù)測(cè)概率玲躯,只要其值足夠大据德,就可以確保分類(lèi)結(jié)果正確。
2. 重要代碼
2.1 從零開(kāi)始實(shí)現(xiàn)
主要包括的步驟:
- 獲取訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)
- 定義模型參數(shù)
- 定義softmax操作
- 構(gòu)建softmax回歸模型
- 定義損失函數(shù)
- 定義準(zhǔn)確率
- 訓(xùn)練模型
- 模型預(yù)測(cè)
def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,
params=None, lr=None, optimizer=None):
for epoch in range(num_epochs):
train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
for X, y in train_iter:
y_hat = net(X)
l = loss(y_hat, y).sum()
# 梯度清零
if optimizer is not None:
optimizer.zero_grad()
elif params is not None and params[0].grad is not None:
for param in params:
param.grad.data.zero_()
l.backward()
if optimizer is None:
d2l.sgd(params, lr, batch_size)
else:
optimizer.step()
train_l_sum += l.item()
train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
n += y.shape[0]
test_acc = evaluate_accuracy(test_iter, net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
% (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [W, b], lr)