1、【問題概述】bash
本節的目的在於嘗試利用Pytorch簡單實現多分類,並無過多的在乎訓練效果哈!網絡
利用鳶尾花數據集作多分類,一共分爲3類。將數據打亂後,選取80/150個做爲訓練集,剩餘做爲測試集。利用簡單的三層神經網絡,Relu做爲激活函數。dom
訓練過程,輸入爲80*4:函數
1)第一層神經網絡有20個神經元,w[1]維度爲4 * 20,第一層輸出爲80 * 20;測試
2)第2層神經網絡有30個神經元,w[2]維度爲20 * 30,第2層輸出爲80 * 30;優化
3)第三層神經網絡有3個神經元,w[3]維度爲30 * 3,第3層輸出爲80 * 3;ui
每一個樣本對應一個1 * 3的輸出,損失函數選擇nn.CrossEntropyLoss(),這裏的交叉熵是nn.logSoftmax()和nn.NLLLoss()的整合,通過損失函數的處理,獲得80 * 1的預測結果。spa
2、【知識點整理】code
1.在mynet網絡初始化的時候,定義一個變量用於定義網絡,簡單方式:對象
self.fc=nn.nn.Sequential(
nn.Linear(4,20),
nn.ReLU(),
nn.Linear(20,30),
nn.ReLU(),
nn.Linear(30,3) )
複製代碼
2.定義損失函數,本例選用nn.CrossEntropyLoss(),針對單目標分類問題, 結合了 nn.LogSoftmax() 和 nn.NLLLoss() 來計算 loss。
input=torch.rand(4,3)
so1=nn.Softmax(dim=1)#先softmax
input2=torch.log(so1(input))#再取log
target=torch.LongTensor([0,1,0,2])#設置labels
#nn.NLLLoss就是根據label取每一個樣本logsoftmax計算結果中相應位置值取負,相加求平均
print(-(input2[0][0]+input2[1][1]+input2[2][0]+input2[3][2])/4)#weight爲空時,手動實現NLLLoss
#調用nn.NLLLoss驗證
loss = nn.NLLLoss()
output = loss(input2, target)
print('output:',output)
結果:
tensor(0.9664)
output: tensor(0.9664)
複製代碼
若是採用了mse等其餘損失函數,須要注意保證output、labels與損失函數要求的輸入一致。
3.使用DataLoader迭代器
方便咱們訪問Dataset裏的對象,值得注意的num_workers的參數設置:若是放在cpu上跑,能夠無論,可是放在GPU上則須要設置爲0;或者在DataLoader操做以後將Tensor放在GPU上,以最後一種方式放在gpu上代碼以下:
train_dataset = Data.TensorDataset(torch.from_numpy(train).float(),
torch.from_numpy(train_label).long())#數據集
#每次迭代取10個樣本,而且打亂順序。假設有80個數據,每次10個,就會取8次,取遍全部數據。
train_loader = Data.DataLoader(dataset=train_dataset,
batch_size=10,shuffle=True)
#for和enumerate用來訪問可遍歷對象,即train_loader,經常配合使用
for i, (x,y) in enumerate(train_loader):
print('i:', i)
if torch.cuda.is_available():#數據放在gpu上
x = x.cuda()
y = y.cuda()
複製代碼
4.定義正向傳播函數
def forward(self,inputs):
outputs=self.fc(inputs)
return outputs
複製代碼
5.定義梯度降低優化器:
#選取優化器
self.optim=torch.optim.Adam(params=self.parameters(),lr=0.1)
#在每次train中,根據前向傳播計算loss,再利用loss進行梯度計算與參數更新
def train():
....
loss=self.mse(out,label) #根據正向傳播計算損失
self.optim.zero_grad()#優化器梯度清零
loss.backward()#反向傳播,計算梯度
self.optim.step()#應用梯度,更新參數
複製代碼
3、【源代碼】
利用sklearn中自帶的數據集鳶尾花做爲原始數據。看代碼:
import torch.nn as nn
import torch
import torch.utils.data as Data
def getdata():
from sklearn.datasets import load_iris
import pandas as pd
import numpy as np
train_data=load_iris()
data=train_data['data']
labels=train_data['target'].reshape(-1,1)
total_data=np.hstack((data,labels))
np.random.shuffle(total_data)
train=total_data[0:80,:-1]
test=total_data[80:,:-1]
train_label=total_data[0:80,-1].reshape(-1,1)
test_label=total_data[80:,-1].reshape(-1,1)
return data,labels,train,test,train_label,test_label
#網絡類
class mynet(nn.Module):
def __init__(self):
super(mynet,self).__init__()
self.fc=nn.Sequential( #添加神經元以及激活函數
nn.Linear(4,20),
nn.ReLU(),
nn.Linear(20,30),
nn.ReLU(),
nn.Linear(30,3)
)
self.mse=nn.CrossEntropyLoss()
self.optim=torch.optim.Adam(params=self.parameters(),lr=0.1)
def forward(self,inputs):
outputs=self.fc(inputs)
return outputs
def train(self,x,label):
out=self.forward(x) #正向傳播
loss=self.mse(out,label) #根據正向傳播計算損失
self.optim.zero_grad()#梯度清零
loss.backward()#計算梯度
self.optim.step()#應用梯度更新參數
def test(self,test_):
return self.fc(test_)
if __name__=='__main__' :
data,labels,train,test,train_label,test_label=getdata()
mynet=mynet()
train_dataset = Data.TensorDataset(torch.from_numpy(train).float(),torch.from_numpy(train_label).long())
BATCH_SIZE=10
train_loader = Data.DataLoader(dataset=train_dataset,batch_size=BATCH_SIZE,shuffle=True)
for epoch in range(100):
for step,(x,y) in enumerate(train_loader):
y=torch.reshape(y,[BATCH_SIZE])
mynet.train(x,y)
if epoch%20==0:
print('Epoch: ', epoch, '| Step: ', step, '| batch y: ', y.numpy())
out=mynet.test(torch.from_numpy(data).float())
prediction = torch.max(out, 1)[1]# 1返回index 0返回原值
pred_y = prediction.data.numpy()
test_y=labels.reshape(1,-1)
target_y =torch.from_numpy(test_y).long().data.numpy()
accuracy = float((pred_y == target_y).astype(int).sum()) / float(target_y.size)
print("鶯尾花預測準確率",accuracy)
複製代碼
結果:
Epoch: 0 | Step: 0 | batch y: [0 2 2 0 1 2 0 0 0 2]
Epoch: 0 | Step: 1 | batch y: [1 2 0 1 1 1 0 0 1 2]
Epoch: 0 | Step: 2 | batch y: [1 2 1 1 0 1 2 2 1 1]
Epoch: 0 | Step: 3 | batch y: [0 2 2 1 1 0 0 1 2 1]
Epoch: 0 | Step: 4 | batch y: [2 0 0 1 0 2 2 0 0 2]
Epoch: 0 | Step: 5 | batch y: [2 0 2 0 2 2 1 1 1 1]
Epoch: 0 | Step: 6 | batch y: [1 0 2 0 2 2 2 2 0 1]
Epoch: 0 | Step: 7 | batch y: [2 0 0 0 1 2 0 2 0 1]
Epoch: 20 | Step: 0 | batch y: [0 0 1 2 2 2 1 0 2 2]
Epoch: 20 | Step: 1 | batch y: [0 1 2 2 2 0 0 0 2 1]
Epoch: 20 | Step: 2 | batch y: [2 1 1 0 1 1 2 1 2 1]
Epoch: 20 | Step: 3 | batch y: [0 2 0 1 0 1 2 0 1 2]
Epoch: 20 | Step: 4 | batch y: [0 2 2 1 2 1 2 2 0 1]
Epoch: 20 | Step: 5 | batch y: [0 0 1 0 2 0 1 2 2 1]
Epoch: 20 | Step: 6 | batch y: [0 2 0 0 0 1 1 0 2 2]
Epoch: 20 | Step: 7 | batch y: [0 0 2 1 1 1 1 2 0 0]
Epoch: 40 | Step: 0 | batch y: [2 1 0 0 1 2 2 1 1 0]
Epoch: 40 | Step: 1 | batch y: [1 1 2 1 2 2 0 0 2 2]
Epoch: 40 | Step: 2 | batch y: [1 1 1 0 0 1 0 1 1 2]
Epoch: 40 | Step: 3 | batch y: [0 2 0 2 2 2 0 0 1 1]
Epoch: 40 | Step: 4 | batch y: [2 0 2 2 1 2 1 2 1 0]
Epoch: 40 | Step: 5 | batch y: [0 1 0 1 0 0 2 0 2 1]
Epoch: 40 | Step: 6 | batch y: [0 1 2 0 1 2 2 0 2 0]
Epoch: 40 | Step: 7 | batch y: [0 0 2 2 0 1 2 2 0 1]
Epoch: 60 | Step: 0 | batch y: [2 2 2 1 1 1 0 0 2 0]
Epoch: 60 | Step: 1 | batch y: [0 2 2 2 0 0 1 1 1 2]
Epoch: 60 | Step: 2 | batch y: [2 1 0 0 1 0 1 1 1 1]
Epoch: 60 | Step: 3 | batch y: [2 0 2 1 1 0 1 0 1 2]
Epoch: 60 | Step: 4 | batch y: [2 2 1 1 0 0 2 2 2 2]
Epoch: 60 | Step: 5 | batch y: [0 1 2 2 0 2 2 1 0 2]
Epoch: 60 | Step: 6 | batch y: [1 2 0 1 1 0 0 0 0 2]
Epoch: 60 | Step: 7 | batch y: [0 2 0 2 0 0 0 2 1 1]
Epoch: 80 | Step: 0 | batch y: [0 2 2 0 0 1 0 0 1 0]
Epoch: 80 | Step: 1 | batch y: [0 2 1 1 2 1 2 0 1 1]
Epoch: 80 | Step: 2 | batch y: [0 0 2 0 1 1 0 2 2 1]
Epoch: 80 | Step: 3 | batch y: [2 2 2 0 2 1 0 1 2 0]
Epoch: 80 | Step: 4 | batch y: [0 2 2 1 2 0 0 0 1 0]
Epoch: 80 | Step: 5 | batch y: [1 2 1 0 2 2 1 0 2 2]
Epoch: 80 | Step: 6 | batch y: [0 2 1 1 1 2 1 2 2 2]
Epoch: 80 | Step: 7 | batch y: [1 2 0 0 0 2 0 1 1 1]
鶯尾花預測準確率 0.9266666666666666
複製代碼