【Pytorch實戰】鳶尾花多分類

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
複製代碼
相關文章
相關標籤/搜索