'''
softmax回歸從零開始實現
'''import torch
import torchvision
import numpy as np
import sys
import d2lzh_pytorch as d2l
'''獲取資料
'''batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
print(train_iter, test_iter)
'''初始化模型引數
引數選擇原因
每個樣本輸入的是長和寬(均為28),所以模型的輸入向量長度就是28*28=784
一共有十個影象類別,所以單層神經網路有10個輸出
因此softmax的權重跟偏差數分別為784*10 和 1*10
'''num_inputs = 784
num_output = 10
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_output)), dtype=torch.float)
b = torch.zeros(num_output, dtype=torch.float)
w.requires_grad_(requires_grad=true)
b.requires_grad_(requires_grad=true)
'''實現softma運算
tensor 對多維度操作
我們需要實現對其中的一行或者一列進行求和,並在結果中保留行(dim=0)or列(dim=1)這兩個維度(keepdim=true)
求和不影響原來的張量
x = torch.tensor([[1,2,3],[4,5,6]])
print(x.sum(dim=0, keepdim=true))
print(x)
tensor([[5, 7, 9]])
tensor([[1, 2, 3],
[4, 5, 6]])
'''def softmax(x):
x_exp = x.exp()
partition = x_exp.sum(dim=1, keepdim=true)
'''這個函式先對每個元素進行指數運算(exp),
然後對exp矩陣同行元素進行求和,
最後領矩陣每行各元素與該行元素之和相除
得到矩陣每行元素和為1,即每行代表了該樣本在不用類目下的**概率
:param x:
:return: 返回的矩陣是乙個**矩陣,任何乙個元素代表乙個樣本在格式輸出類別的**概率
'''return x_exp / partition
'''定義模型
'''def net(x):
return softmax(torch.mm(x.view((-1, num_inputs)),w)+b)
'''定義損失函式
softmax回歸使用交叉熵損失函式,為了得到標籤的**概率使用gather函式
torch.gather(input, dim, index, out=none)
維度dim按照索引列表index從input中選取指定元素
y_hat = torch.tensor([[0.1, 0.3, 0.6],[0.3, 0.2, 0.5]])
print(y_hat)
y = torch.longtensor([0, 2])
print(y_hat.gather(1, y.view(-1, 1)))
tensor([[0.1000, 0.3000, 0.6000],
[0.3000, 0.2000, 0.5000]])
tensor([[0.1000],
[0.5000]])
gather函式會按照index的torch的形狀進行選取input裡面的元素
dim=1 則按照行進行選擇
即本例子選擇的是第一行的第乙個(索引為0的元素),第二行的第三個(索引為2的元素)
y_hat = torch.tensor([[0.1, 0.3, 0.6],[0.3, 0.2, 0.5]])
y = torch.longtensor([[0, 0, 1],[1, 0, 1]])
print(y_hat.gather(0, y))
tensor([[0.1000, 0.3000, 0.6000],
[0.3000, 0.2000, 0.5000]])
tensor([[0.1000, 0.3000, 0.5000],
[0.3000, 0.3000, 0.5000]])
dim為0的 按列進行選擇
所以得到的結果應該是
第一列的第乙個 第二列的第乙個 第三列的第二個
第一列的第二個 第二列的第乙個 第三列的第二個
# 使用小技巧 y.view(-1, 1) 會將y轉換成總長度除以1得到的行數,1為列的張量
# 舉例說明
# y = torch.arange(15)
# y.view(5,3)
# y.view(-1,3)
# y.view(5,-1)
# 以上三個都是一樣的效果
'''def cross_entropy(y_hat, y):
return - torch.log(y_hat.gather(1,y.view(-1,1)))
'''計算分類準確率 (分類**正確的數量佔總**數量的比)
使用y_hat.argmax(dim=1)函式 返回的是矩陣y_hat每行最大的索引,
且返回結果的形狀跟y_hat形狀一樣
'''def accuracy(y_hat, y):
''':param y_hat: **值
:param y: 真實值
:return:
'''return (y_hat.argmax(dim=1) == y).float().mean().item()
'''0.5
通例子可以看出來
**值中第一行**值為0.6 索引為 2
實際值中正確值為0.1 索引為0
**值中第一行**值為0.5 索引為 2
實際值中正確值為0.5 索引為2
'''def evaluate_accuracy(data_iter, net):
acc_sum, n = 0.0, 0
for x, y in data_iter:
acc_sum += (net(x).argmax(dim=1) == y).float().sum().item()
n += y.shape[0]
return acc_sum/n
print(evaluate_accuracy(test_iter, net))
'''訓練模型
使用小批量隨機梯度下降來優化模型的損失函式
'''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(f'epoch , loss , train acc , test acc ')
num_epochs, lr = 5, 0.1
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [w, b], lr)
多分類學習
多分類學習的基本思路是拆解法,即將多個二分類任務拆為若干個二分類任務求解。具體地就是,先對問題進行拆分,然後為每個拆分的二分類任務訓練乙個分類器 在測試時,對這些分類器的 結果進行整合以獲得最終的多分類結果。關鍵 多分類任務如何拆分。經典的為 一對一 one vs one,ovo 一對多 one v...
softmax的多分類
from 我們常見的邏輯回歸 svm等常用於解決二分類問題,對於多分類問題,比如識別手寫數字,它就需要10個分類,同樣也可以用邏輯回歸或svm,只是需要多個二分類來組成多分類,但這裡討論另外一種方式來解決多分類 softmax。softmax的函式為 p i exp tix kk 1exp tkx ...
softmax的多分類
我們常見的邏輯回歸 svm等常用於解決二分類問題,對於多分類問題,比如識別手寫數字,它就需要10個分類,同樣也可以用邏輯回歸或svm,只是需要多個二分類來組成多分類,但這裡討論另外一種方式來解決多分類 softmax。softmax的函式為 p i dfrac exp theta k tx 可以看到...