Pytorch中Module,Parameter和Buffer的區別


下文都將torch.nn簡寫成nn

  • Module: 就是我們常用的torch.nn.Module類,你定義的所有網絡結構都必須繼承這個類。
  • Buffer: buffer和parameter相對,就是指那些不需要參與反向傳播的參數
    示例如下:
class MyModel(nn.Module):
	def __init__(self):
		super(MyModel, self).__init__()
		self.my_tensor = torch.randn(1) # 參數直接作為模型類成員變量
		self.register_buffer('my_buffer', torch.randn(1)) # 參數注冊為 buffer
		self.my_param = nn.Parameter(torch.randn(1))
	def forward(self, x):
		return x	

model = MyModel()
print(model.state_dict())
>>>OrderedDict([('my_param', tensor([1.2357])), ('my_buffer', tensor([-0.9982]))])
  • Parameter: 是nn.parameter.Paramter,也就是組成Module的參數。例如一個nn.Linear通常由weightbias參數組成。它的特點是默認requires_grad=True,也就是說訓練過程中需要反向傳播的,就需要使用這個
import torch.nn as nn
fc = nn.Linear(2,2)

# 讀取參數的方式一
fc._parameters
>>> OrderedDict([('weight', Parameter containing:
              tensor([[0.4142, 0.0424],
                      [0.3940, 0.0796]], requires_grad=True)),
             ('bias', Parameter containing:
              tensor([-0.2885,  0.5825], requires_grad=True))])
			  
# 讀取參數的方式二(推薦這種)
for n, p in fc.named_parameters():
	print(n,p)
>>>weight Parameter containing:
tensor([[0.4142, 0.0424],
        [0.3940, 0.0796]], requires_grad=True)
bias Parameter containing:
tensor([-0.2885,  0.5825], requires_grad=True)

# 讀取參數的方式三
for p in fc.parameters():
	print(p)
>>>Parameter containing:
tensor([[0.4142, 0.0424],
        [0.3940, 0.0796]], requires_grad=True)
Parameter containing:
tensor([-0.2885,  0.5825], requires_grad=True)

通過上面的例子可以看到,nn.parameter.Paramterrequires_grad屬性值默認為True。另外上面例子給出了三種讀取parameter的方法,推薦使用后面兩種(這兩種的區別可參閱Pytorch: parameters(),children(),modules(),named_*區別),因為是以迭代生成器的方式來讀取,第一種方式是一股腦的把參數全丟給你,要是模型很大,估計你的電腦會吃不消。

另外需要介紹的是_parametersnn.Module__init__()函數中就定義了的一個OrderDict類,這個可以通過看下面給出的部分源碼看到,可以看到還初始化了很多其他東西,其實原理都大同小異,你理解了這個之后,其他的也是同樣的道理。

class Module(object):
	...
    def __init__(self):
        self._backend = thnn_backend
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._forward_pre_hooks = OrderedDict()
        self._state_dict_hooks = OrderedDict()
        self._load_state_dict_pre_hooks = OrderedDict()
        self._modules = OrderedDict()
        self.training = True

每當我們給一個成員變量定義一個nn.parameter.Paramter的時候,都會自動注冊到_parameters,具體的步驟如下:

import torch.nn as nn
class MyModel(nn.Module):
	def __init__(self):
		super(MyModel, self).__init__()
		# 下面兩種定義方式均可
		self.p1 = nn.paramter.Paramter(torch.tensor(1.0))
		print(self._parameters)
		self.p2 = nn.Paramter(torch.tensor(2.0))
		print(self._parameters)
  • 首先運行super(MyModel, self).__init__(),這樣MyModel就初始化了_paramters等一系列的OrderDict,此時所有變量還都是空的。
  • self.p1 = nn.paramter.Paramter(torch.tensor(1.0)): 這行代碼會觸發nn.Module預定義好的__setattr__函數,該函數部分源碼如下,:
def __setattr__(self, name, value):
	...
	params = self.__dict__.get('_parameters')
	if isinstance(value, Parameter):
		if params is None:
			raise AttributeError(
				"cannot assign parameters before Module.__init__() call")
		remove_from(self.__dict__, self._buffers, self._modules)
		self.register_parameter(name, value)
	...

__setattr__函數作用簡單理解就是判斷你定義的參數是否正確,如果正確就繼續調用register_parameter函數進行注冊,這個函數簡單概括就是做了下面這件事

def register_parameter(self,name,param):
	...
	self._parameters[name]=param

下面我們實例化這個模型看結果怎樣

model = MyModel()
>>>OrderedDict([('p1', Parameter containing:
tensor(1., requires_grad=True))])
OrderedDict([('p1', Parameter containing:
tensor(1., requires_grad=True)), ('p2', Parameter containing:
tensor(2., requires_grad=True))])

結果和上面分析的一致。



MARSGGBO原創


如有意合作,歡迎私戳

郵箱:marsggbo@foxmail.com


2019-12-20 21:11:02




免責聲明!

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



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