除了二元分類問題以為,現實上其實還有相當多的多元分類的問題可以應用。在「scikit-learn」程式庫中也提供了一個相當著名的「鳶尾花分類問題」(Anderson's Iris data
set);它總共有 150 筆資訊,分別同時觀察花萼(sepal)和花瓣(petal)的長度
(length)和寬度(width)來進行加拿大加斯帕半島上的三種不同的鳶尾花的分類,分別是山鳶尾(setosa)、變色鳶尾(verscicolor)和維吉尼亞鳶尾(virginica)。
從「scikit-learn」程式集的「datasets」子程式庫,可以使用「load_iris()」函數取得鳶尾花的資料,然後簡單整理成「pandas.DataFrame」的格式如下。
from sklearn import datasets
iris=datasets.load_iris()
print(iris['DESCR'])日
#———————————————-
import pandas as pd
from sklearn.model_selection import train_test_split
iris_x=pd.DataFrame(iris['data'])
iris_x.columns=iris['feature_names']
# print(iris_x.to_string(index=False))
iris_y=pd.DataFrame(iris['target'])
iris_y.columns=['target names']
# print(iris_y.to_string(index=False))
data=pd.concat([iris_x,iris_y],axis=1)
print(data.to_string(index=False))
從整理好的資料來看,可以使用一個 4 個輸入 1 個輸出的類神經網路來建立模型;這個模型的輸出值,應該是「0」「1」「2」三個整數中的其中一個,這個輸出有三種分類結果,分別代表「山鳶尾」、「變色鳶尾」以及「virginica」;這種將分類輸出數值化的方法,是多元分類上常用的一種方式。
因此我們所創建的「類神經網路」類型也就跟之前的二元分類所使用的一致。
import torch
from torch import nn
#------------
class classNeural(nn.Module):
def __init__(self,n_input,n_hidden,n_output):
super().__init__()
self.n_input=n_input
self.n_hidden=n_hidden
self.n_output=n_output
#--------
self.layer1=nn.Linear(n_input,n_hidden)
self.layer2=nn.Linear(n_hidden,n_hidden)
self.layer3=nn.Linear(n_hidden,n_output)
self.active=nn.Sigmoid()
#--------
def forward(self,x):
x=self.active(self.layer1(x))
x=self.active(self.layer2(x))
return self.layer3(x)
#-------------
device=torch.device('cpu')
if(torch.cuda.is_available()):
device=torch.device('cuda')
torch.manual_seed(13)
irisNeural=classNeural(4,8,1).to(device)
loss_fn=nn.MSELoss() # MSE
optimizer=torch.optim.AdamW(irisNeural.parameters(),lr=0.01)
我們將全部的資料分為 80% 的訓練資料以及 20% 的測試資料,並且進行正規化;同時,為了在 PyTorch/CUDA 使用 GPU 來訓練類神經網路,我們將訓練資料及接下來要使用的測試資料,轉換成 GPU 上使用的 tensor 型態。
import numpy as np
x=data.iloc[:,0:4].values
label=data.iloc[:,4].values
x_train, x_test, y_train, y_test = train_test_split(x,label,test_size=0.2,random_state=13)
data_train=(x_train-np.mean(x))/(np.max(x)-np.min(x))
label_train=(y_train-np.mean(label))/(np.max(label)-np.min(label))
data_test=(x_test-np.mean(x))/(np.max(x)-np.min(x))
label_test=(y_test-np.mean(label))/(np.max(label)-np.min(label))
X_train=torch.tensor(data_train.astype('float32')).to(device)
Y_train=torch.tensor(label_train.astype('float32')).unsqueeze(dim=1).to(device)
X_test=torch.tensor(data_test.astype('float32')).to(device)
訓練的過程可以看到平均絕對誤差值會逐步收歛,之後就不再變化。分類模型訓練的結果,圓形表示訓練或測試的資料,而「X」形表示預測的結果。就四項特徵輸入預測的結果,120 筆訓練資料有 118 筆預測正確,正確率有 98%;30 筆測試資料有 28 筆預測正確,正確率有 93%。
# 訓練
irisNeural.train()
for epoche in range(1500):
Y_pred=irisNeural(X_train)
loss=loss_fn(Y_pred,Y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 預測
irisNeural.eval()
with torch.inference_mode():
Y_pred=irisNeural(X_train)
y_pred=Y_pred.squeeze(dim=1).to('cpu').numpy()
label_predTrain=np.round(y_pred*(np.max(label)-np.min(label))+np.mean(label)).astype('int')
# 測試
with torch.inference_mode():
Y_pred=irisNeural(X_test)
y_pred=Y_pred.squeeze(dim=1).to('cpu').numpy()
label_predTest=np.round(y_pred*(np.max(label)-np.min(label))+np.mean(label)).astype('int')