除了單變數及多變數的連續浮點運算問題以外,反饋類神經網路也可以運用在機器學習 (Machine Learning) 中的非線性分類問題上面;有關機器學習的題目,Python 其實有相當多的資源可以用來作為範例。首先,我們先安裝在「scikit-learn」這個經常使用程式庫工具。
pip install scikit-learn
我們可以在「scikit-learn」這個程式庫中使用「make_circles()」這個函數來建立一個二元分類的問題。在這個函數產生會產生多組座標的資料形成二個圓形,作為二元分類的例子;其中外圓形的資料會標記為「0」,而內圓形的資料則被標記為「1」。內圈資料與外圈資距離中心距離可以使用參數「factor」來指定;而資料的亂數散佈則使用參數「noise」來指定。資料產生之後,再使用「train_test_split()」函數將訓練資料及測試資料依照 「factor」指 的比例來作亂數分割。以下圖來說,藍色的點代表外圓形的訓練資料,綠色的點為外圓形的測試資料;紅色點代表內圓形的訓練資料,褐色點代表內圓形的測試資料。
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import matplotlib.colors as Color
noData = 1000
x, label = make_circles(noData,noise=0.05,factor=0.6, random_state=13)
x_train, x_test, y_train, y_test = train_test_split(x,label,test_size=0.2,random_state=13)
colorTrain=Color.ListedColormap(['blue','red'])
colorTest=Color.ListedColormap(['green','brown'])
plt.scatter(x_train[:,0],x_train[:,1],c=y_train,cmap=colorTrain)
plt.scatter(x_test[:,0],x_test[:,1],c=y_test,cmap=colorTest)
plt.grid()
plt.show()
將「train_test_split()」的訓練資料轉換成 PyTorch/CUDA 使用的 tensor 資料型態。
import torch
X_train = torch.from_numpy(x_train.astype('float32')).to(device)
Y_train = torch.from_numpy(y_train.astype('float32')).unsqueeze(dim=1).to(device)
在這裏仍然使用反饋類神經網路,並且創建一個 2 維度的類神經網路。
from torch import nn
device=torch.device('cpu')
if torch.cuda.is_available():
device=torch.device('cuda')
#------------
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_output)
self.active=nn.Sigmoid()
#--------
def forward(self,x):
x=self.active(self.layer1(x))
return self.layer2(x)
#-------------
torch.manual_seed(13)
neural=classNeural(2,5,1).to(device)
loss_fn=nn.MSELoss() # MSE
optimizer=torch.optim.AdamW(neural.parameters(),lr=0.01)
反饋類神經網路的訓練與連續數的模型訓練並沒有不同;不過在最輸出預測值來觀察訓練誤差時,則加上「numpy.round()」函數,將類神經網路輸出的連續浮點數,轉換成「0」、「1」的二元分類數值。
mae_y,mae_x=[],[]
for epoche in range(1500):
neural.train()
Y_pred=neural(X_train)
loss=loss_fn(Y_pred,Y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoche % 50 ==0:
neural.eval()
with torch.inference_mode():
Y_pred=neural(X_train)
y_pred=np.round(Y_pred.squeeze(dim=1).to('cpu').numpy())
mae_y.append(np.mean(np.abs(y_train-y_pred)))
mae_x.append(epoche)
#---------------
plt.plot(mae_x,mae_y,'b--')
plt.grid()
plt.ylabel('Mean Absolute Error')
plt.show()
最後可以將訓練資料及測試資料輪入訓練好的類神經網路。在訓練的部份,藍色圓代表外圓的訓練資料,黃色「X」代表預測外圓的結果;紅色圓代表內圓的訓練資料,黑色「X」代表預測內圓的結果。
neural.eval()
with torch.inference_mode():
Y_pred=neural(X_train)
y_pred=np.round(Y_pred.squeeze(dim=1).to('cpu').numpy())
#---------------
colorPred=Color.ListedColormap(['yellow','black'])
plt.title('Training')
plt.scatter(x_train[:,0],x_train[:,1],c=y_train,cmap=colorTrain,marker='o')
plt.scatter(x_train[:,0],x_train[:,1],c=y_pred,cmap=colorPred,marker='x',s=12)
plt.grid()
plt.show()
在測試的部份,藍色圓代表外圓的測試資料,這些資料並沒有參與到訓練的階段,但是類神經網路還是能來預測外圓的結果,而顯示在以黃色「X」的位置;同樣地,紅色圓代表內圓的測試資料,黑色「X」代表預測內圓的結果;可以看到以這個二元分類的問題來說,反饋類神經網路可以獲得相當完美的結果。
neural.eval()
X_test=torch.from_numpy(x_test.astype('float32')).to(device)
with torch.inference_mode():
Y_pred=neural(X_test)
y_pred=np.round(Y_pred.squeeze(dim=1).to('cpu').numpy())
#--------------
mae=np.mean(np.abs(y_test-y_pred))
plt.title('Testing')
plt.scatter(x_test[:,0],x_test[:,1],c=y_test,cmap=colorTrain,marker='o')
plt.scatter(x_test[:,0],x_test[:,1],c=y_pred,cmap=colorPred,marker='x',s=12)
plt.grid()
plt.show()