多層感知器 (MLP) 的實現(xiàn)并不比簡單的線性模型復雜多少。關鍵的概念差異是我們現(xiàn)在連接多個層。
import torch from torch import nn from d2l import torch as d2l
from mxnet import np, npx from mxnet.gluon import nn from d2l import mxnet as d2l npx.set_np()
import jax from flax import linen as nn from jax import numpy as jnp from d2l import jax as d2l
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
import tensorflow as tf from d2l import tensorflow as d2l
5.2.1. 從零開始實施
讓我們從頭開始實現(xiàn)這樣一個網(wǎng)絡。
5.2.1.1. 初始化模型參數(shù)
回想一下,F(xiàn)ashion-MNIST 包含 10 個類,并且每個圖像由一個28×28=784灰度像素值網(wǎng)格。和以前一樣,我們暫時忽略像素之間的空間結(jié)構(gòu),因此我們可以將其視為具有 784 個輸入特征和 10 個類別的分類數(shù)據(jù)集。首先,我們將實現(xiàn)一個具有一個隱藏層和 256 個隱藏單元的 MLP。層數(shù)和寬度都是可調(diào)的(它們被認為是超參數(shù))。通常,我們選擇層寬度可以被 2 的較大次冪整除。由于內(nèi)存在硬件中分配和尋址的方式,這在計算上是高效的。
同樣,我們將用幾個張量表示我們的參數(shù)。請注意, 對于每一層,我們必須跟蹤一個權(quán)重矩陣和一個偏置向量。與往常一樣,我們?yōu)檫@些參數(shù)的損失梯度分配內(nèi)存。
在下面的代碼中,我們使用 `nn.Parameter< https://pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html >`__ 自動將類屬性注冊為要跟蹤的參數(shù)autograd(第 2.5 節(jié)) .
class MLPScratch(d2l.Classifier):
def __init__(self, num_inputs, num_outputs, num_hiddens, lr, sigma=0.01):
super().__init__()
self.save_hyperparameters()
self.W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens) * sigma)
self.b1 = nn.Parameter(torch.zeros(num_hiddens))
self.W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs) * sigma)
self.b2 = nn.Parameter(torch.zeros(num_outputs))
In the code below, we first define and initialize the parameters and then enable gradient tracking.
class MLPScratch(d2l.Classifier):
def __init__(self, num_inputs, num_outputs, num_hiddens, lr, sigma=0.01):
super().__init__()
self.save_hyperparameters()
self.W1 = np.random.randn(num_inputs, num_hiddens) * sigma
self.b1 = np.zeros(num_hiddens)
self.W2 = np.random.randn(num_hiddens, num_outputs) * sigma
self.b2 = np.zeros(num_outputs)
for param in self.get_scratch_params():
param.attach_grad()
In the code below we use `flax.linen.Module.param
class MLPScratch(d2l.Classifier):
num_inputs: int
num_outputs: int
num_hiddens: int
lr: float
sigma: float = 0.01
def setup(self):
self.W1 = self.param('W1', nn.initializers.normal(self.sigma),
(self.num_inputs, self.num_hiddens))
self.b1 = self.param('b1', nn.initializers.zeros, self.num_hiddens)
self.W2 = self.param('W2', nn.initializers.normal(self.sigma),
(self.num_hiddens, self.num_outputs))
self.b2 = self.param('b2', nn.initializers.zeros, self.num_outputs)
In the code below we use `tf.Variable
class MLPScratch(d2l.Classifier):
def __init__(self, num_inputs, num_outputs, num_hiddens, lr, sigma=0.01):
super().__init__()
self.save_hyperparameters()
self.W1 = tf.Variable(
tf.random.normal((num_inputs, num_hiddens)) * sigma)
self.b1 = tf.Variable(tf.zeros(num_hiddens))
self.W2 = tf.Variable(
tf.random.normal((num_hiddens, num_outputs)) * sigma)
self.b2 = tf.Variable(tf.zeros(num_outputs))
5.2.1.2. 模型
為了確保我們知道一切是如何工作的,我們將自己實現(xiàn) ReLU 激活,而不是直接調(diào)用內(nèi)置relu函數(shù)。
def relu(X): a = torch.zeros_like(X) return torch.max(X, a)
def relu(X): return np.maximum(X, 0)
def relu(X): return jnp.maximum(X, 0)
def relu(X): return tf.math.maximum(X, 0)
由于我們忽略了空間結(jié)構(gòu),我們將reshape每個二維圖像轉(zhuǎn)換為長度為 的平面向量num_inputs。最后,我們只用幾行代碼就實現(xiàn)了我們的模型。由于我們使用框架內(nèi)置的 autograd,這就是它所需要的全部。
@d2l.add_to_class(MLPScratch) def forward(self, X): X = X.reshape((-1, self.num_inputs)) H = relu(torch.matmul(X, self.W1) + self.b1) return torch.matmul(H, self.W2) + self.b2
@d2l.add_to_class(MLPScratch) def forward(self, X): X = X.reshape((-1, self.num_inputs)) H = relu(np.dot(X, self.W1) + self.b1) return np.dot(H, self.W2) + self.b2
@d2l.add_to_class(MLPScratch) def forward(self, X): X = X.reshape((-1, self.num_inputs)) H = relu(jnp.matmul(X, self.W1) + self.b1) return jnp.matmul(H, self.W2) + self.b2
@d2l.add_to_class(MLPScratch) def forward(self, X): X = tf.reshape(X, (-1, self.num_inputs)) H = relu(tf.matmul(X, self.W1) + self.b1) return tf.matmul(H, self.W2) + self.b2
5.2.1.3. 訓練
幸運的是,MLP 的訓練循環(huán)與 softmax 回歸完全相同。我們定義模型、數(shù)據(jù)、訓練器,最后fit在模型和數(shù)據(jù)上調(diào)用方法。
model = MLPScratch(num_inputs=784, num_outputs=10, num_hiddens=256, lr=0.1) data = d2l.FashionMNIST(batch_size=256) trainer = d2l.Trainer(max_epochs=10) trainer.fit(model, data)
model = MLPScratch(num_inputs=784, num_outputs=10, num_hiddens=256, lr=0.1) data = d2l.FashionMNIST(batch_size=256) trainer = d2l.Trainer(max_epochs=10) trainer.fit(model, data)
model = MLPScratch(num_inputs=784, num_outputs=10, num_hiddens=256, lr=0.1) data = d2l.FashionMNIST(batch_size=256) trainer = d2l.Trainer(max_epochs=10) trainer.fit(model, data)
model = MLPScratch(num_inputs=784, num_outputs=10, num_hiddens=256, lr=0.1) data = d2l.FashionMNIST(batch_size=256) trainer = d2l.Trainer(max_epochs=10) trainer.fit(model, data)
5.2.2. 簡潔的實現(xiàn)
正如您所料,通過依賴高級 API,我們可以更簡潔地實現(xiàn) MLP。
5.2.2.1. 模型
與我們對 softmax 回歸實現(xiàn)的簡潔實現(xiàn)(第 4.5 節(jié))相比,唯一的區(qū)別是我們添加了兩個完全連接的層,而我們之前只添加了 一個。第一個是隱藏層,第二個是輸出層。
class MLP(d2l.Classifier):
def __init__(self, num_outputs, num_hiddens, lr):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential(nn.Flatten(), nn.LazyLinear(num_hiddens),
nn.ReLU(), nn.LazyLinear(num_outputs))
class MLP(d2l.Classifier):
def __init__(self, num_outputs, num_hiddens, lr):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential()
self.net.add(nn.Dense(num_hiddens, activation='relu'),
nn.Dense(num_outputs))
self.net.initialize()
class MLP(d2l.Classifier):
num_outputs: int
num_hiddens: int
lr: float
@nn.compact
def __call__(self, X):
X = X.reshape((X.shape[0], -1)) # Flatten
X = nn.Dense(self.num_hiddens)(X)
X = nn.relu(X)
X = nn.Dense(self.num_outputs)(X)
return X
class MLP(d2l.Classifier):
def __init__(self, num_outputs, num_hiddens, lr):
super().__init__()
self.save_hyperparameters()
self.net = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(num_hiddens, activation='relu'),
tf.keras.layers.Dense(num_outputs)])
以前,我們forward為模型定義了使用模型參數(shù)轉(zhuǎn)換輸入的方法。這些操作本質(zhì)上是一個管道:您獲取一個輸入并應用一個轉(zhuǎn)換(例如,矩陣與權(quán)重相乘,然后是偏差加法),然后重復使用當前轉(zhuǎn)換的輸出作為下一個轉(zhuǎn)換的輸入。但是,您可能已經(jīng)注意到 forward這里沒有定義任何方法。實際上,從類(第 3.2.2 節(jié)MLP)繼承 方法以簡單地調(diào)用 (是輸入),現(xiàn)在定義為通過類進行的一系列轉(zhuǎn)換。該類抽象了前向過程,使我們能夠?qū)W⒂谵D(zhuǎn)換。我們將進一步討論如何forwardModuleself.net(X)XSequentialSequentialSequential類在第 6.1.2 節(jié)中起作用 。
5.2.2.2. 訓練
訓練循環(huán)與我們實現(xiàn) softmax 回歸時完全相同。這種模塊化使我們能夠?qū)⒂嘘P模型架構(gòu)的問題與正交考慮分開。
model = MLP(num_outputs=10, num_hiddens=256, lr=0.1) trainer.fit(model, data)
model = MLP(num_outputs=10, num_hiddens=256, lr=0.1) trainer.fit(model, data)
model = MLP(num_outputs=10, num_hiddens=256, lr=0.1) trainer.fit(model, data)
model = MLP(num_outputs=10, num_hiddens=256, lr=0.1) trainer.fit(model, data)
5.2.3. 概括
現(xiàn)在我們在設計深度網(wǎng)絡方面有了更多的實踐,從單層到多層深度網(wǎng)絡的步驟不再構(gòu)成如此重大的挑戰(zhàn)。特別是,我們可以重用訓練算法和數(shù)據(jù)加載器。但請注意,從頭開始實施 MLP 仍然很麻煩:命名和跟蹤模型參數(shù)使得擴展模型變得困難。例如,假設想要在第 42 層和第 43 層之間插入另一層。這可能是第 42b 層,除非我們愿意執(zhí)行順序重命名。此外,如果我們從頭開始實施網(wǎng)絡,框架就很難執(zhí)行有意義的性能優(yōu)化。
盡管如此,您現(xiàn)在已經(jīng)達到了 1980 年代后期的最先進水平,當時完全連接的深度網(wǎng)絡是神經(jīng)網(wǎng)絡建模的首選方法。我們的下一個概念性步驟將是考慮圖像。在我們這樣做之前,我們需要回顧一些關于如何有效計算模型的統(tǒng)計基礎知識和細節(jié)。
5.2.4. 練習
更改隱藏單元的數(shù)量num_hiddens并繪制其數(shù)量如何影響模型的準確性。這個超參數(shù)的最佳值是多少?
嘗試添加隱藏層以查看它如何影響結(jié)果。
為什么用單個神經(jīng)元插入隱藏層是個壞主意?會出什么問題?
改變學習率如何改變你的結(jié)果?在所有其他參數(shù)固定的情況下,哪個學習率能給你最好的結(jié)果?這與紀元數(shù)有何關系?
讓我們聯(lián)合優(yōu)化所有超參數(shù),即學習率、時期數(shù)、隱藏層數(shù)和每層隱藏單元數(shù)。
通過對所有這些進行優(yōu)化可以獲得的最佳結(jié)果是什么?
為什么處理多個超參數(shù)更具挑戰(zhàn)性?
描述聯(lián)合優(yōu)化多個參數(shù)的有效策略。
比較框架的速度和從頭開始實施一個具有挑戰(zhàn)性的問題。它如何隨著網(wǎng)絡的復雜性而變化?
測量對齊良好和未對齊矩陣的張量矩陣乘法的速度。例如,測試維度為 1024、1025、1026、1028 和 1032 的矩陣。
這在 GPU 和 CPU 之間有何變化?
確定 CPU 和 GPU 的內(nèi)存總線寬度。
嘗試不同的激活函數(shù)。哪一個效果最好?
網(wǎng)絡的權(quán)重初始化之間是否存在差異?有關系嗎?
-
感知器
+關注
關注
0文章
34瀏覽量
12155 -
pytorch
+關注
關注
2文章
813瀏覽量
14921
發(fā)布評論請先 登錄
DL:DL單層感知器Perceptron的原理及Perceptron Can not solve XOR problem
如何使用Keras框架搭建一個小型的神經(jīng)網(wǎng)絡多層感知器
多層感知器在提高軟件可維護性上的應用
對多層感知器和反向傳播進行入門級的介紹
人工智能–多層感知器基礎知識解讀
利用人工神經(jīng)網(wǎng)絡感知器實現(xiàn)雙足行走機器人的穩(wěn)定性控制
使用MATLAB編寫單層感知器的函數(shù)免費下載
關于機器人的五大感知器官
關于無線水壓傳感器(感知器)SG9A01的屬性介紹
無線水壓感知器(傳感器)SG9A01的參數(shù)是怎樣的
PyTorch教程5.2之多層感知器的實現(xiàn)
使用多層感知器進行機器學習
PyTorch教程-5.2. 多層感知器的實現(xiàn)
評論