多層感知器 (MLP) 的實(shí)現(xiàn)并不比簡(jiǎn)單的線性模型復(fù)雜多少。關(guān)鍵的概念差異是我們現(xiàn)在連接多個(gè)層。
import tensorflow as tf
from d2l import tensorflow as d2l
5.2.1. 從零開始實(shí)施
讓我們從頭開始實(shí)現(xiàn)這樣一個(gè)網(wǎng)絡(luò)。
5.2.1.1. 初始化模型參數(shù)
回想一下,F(xiàn)ashion-MNIST 包含 10 個(gè)類,并且每個(gè)圖像由一個(gè)28×28=784灰度像素值網(wǎng)格。和以前一樣,我們暫時(shí)忽略像素之間的空間結(jié)構(gòu),因此我們可以將其視為具有 784 個(gè)輸入特征和 10 個(gè)類別的分類數(shù)據(jù)集。首先,我們將實(shí)現(xiàn)一個(gè)具有一個(gè)隱藏層和 256 個(gè)隱藏單元的 MLP。層數(shù)和寬度都是可調(diào)的(它們被認(rèn)為是超參數(shù))。通常,我們選擇層寬度可以被 2 的較大次冪整除。由于內(nèi)存在硬件中分配和尋址的方式,這在計(jì)算上是高效的。
同樣,我們將用幾個(gè)張量表示我們的參數(shù)。請(qǐng)注意, 對(duì)于每一層,我們必須跟蹤一個(gè)權(quán)重矩陣和一個(gè)偏置向量。與往常一樣,我們?yōu)檫@些參數(shù)的損失梯度分配內(nèi)存。
在下面的代碼中,我們使用 `nn.Parameter
< https://pytorch.org/docs/stable/generated/torch.nn.parameter.Parameter.html >`__ 自動(dòng)將類屬性注冊(cè)為要跟蹤的參數(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
<https://flax.readthedocs.io/en/latest/api_reference/flax.linen.html#flax.linen.Module.param>`__ to define the model parameter.
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
<https://www.tensorflow.org/api_docs/python/tf/Variable>`__ to define the model parameter.
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. 模型
為了確保我們知道一切是如何工作的,我們將自己實(shí)現(xiàn) ReLU 激活,而不是直接調(diào)用內(nèi)置relu
函數(shù)。
def relu(X):
return np.maximum(X, 0)
由于我們忽略了空間結(jié)構(gòu),我們將reshape
每個(gè)二維圖像轉(zhuǎn)換為長(zhǎng)度為 的平面向量num_inputs
。最后,我們只用幾行代碼就實(shí)現(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
5.2.1.3. 訓(xùn)練
幸運(yùn)的是,MLP 的訓(xùn)練循環(huán)與 softmax 回歸完全相同。我們定義模型、數(shù)據(jù)、訓(xùn)練器,最后fit
在模型和數(shù)據(jù)上調(diào)用方法。
評(píng)論
查看更多