原創(chuàng)網(wǎng)站設(shè)計個人能接廣告聯(lián)盟嗎
1 層和塊
塊由類(class)表示。它的任何子類都必須定義一個將其輸入轉(zhuǎn)換為輸出的前向傳播函數(shù),并且必須存儲任何必需的參數(shù)。注意,有些塊不需要任何參數(shù)。最后,為了計算梯度,塊必須具有反向傳播函數(shù)。
1.1 自定義塊
每個塊必須提供的基本功能:
- 將輸入數(shù)據(jù)作為其前向傳播函數(shù)的參數(shù)。
- 通過前向傳播函數(shù)來生成輸出。
- 計算其輸出關(guān)于輸入的梯度,可通過其反向傳播函數(shù)進(jìn)行訪問。通常這是自動發(fā)生的。
- 存儲和訪問前向傳播計算所需的參數(shù)。
- 根據(jù)需要初始化模型參數(shù)。
class MLP(nn.Module):# 用模型參數(shù)聲明層。這里,我們聲明兩個全連接的層def __init__(self):# 調(diào)用MLP的父類Module的構(gòu)造函數(shù)來執(zhí)行必要的初始化。# 這樣,在類實例化時也可以指定其他函數(shù)參數(shù),例如模型參數(shù)params(稍后將介紹)super().__init__()self.hidden = nn.Linear(20, 256) # 隱藏層self.out = nn.Linear(256, 10) # 輸出層# 定義模型的前向傳播,即如何根據(jù)輸入X返回所需的模型輸出def forward(self, X):# 注意,這里我們使用ReLU的函數(shù)版本,其在nn.functional模塊中定義。return self.out(F.relu(self.hidden(X)))
2 參數(shù)管理
參數(shù)是復(fù)合的對象,包含值、梯度和額外信息。
訪問第一個全連接層的參數(shù)和訪問所有層
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
print(*[(name, param.shape) for name, param in net.named_parameters()])
另一種訪問網(wǎng)絡(luò)參數(shù)的方式
net.state_dict()['2.bias'].data
2.1 參數(shù)初始化
默認(rèn)情況下,PyTorch會根據(jù)一個范圍均勻地初始化權(quán)重和偏置矩陣,這個范圍是根據(jù)輸入和輸出維度計算出的。PyTorch的nn.init模塊提供了多種預(yù)置初始化方法。
2.1.1 內(nèi)置初始化
下面的代碼將所有權(quán)重參數(shù)初始化為標(biāo)準(zhǔn)差為0.01的高斯隨機(jī)變量, 且將偏置參數(shù)設(shè)置為0。
def init_normal(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, mean=0, std=0.01)nn.init.zeros_(m.bias)
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]
還可以將所有參數(shù)初始化為給定的常數(shù),比如初始化為1。
def init_constant(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 1)nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]
還可以[對某些塊應(yīng)用不同的初始化方法]。 例如,下面使用Xavier初始化方法初始化第一個神經(jīng)網(wǎng)絡(luò)層, 然后將第三個神經(jīng)網(wǎng)絡(luò)層初始化為常量值42。
def init_xavier(m):if type(m) == nn.Linear:nn.init.xavier_uniform_(m.weight)
def init_42(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 42)net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
2.1.2 自定義初始化
使用以下的分布為任意權(quán)重參數(shù)𝑤定義初始化方法:
def my_init(m):if type(m) == nn.Linear:print("Init", *[(name, param.shape)for name, param in m.named_parameters()][0])nn.init.uniform_(m.weight, -10, 10)m.weight.data *= m.weight.data.abs() >= 5net.apply(my_init)
net[0].weight[:2]
2.2 參數(shù)綁定
在多個層間共享參數(shù): 可以定義一個稠密層,然后使用它的參數(shù)來設(shè)置另一個層的參數(shù)。
# 我們需要給共享層一個名稱,以便可以引用它的參數(shù)
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),shared, nn.ReLU(),shared, nn.ReLU(),nn.Linear(8, 1))
net(X)
# 檢查參數(shù)是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 確保它們實際上是同一個對象,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])
這個例子表明第三個和第五個神經(jīng)網(wǎng)絡(luò)層的參數(shù)是綁定的。 它們不僅值相等,而且由相同的張量表示。 因此,如果我們改變其中一個參數(shù),另一個參數(shù)也會改變。
當(dāng)參數(shù)綁定時,梯度會發(fā)生什么情況? 答案是由于模型參數(shù)包含梯度,因此在反向傳播期間第二個隱藏層 (即第三個神經(jīng)網(wǎng)絡(luò)層)和第三個隱藏層(即第五個神經(jīng)網(wǎng)絡(luò)層)的梯度會加在一起。
3 自定義層
3.1 不帶參數(shù)的層
首先,我們(構(gòu)造一個沒有任何參數(shù)的自定義層)。只需繼承基礎(chǔ)層類并實現(xiàn)前向傳播功能。
import torch
import torch.nn.functional as F
from torch import nnclass CenteredLayer(nn.Module):def __init__(self):super().__init__()def forward(self, X):return X - X.mean()
3.2 帶參數(shù)的層
參數(shù)可以通過訓(xùn)練進(jìn)行調(diào)整。 我們可以使用內(nèi)置函數(shù)來創(chuàng)建參數(shù),這些函數(shù)提供一些基本的管理功能。 比如管理訪問、初始化、共享、保存和加載模型參數(shù)。
實現(xiàn)自定義版本的全連接層。 回想一下,該層需要兩個參數(shù),一個用于表示權(quán)重,另一個用于表示偏置項。
class MyLinear(nn.Module):def __init__(self, in_units, units):super().__init__()self.weight = nn.Parameter(torch.randn(in_units, units))self.bias = nn.Parameter(torch.randn(units,))def forward(self, X):linear = torch.matmul(X, self.weight.data) + self.bias.datareturn F.relu(linear)