pytorch nn.Module()模塊


nn.Module()

https://zhuanlan.zhihu.com/p/340453841

nn.Module()

nn.Module是nn中十分重要的類,包含網絡各層的定義及forward方法

pytorch 里面一切自定義操作基本上都是繼承nn.Module類來實現的。 簡單的說 torch的核心是Module類,所有神經網絡模塊的基類。 模塊也可以包含其他模塊,從而可以將它們嵌套在樹形結構中

如何定義自己的網絡:

  • 我們在定義自已的網絡的時候,需要繼承nn.Module 類,
  • 重新實現構造函數__init__構造函數
  • 重新實現 forward這兩個方法。

注意事項:

  • 一般把網絡中具有可學習參數的層(如全連接層、卷積層等)(模塊類的初始化) 放在構造函數__init__()

  • forward方法是必須要重寫的,它是實現模型的功能,實現各個層之間的連接關系的核心

import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
    # nn.Module的子類函數必須在構造函數中執行父類的構造函數
    def __init__(self):
        super(Model, self).__init__()   # 等價與nn.Module.__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)
	def forward(self, x):
		x = F.relu(self.conv1(x))
		return F.relu(self.conv2(x))
    
   
model=Model()
print(model)

#Model(
#  (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
#  (conv2): Conv2d(20, 20, kernel_size=(5, 5), stride=(1, 1))
# )

1、核心


forward(*input)			# 基函數中沒有是實現需要在子函數中實現

apply(fn)				# 將Module及其所有的SubModule傳進給定的fn函數操作
add_module(name,module)	# 將子模塊加入當前的模塊中,被添加的模塊可以name來獲取


apply(fn)

# 將net中的子模型Linear的 weight設置成 1,bias設置為0.  
# Example:    
def init_weights(m):
    # print(m)
    if type(m) == nn.Linear:
        m.weight.data.fill_(1.0)
        m.bias.data.fill_(0)
net = nn.Sequential(nn.Linear(2, 2))
net.apply(init_weights)

print(list(net.named_parameters()))
# >>>  tensor([[1., 1.], [1., 1.]], requires_grad=True)), ('0.bias', Parameter containing:tensor([0., 0.], requires_grad=True))] 

state_dict()

返回一個包含模塊完整狀態的字典

>>> net = torch.nn.Linear(2, 2)
>>> net.state_dict()

OrderedDict([('weight', tensor([[-0.3558,  0.2153],
        [-0.2785,  0.6982]])), ('bias', tensor([ 0.5771, -0.6232]))])
>>> net.state_dict().keys()
odict_keys(['weight', 'bias'])

add_module()

add_module(name,module)
# 添加子模塊到當前模塊中
# 該添加子模塊能夠使用給定的名字name來訪問

"""輸入參數
name(string)      子模塊的名字
module (Module)   添加到該模塊中的子模塊
"""

2、查看

使用 nn.Module 可以對網絡中的參數進行有效的管理

parameters()			# 返回一個 包含模型所有參數 的迭代器
buffers()			
children() 				# 返回當前模型 子模塊的迭代器, 不遞歸  包含子模塊
modules()				# 返回一個包含 當前模型 所有模塊的迭代器,遞歸所有葉子module 

與之對應的四個
named_parameters()
named_buffers()
named_children()
named_modules()

net = nn.Sequential(
    nn.Linear(in_features=4, out_features=2),
    nn.Linear(in_features=2, out_features=2)
)

# 隱藏層的編號是從0開始的
list(net.parameters())[0] # [0]是layer0的w
list(net.parameters())[3].shape # [3]是layer1的b
dict(net.named_parameters()).items() # 返回所有層的參數
    
optimizer = optim.SGD(net.parameters(), lr=1e-3)

# 輸出

torch.Size([2, 4])
torch.Size([2])
dict_items([('0.weight', Parameter containing:
tensor([[ 0.0195,  0.4698, -0.4913, -0.3336],
        [ 0.1422,  0.2908, -0.2469,  0.0583]], requires_grad=True)), ('0.bias', Parameter containing:
tensor([-0.4704, -0.1133], requires_grad=True)), ('1.weight', Parameter containing:
tensor([[-0.6511,  0.2442],
        [ 0.5658,  0.4419]], requires_grad=True)), ('1.bias', Parameter containing:
tensor([ 0.0114, -0.5664], requires_grad=True))])



3、設置

# 設置為訓練或者測試模式
train()			# 將module設置為 training mode,只影響dropout和batchNorm
eval()   		# 將模型設置成evaluation模式,只影響dropout和batchNorm

requires_grad_() 	# 用於設置self.parameters()是否需要record梯度,默認情況下是True
zero_grad()			# 用於設置self.parameters()的gradients為零

to()  				# 它可以當成三種函數來使用

# 選擇設備
cpu(device,id=None)   # 
cuda(device,id=None)
to() 			# 三種函數來使用  
"""
1、張量		to(tensor, non_blocking=False)
2、類型		to(dtype, non_blocking=False) 【cpu,cuda,type.float,double,half】
3、設備		to(device=None, dtype=None, non_blocking=False)
4、存儲		to(memory_format=torch.channels_last)
"""

# 案例1
>>> linear = nn.Linear(2, 2)
>>> print(linear.weight)
Parameter containing:
tensor([[ 0.0822, -0.5305],
        [ 0.3486, -0.3749]], requires_grad=True)

>>> linear.to(torch.double)
>>> print(linear.weight)
Parameter containing:
tensor([[ 0.0822, -0.5305],
        [ 0.3486, -0.3749]], dtype=torch.float64, requires_grad=True)

# 案例2
>>> gpu1 = torch.device("cuda:0")
>>> linear.to(gpu1, dtype=torch.half, non_blocking=True)
>>> print(linear.weight)
Parameter containing:
tensor([[ 0.0822, -0.5303],
        [ 0.3486, -0.3750]], device='cuda:0', dtype=torch.float16,requires_grad=True)

# 案例3
>>> cpu = torch.device("cpu")
>>> linear.to(cpu,dtype=torch.double)
>>> print(linear.weight)
Parameter containing:
tensor([[ 0.0822, -0.5303],
        [ 0.3486, -0.3750]], dtype=torch.float64, requires_grad=True)

4、注冊

register_parameter				# 向self._parameters注冊新元素
register_buffer					# 向self._buffers注冊新元素 

register_backward_hook			# 向self._backward_hooks注冊新元素
register_forward_pre_hook		# 向self._forward_pre_hooks注冊新元素
register_forward_hook			# 向self._forward_hooks注冊新元素

5、轉換

可以很方便的將所有運算都轉入到 GPU 上去,使用.device() 函數

to()		 # 
type()		 # type函數是將所有parameters和buffers都轉成指定的目標類型dst_type
double()	 # 將parameters和buffers的數據類型轉換成double
float()      # 將parameters和buffers的數據類型轉換成float
half()		 # 將parameters和buffers的數據類型轉換成half 

6、加載

可以很方便的進行 save 和 load,以防止突然發生的斷點和系統崩潰現象

load_state_dict(state_dict, strict=True)
# 將state_dict中的參數和緩沖區復制到此模塊及其后代中。如果strict為真,則state_dict的鍵必須與該模塊的state_dict()函數返回的鍵完全匹配。

"""
state_dict (dict) – 保存parameters和persistent buffers的字典。
將state_dict中的parameters和buffers復制到此module和它的后代中。

state_dict中的key必須和 model.state_dict()返回的key一致。
"""


如何將模型連接起來

nn.Sequential()

nn.Sequential(*args)

Sequential 本質上是一個容器,只是繼承了 nn.Module() ,時序容器,Modules 會以他們傳入的順序被添加到容器中

  • 繼承了 nn.Module()
class Sequential(Module): # 繼承Module
    def __init__(self, *args):  # 重寫了構造函數
    def _get_item_by_idx(self, iterator, idx):
    def __getitem__(self, idx):
    def __setitem__(self, idx, module):
    def __delitem__(self, idx):
    def __len__(self):
    def __dir__(self):
    def forward(self, input):  # 重寫關鍵方法forward

當你使用Sequential時,Modules會以傳入的順序來添加layer到容器中,也可以傳入一個OrderedDict

添加模塊1

# Example of using Sequential
# 三種寫法

model = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )
# 采用第一種方式,默認命名方式為  [0,1,2,3,4,...]
print(model)
print(model[2]) # 通過索引獲取第幾個層
'''運行結果為:
Sequential(
  (0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
  (1): ReLU()
  (2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
  (3): ReLU()
	)
	
Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
'''


添加模塊2


model = nn.Sequential(OrderedDict([
          ('conv1', nn.Conv2d(1,20,5)),
          ('relu1', nn.ReLU()),
          ('conv2', nn.Conv2d(20,64,5)),
          ('relu2', nn.ReLU())
        ]))
print(model)
print(model[2]) # 通過索引獲取第幾個層
'''運行結果為:
Sequential(
  (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
  (relu1): ReLU()
  (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
  (relu2): ReLU()
	)
	
Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
'''


# model[2] 是正確的
# model["conv2"] 是錯誤的
# 這其實是由它的定義實現的,看上面的Sequenrial定義可知,只支持index訪問。


添加模塊3

# 繼承 nn.Module 的方法,可以自定義添加模塊
# add_module(name, module)

import torch.nn as nn
from collections import OrderedDict
model = nn.Sequential()

##  實際上使用的是  nn.module() 的屬性

model.add_module("conv1",nn.Conv2d(1,20,5))
model.add_module('relu1', nn.ReLU())
model.add_module('conv2', nn.Conv2d(20,64,5))
model.add_module('relu2', nn.ReLU())
 
print(model)
print(model[2]) # 通過索引獲取第幾個層

'''運行結果為:
Sequential(
  (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
  (relu1): ReLU()
  (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
  (relu2): ReLU()
	)
Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
'''

nn.ModuleList()

class torch.nn.ModuleList(modules=None)

將你的模型保存在一個list中,可以像python list一樣被索引, moduleList 中包含的modules已經被正確的注冊,對所有module method可見

ModuleList 具有和List 相似的用法,實際上可以把它視作是 Module 和 list 的結合。

# 輸入參數  modules (list, optional) – 將要被添加到MuduleList中的 modules 列表

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers=nn.ModuleList([
            nn.Linear(1,10), nn.ReLU(),
            nn.Linear(10,1)])
    def forward(self,x):
        out = x
        for layer in self.layers:
            out = layer(out)
        return out
    
model = Model()
print(model)

Model(
  (layers): ModuleList(
    (0): Linear(in_features=1, out_features=10, bias=True)
    (1): ReLU()
    (2): Linear(in_features=10, out_features=1, bias=True)
  )
)

append(module)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers=nn.ModuleList([
            nn.Linear(1,10), nn.ReLU(),
            nn.Linear(10,1)])
        self.layers.append(nn.Linear(1, 5))
    def forward(self,x):
        out = x
        for layer in self.layers:
            out = layer(out)
        return out

extend(modules)

extend(),必須也為一個list

self.layers.extend([nn.Linear(size1, size2) for i in range(1, num_layers)])


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM