类型torch.nn.Parameter
官方解释
-
Parameters
是Variable
的子类。Variable
的一种。 -
Paramenters
和Modules
一起使用的时候会有一些特殊的属性,即:当Paramenters
赋值给Module
的属性的时候,他会自动的被加到Module
的参数列表中,也就是会出现在parameters()迭代器
中。常被用于模块参数module parameter
。 - 将
Varibale
赋值给Module
属性则不会有这样的影响。 这样做的原因是:我们有时候会需要缓存一些临时的状态state
, 比如:模型中RNN的最后一个隐状态。如果没有Parameter
这个类的话,那么这些临时变量也会注册成为模型变量。
Variable
与Parameter
的另一个不同之处在于,Parameter
不能被volatile
(即:无法设置volatile=True
)而且默认requires_grad=True
。Variable
默认requires_grad=False
。
参数说明:
- data (Tensor) – parameter tensor
- requires_grad (bool, optional) – 默认为True,在BP的过程中会对其求微分。
类内函数Module.parameters()
源码分析
可以通过Module.parameters()
获取网络的参数,那这个函数的实现细节我们通过代码进行分析:
def parameters(self):
r"""Returns an iterator over module parameters.
This is typically passed to an optimizer.
Yields:
Parameter: module parameter
Example::
>>> for param in model.parameters():
>>> print(type(param.data), param.size())
<class 'torch.FloatTensor'> (20L,)
<class 'torch.FloatTensor'> (20L, 1L, 5L, 5L)
"""
for name, param in self.named_parameters():
yield param
他主要是引用另一个类内成员函数named_parameters()
,实现对所有参数的索引包装,生成迭代器,下面看另一个函数:
def named_parameters(self, memo=None, prefix=''):
r"""Returns an iterator over module parameters, yielding both the
name of the parameter as well as the parameter itself
Yields:
(string, Parameter): Tuple containing the name and parameter
Example::
>>> for name, param in self.named_parameters():
>>> if name in ['bias']:
>>> print(param.size())
"""
if memo is None:
memo = set()
#本身模块的参数
for name, p in self._parameters.items():
if p is not None and p not in memo:
memo.add(p)
yield prefix + ('.' if prefix else '') + name, p
for mname, module in self.named_children():
submodule_prefix = prefix + ('.' if prefix else '') + mname
#递归取得子模块的参数
for name, p in module.named_parameters(memo, submodule_prefix):
yield name, p
可以看到是通过枚举模块和子模块(成员self
对象是Module
类型)的成员_parameters
,那_parameters
的定义通过Module
的初始化函数可以看懂,可以看到_parameters
(也留意_modules
) 其实是有序字典。
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._modules = OrderedDict()
self.training = True
使用函数获得参数组
使用.parameters()
获得参数组,具体原理查看源码可以得知(之后的一篇文章中会有讲述),这个函数是属于每一个网络在初始化的时候都会继承于nn.Module
的类成员函数,主要功能就是返回一个迭代器。我们可以测试一下。
具体功能就是可以通过它得到所有一个网络下参数迭代器,可以通过for循环对她进行遍历
下面我们来看一下
print(net.parameters())
print(type(net.parameters()))#返回一个迭代器
print(list(net.parameters()))
for name, parms in net.named_parameters():
print('-->name:', name)
print('-->para:', parms)
print("===")
input()
类内函数 Module.__setattr__(self, name, value)
实现类内成员的赋值
该函数在类完成初始化后,调用该函数对类内成员。可以看到如果赋值类成员的对象是Parameter类型
,那么将调用函数register_parameter
注册参数,其实是添加参数到有序字典成员_parameters
中:
源码:
def __setattr__(self, name, value):
def remove_from(*dicts):
for d in dicts:
if name in d:
del d[name]
params = self.__dict__.get('_parameters')
#如果成员是Parameter类型
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)
elif params is not None and name in params:
if value is not None:
raise TypeError("cannot assign '{}' as parameter '{}' "
"(torch.nn.Parameter or None expected)"
.format(torch.typename(value), name))
self.register_parameter(name, value)
else:
modules = self.__dict__.get('_modules')
#如果成员是Module类型
if isinstance(value, Module):
if modules is None:
raise AttributeError(
"cannot assign module before Module.__init__() call")
remove_from(self.__dict__, self._parameters, self._buffers)
modules[name] = value
elif modules is not None and name in modules:
if value is not None:
raise TypeError("cannot assign '{}' as child module '{}' "
"(torch.nn.Module or None expected)"
.format(torch.typename(value), name))
modules[name] = value
else:
buffers = self.__dict__.get('_buffers')
if buffers is not None and name in buffers:
if value is not None and not isinstance(value, torch.Tensor):
raise TypeError("cannot assign '{}' as buffer '{}' "
"(torch.Tensor or None expected)"
.format(torch.typename(value), name))
buffers[name] = value
else:
object.__setattr__(self, name, value)
def register_parameter(self, name, param):
r"""Adds a parameter to the module.
The parameter can be accessed as an attribute using given name.
Args:
name (string): name of the parameter. The parameter can be accessed
from this module using the given name
parameter (Parameter): parameter to be added to the module.
"""
if '_parameters' not in self.__dict__:
raise AttributeError(
"cannot assign parameter before Module.__init__() call")
elif not isinstance(name, torch._six.string_classes):
raise TypeError("parameter name should be a string. "
"Got {}".format(torch.typename(name)))
elif '.' in name:
raise KeyError("parameter name can't contain \".\"")
elif name == '':
raise KeyError("parameter name can't be empty string \"\"")
elif hasattr(self, name) and name not in self._parameters:
raise KeyError("attribute '{}' already exists".format(name))
if param is None:
self._parameters[name] = None
elif not isinstance(param, Parameter):
raise TypeError("cannot assign '{}' object to parameter '{}' "
"(torch.nn.Parameter or None required)"
.format(torch.typename(param), name))
elif param.grad_fn:
raise ValueError(
"Cannot assign non-leaf Tensor to parameter '{0}'. Model "
"parameters must be created explicitly. To express '{0}' "
"as a function of another Tensor, compute the value in "
"the forward() method.".format(name))
else:
self._parameters[name] = param