本文來自《20天吃透Pytorch》
一,nn.functional 和 nn.Module
前面我們介紹了Pytorch的張量的結構操作和數學運算中的一些常用API。
利用這些張量的API我們可以構建出神經網絡相關的組件(如激活函數,模型層,損失函數)。
Pytorch和神經網絡相關的功能組件大多都封裝在 torch.nn模塊下。
這些功能組件的絕大部分既有函數形式實現,也有類形式實現。
其中nn.functional(一般引入后改名為F)有各種功能組件的函數實現。例如:
(激活函數) * F.relu * F.sigmoid * F.tanh * F.softmax
(模型層) * F.linear * F.conv2d * F.max_pool2d * F.dropout2d * F.embedding
(損失函數) * F.binary_cross_entropy * F.mse_loss * F.cross_entropy
為了便于對參數進行管理,一般通過繼承 nn.Module 轉換成為類的實現形式,并直接封裝在 nn 模塊下。例如:
(激活函數) * nn.ReLU * nn.Sigmoid * nn.Tanh * nn.Softmax
(模型層) * nn.Linear * nn.Conv2d * nn.MaxPool2d * nn.Dropout2d * nn.Embedding
(損失函數) * nn.BCELoss * nn.MSELoss * nn.CrossEntropyLoss
二,使用nn.Module來管理參數
在Pytorch中,模型的參數是需要被優化器訓練的,因此,通常要設置參數為 requires_grad = True 的張量。
同時,在一個模型中,往往有許多的參數,要手動管理這些參數并不是一件容易的事情。
Pytorch一般將參數用nn.Parameter來表示,并且用nn.Module來管理其結構下的所有參數。
# nn.Parameter 具有 requires_grad = True 屬性
w = nn.Parameter(torch.randn(2,2))
print(w)
print(w.requires_grad)# nn.ParameterList 可以將多個nn.Parameter組成一個列表
params_list = nn.ParameterList([nn.Parameter(torch.rand(8,i)) for i in range(1,3)])
print(params_list)
print(params_list[0].requires_grad)# nn.ParameterDict 可以將多個nn.Parameter組成一個字典params_dict = nn.ParameterDict({"a":nn.Parameter(torch.rand(2,2)),"b":nn.Parameter(torch.zeros(2))})
print(params_dict)
print(params_dict["a"].requires_grad)# 可以用Module將它們管理起來
# module.parameters()返回一個生成器,包括其結構下的所有parametersmodule = nn.Module()
module.w = w
module.params_list = params_list
module.params_dict = params_dictnum_param = 0
for param in module.parameters():print(param,"\n")num_param = num_param + 1
print("number of Parameters =",num_param)#實踐當中,一般通過繼承nn.Module來構建模塊類,并將所有含有需要學習的參數的部分放在構造函數中。#以下范例為Pytorch中nn.Linear的源碼的簡化版本
#可以看到它將需要學習的參數放在了__init__構造函數中,并在forward中調用F.linear函數來實現計算邏輯。class Linear(nn.Module):__constants__ = ['in_features', 'out_features']def __init__(self, in_features, out_features, bias=True):super(Linear, self).__init__()self.in_features = in_featuresself.out_features = out_featuresself.weight = nn.Parameter(torch.Tensor(out_features, in_features))if bias:self.bias = nn.Parameter(torch.Tensor(out_features))else:self.register_parameter('bias', None)def forward(self, input):return F.linear(input, self.weight, self.bias)
三,使用nn.Module來管理子模塊
實際上nn.Module除了可以管理其引用的各種參數,還可以管理其引用的子模塊,功能十分強大。
一般情況下,我們都很少直接使用 nn.Parameter來定義參數構建模型,而是通過一些拼裝一些常用的模型層來構造模型。
這些模型層也是繼承自nn.Module的對象,本身也包括參數,屬于我們要定義的模塊的子模塊。
nn.Module提供了一些方法可以管理這些子模塊。
children() 方法: 返回生成器,包括模塊下的所有子模塊。
named_children()方法:返回一個生成器,包括模塊下的所有子模塊,以及它們的名字。
modules()方法:返回一個生成器,包括模塊下的所有各個層級的模塊,包括模塊本身。
named_modules()方法:返回一個生成器,包括模塊下的所有各個層級的模塊以及它們的名字,包括模塊本身。
其中chidren()方法和named_children()方法較多使用。
modules()方法和named_modules()方法較少使用,其功能可以通過多個named_children()的嵌套使用實現。
i = 0
for child in net.children():i+=1print(child,"\n")
print("child number",i)
i = 0
for name,child in net.named_children():i+=1print(name,":",child,"\n")
print("child number",i)
i = 0
for module in net.modules():i+=1print(module)
print("module number:",i)
下面我們通過named_children方法找到embedding層,并將其參數設置為不可訓練(相當于凍結embedding層)。
children_dict = {name:module for name,module in net.named_children()}print(children_dict)
embedding = children_dict["embedding"]
embedding.requires_grad_(False) #凍結其參數