多層感知器(Multilayer perceptron, MLP)的一層,可以表示為 = f(xTW + b),其中的 x 為輸入向量,W 為權重矩陣,b 為偏差向量,f 為 activation function, 為輸出向量。並且由於堆疊多層時,每一層的每個輸出都是完全連接到下一層的每個輸入,所以這樣的每一層又叫做全連接層(fully connected layer)。多層感知器或者其他各種類神經網路的訓練,則首先需要使用損失函數(loss function)評估網路算出來的 和標準答案 y 之間的差異,透過你所選用的工具(例如 PyTorch 或者 TensorFlow)進行反向傳播求出梯度以後,再使用優化器(optimizer)來更新每個 W 和 b。如此反覆進行之後,通常就可以訓練出恰當的類神經網路。

對於 activation function、損失函數以及最佳化方法,可以依照你要處理的問題特性,或者實際效果來選擇。常用的 activation function 有 sigmoid、ReLU、tanh,損失函數則有常用於回歸問題的 mean squared error (MSE),以及常用於分類問題的 cross entropy 等可以選擇。最佳化方法則通常有 SGD (stochastic gradient descent)、Momentum、AdaGrad、RMSProp,以及 Adam 等方式,若無特殊需求,且在可以選擇的情況下,通常你可以先試試看 Adam。

若要使用 MLP 解決問題,有很多工具可以幫忙,常見或曾經常見的有 PyTorchTensorFlow,以及 Chainer 等等,不過這些工具為了能讓你做更自由的調整,所以在真正的類神經網路本身和資料的事前處理,都有許多工作要自己做,因此以下先使用 scikit-learn 的 neural_network.MLPClassifier 來示範 MLP 的使用,範例的資料集是 Wine Data Set

import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier

dataset = load_wine()
print('Data shapes:', dataset.data.shape, dataset.target.shape)

X_train, X_test, y_train, y_test = train_test_split(dataset.data, dataset.target)
print('Training data shapes:', X_train.shape, y_train.shape)
print('Test data shapes:', X_test.shape, y_test.shape)

model = MLPClassifier(hidden_layer_sizes=(256, 256))
model.fit(X_train, y_train)
pred = model.predict(X_test)
print('Accuracy: {:.2f}%'.format(100*np.mean(pred == y_test)))

hidden = np.maximum(X_test @ model.coefs_[0] + model.intercepts_[0], 0)
hidden = np.maximum(hidden @ model.coefs_[1] + model.intercepts_[1], 0)
pred = np.argmax(hidden @ model.coefs_[2] + model.intercepts_[2], axis=1)

print('Accuracy: {:.2f}%'.format(100*np.mean(pred == y_test)))

在上述範例中,

如果你對超參數或特徵等方面的選擇不太有想法,或者想要在二維平面上,看看不同超參數在不同資料上的視覺化效果,可以前往 TensorFlow Playground 網站嘗試。

如前所述,若使用 PyTorch 等工具來訓練類神經網路,則為了能讓你做更自由的調整,有許多超參數都需要一一明確指定,以下是把前一個範的預測工作,改用 PyTorch 來進行:

import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

dataset = load_wine()
print('Data shapes:', dataset.data.shape, dataset.target.shape)

X_train, X_test, y_train, y_test = train_test_split(dataset.data, dataset.target)
print('Training data shapes:', X_train.shape, y_train.shape)
print('Test data shapes:', X_test.shape, y_test.shape)

X_train = torch.FloatTensor(X_train)
X_test = torch.FloatTensor(X_test)
y_train = torch.LongTensor(y_train)

train_loader = DataLoader(
	TensorDataset(X_train, y_train), batch_size=128, shuffle=True
)

model = nn.Sequential(
	nn.Linear(13, 256),
	nn.ReLU(),
	nn.Linear(256, 256),
	nn.ReLU(),
	nn.Linear(256, 3)
).to(device)
optim = torch.optim.Adam(model.parameters())
criterion = nn.CrossEntropyLoss()

model.train()
for _ in range(200):
	for X_batch, y_batch in train_loader:
		loss = criterion(model(X_batch.to(device)), y_batch.to(device))
		optim.zero_grad()
		loss.backward()
		optim.step()

model.eval()
pred = model(X_test.to(device)).argmax(dim=1).detach().cpu().numpy()
print('Accuracy: {:.2f}%'.format(100 * (pred == y_test).mean()))

在上述範例中,