类型torch.nn.Parameter

官方解释

  • ParametersVariable的子类。Variable的一种。
  • ParamentersModules一起使用的时候会有一些特殊的属性,即:当Paramenters赋值给Module的属性的时候,他会自动的被加到Module的参数列表中,也就是会出现在parameters()迭代器中。常被用于模块参数module parameter
  • Varibale赋值给Module属性则不会有这样的影响。 这样做的原因是:我们有时候会需要缓存一些临时的状态state, 比如:模型中RNN的最后一个隐状态。如果没有Parameter这个类的话,那么这些临时变量也会注册成为模型变量。

VariableParameter的另一个不同之处在于,Parameter不能被volatile(即:无法设置volatile=True)而且默认requires_grad=TrueVariable默认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()

pytorch模型封装 pytorch model.parameters_pytorch

类内函数 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