主要內(nèi)容
- 多層感知機(jī)的基本知識
- 使用多層感知機(jī)圖像分類的從零開始的實(shí)現(xiàn)
- 使用PyTorch的簡潔實(shí)現(xiàn)
多層感知機(jī)的基本知識
深度學(xué)習(xí)主要關(guān)注多層模型薛躬。在這里,我們將以多層感知機(jī)(multilayer perceptron呆细,MLP)為例型宝,介紹多層神經(jīng)網(wǎng)絡(luò)的概念八匠。
隱藏層
下圖展示了一個多層感知機(jī)的神經(jīng)網(wǎng)絡(luò)圖,它含有一個隱藏層趴酣,該層中有5個隱藏單元梨树。
表達(dá)公式
具體來說,給定一個小批量樣本岖寞,其批量大小為
抡四,輸入個數(shù)為
。假設(shè)多層感知機(jī)只有一個隱藏層仗谆,其中隱藏單元個數(shù)為
指巡。記隱藏層的輸出(也稱為隱藏層變量或隱藏變量)為
,有
隶垮。因?yàn)殡[藏層和輸出層均是全連接層藻雪,可以設(shè)隱藏層的權(quán)重參數(shù)和偏差參數(shù)分別為
和
狸吞,輸出層的權(quán)重和偏差參數(shù)分別為
和
。
我們先來看一種含單隱藏層的多層感知機(jī)的設(shè)計蹋偏。其輸出的計算為
也就是將隱藏層的輸出直接作為輸出層的輸入威始。如果將以上兩個式子聯(lián)立起來枢纠,可以得到
從聯(lián)立后的式子可以看出葫掉,雖然神經(jīng)網(wǎng)絡(luò)引入了隱藏層些举,卻依然等價于一個單層神經(jīng)網(wǎng)絡(luò):其中輸出層權(quán)重參數(shù)為,偏差參數(shù)為
。不難發(fā)現(xiàn)挪挤,即便再添加更多的隱藏層叼丑,以上設(shè)計依然只能與僅含輸出層的單層神經(jīng)網(wǎng)絡(luò)等價。
激活函數(shù)
上述問題的根源在于全連接層只是對數(shù)據(jù)做仿射變換(affine transformation)扛门,而多個仿射變換的疊加仍然是一個仿射變換鸠信。解決問題的一個方法是引入非線性變換,例如對隱藏變量使用按元素運(yùn)算的非線性函數(shù)進(jìn)行變換论寨,然后再作為下一個全連接層的輸入星立。這個非線性函數(shù)被稱為激活函數(shù)(activation function)爽茴。
下面我們介紹幾個常用的激活函數(shù):
ReLU函數(shù)
ReLU(rectified linear unit)函數(shù)提供了一個很簡單的非線性變換。給定元素绰垂,該函數(shù)定義為
可以看出室奏,ReLU函數(shù)只保留正數(shù)元素,并將負(fù)數(shù)元素清零劲装。為了直觀地觀察這一非線性變換胧沫,我們先定義一個繪圖函數(shù)xyplot。
Sigmoid函數(shù)
sigmoid函數(shù)可以將元素的值變換到0和1之間:
tanh函數(shù)
tanh(雙曲正切)函數(shù)可以將元素的值變換到-1和1之間:
我們接著繪制tanh函數(shù)占业。當(dāng)輸入接近0時绒怨,tanh函數(shù)接近線性變換。雖然該函數(shù)的形狀和sigmoid函數(shù)的形狀很像谦疾,但tanh函數(shù)在坐標(biāo)系的原點(diǎn)上對稱窖逗。
關(guān)于激活函數(shù)的選擇
ReLu函數(shù)是一個通用的激活函數(shù),目前在大多數(shù)情況下使用餐蔬。但是,ReLU函數(shù)只能在隱藏層中使用佑附。
用于分類器時樊诺,sigmoid函數(shù)及其組合通常效果更好。由于梯度消失問題音同,有時要避免使用sigmoid和tanh函數(shù)词爬。
在神經(jīng)網(wǎng)絡(luò)層數(shù)較多的時候,最好使用ReLu函數(shù)权均,ReLu函數(shù)比較簡單計算量少顿膨,而sigmoid和tanh函數(shù)計算量大很多。
在選擇激活函數(shù)的時候可以先選用ReLu函數(shù)如果效果不理想可以嘗試其他激活函數(shù)叽赊。
多層感知機(jī)
多層感知機(jī)就是含有至少一個隱藏層的由全連接層組成的神經(jīng)網(wǎng)絡(luò)恋沃,且每個隱藏層的輸出通過激活函數(shù)進(jìn)行變換。多層感知機(jī)的層數(shù)和各隱藏層中隱藏單元個數(shù)都是超參數(shù)必指。以單隱藏層為例并沿用本節(jié)之前定義的符號囊咏,多層感知機(jī)按以下方式計算輸出:
其中表示激活函數(shù)梅割。
多層感知機(jī)從零開始的實(shí)現(xiàn)
import torch
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l
print(torch.__version__)
# 獲取訓(xùn)練集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')
# 定義模型參數(shù)
num_inputs, num_outputs, num_hiddens = 784, 10, 256
W1 = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_hiddens)), dtype=torch.float)
b1 = torch.zeros(num_hiddens, dtype=torch.float)
W2 = torch.tensor(np.random.normal(0, 0.01, (num_hiddens, num_outputs)), dtype=torch.float)
b2 = torch.zeros(num_outputs, dtype=torch.float)
params = [W1, b1, W2, b2]
for param in params:
param.requires_grad_(requires_grad=True)
# 定義激活函數(shù)
def relu(X):
return torch.max(input=X, other=torch.tensor(0.0))
# 定義網(wǎng)絡(luò)
def net(X):
X = X.view((-1, num_inputs))
H = relu(torch.matmul(X, W1) + b1)
return torch.matmul(H, W2) + b2
# 定義損失函數(shù)
loss = torch.nn.CrossEntropyLoss()
# 訓(xùn)練
num_epochs, lr = 5, 100.0
# def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,
# params=None, lr=None, optimizer=None):
# for epoch in range(num_epochs):
# train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
# for X, y in train_iter:
# y_hat = net(X)
# l = loss(y_hat, y).sum()
#
# # 梯度清零
# if optimizer is not None:
# optimizer.zero_grad()
# elif params is not None and params[0].grad is not None:
# for param in params:
# param.grad.data.zero_()
#
# l.backward()
# if optimizer is None:
# d2l.sgd(params, lr, batch_size)
# else:
# optimizer.step() # “softmax回歸的簡潔實(shí)現(xiàn)”一節(jié)將用到
#
#
# train_l_sum += l.item()
# train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
# n += y.shape[0]
# test_acc = evaluate_accuracy(test_iter, net)
# print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
# % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
多層感知機(jī)PyTorch實(shí)現(xiàn)
import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l
print(torch.__version__)
# 初始化模型和各個參數(shù)
num_inputs, num_outputs, num_hiddens = 784, 10, 256
net = nn.Sequential(
d2l.FlattenLayer(),
nn.Linear(num_inputs, num_hiddens),
nn.ReLU(),
nn.Linear(num_hiddens, num_outputs),
)
for params in net.parameters():
init.normal_(params, mean=0, std=0.01)
# 訓(xùn)練
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')
loss = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)