pytorch中state_dict()和named_parameters()的差别,以及model.buffer/model.parameter

在使用pytorch过程中,我发现了torch中存在3个功能极其类似的方法,它们分别是model.parameters()model.named_parameters()model.state_dict(),下面就具体来说说这三个函数的差异
首先,说说比较接近的model.parameters()model.named_parameters()。这两者唯一的差别在于,named_parameters()返回的list中,每个元祖打包了2个内容,分别是layer-name和layer-param,而parameters()只有后者。后面只谈model.named_parameters()model.state_dict()间的差别。


它们的差异主要体现在3方面:

  • 返回值类型不同
  • 存储的模型参数的种类不同
  • 返回的值的require_grad属性不同

首先说第一个,这很简单,model.state_dict()是将layer_name : layer_param的键值信息存储为dict形式,而model.named_parameters()则是打包成一个元祖然后再存到list当中;
第二,model.state_dict()存储的是该model中包含的所有layer中的所有参数;而model.named_parameters()则只保存可学习、可被更新的参数,model.buffer()中的参数不包含在model.named_parameters()
最后,model.state_dict()所存储的模型参数tensor的require_grad属性都是False,而model.named_parameters()require_grad属性都是True


最后,再说说nn.Parameters()

实际上,我们以上提到的model.parameters()model.named_parameters()都和这个module有关,毕竟模型参数在初始化中就是用这个模块被实例化的。以神经网络中最常见的nn.Linear()为例,这是pytorch1.4的nn.Linear()源码:

class Linear(Module):
	 __constants__ = ['bias']
    def __init__(self, in_features, out_features, bias=True):
        super(Linear, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        self.weight = Parameter(torch.Tensor(out_features, in_features))
        if bias:
            self.bias = Parameter(torch.Tensor(out_features))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()

如上代码第7、第9行,大家可以发现,我们新建的线性层的参数weight和bias的初始化,都是使用nn.Parameters()做的,那么我们再看看这个module的玄机(同样是torch源码):

class Parameter(torch.Tensor):
    def __new__(cls, data=None, requires_grad=True):
        if data is None:
            data = torch.Tensor()
        return torch.Tensor._make_subclass(cls, data, requires_grad)

注意第2行,这里正是说明为何model.parameters()迭代出来的所有参数的require_grad属性都是True了,因为它们在被创建时,默认的require_grad就是True。这也符合逻辑,即,使用nn.Parameter()创建的变量是模型参数,本就是要参与学习和更新的;而不参与模型学习和更新的呢?我们再看一个例子:

class _BatchNorm(Module):
    def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True,  track_running_stats=True):
        super(_BatchNorm, self).__init__()
        self.num_features = num_features
        self.eps = eps
        self.momentum = momentum
        self.affine = affine
        self.track_running_stats = track_running_stats
        if self.affine:
            self.weight = Parameter(torch.Tensor(num_features))
            self.bias = Parameter(torch.Tensor(num_features))
        else:
            self.register_parameter('weight', None)
            self.register_parameter('bias', None)
        if self.track_running_stats:
            self.register_buffer('running_mean', torch.zeros(num_features))
            self.register_buffer('running_var', torch.ones(num_features))
            self.register_buffer('num_batches_tracked', torch.tensor(0, dtype=torch.long))
        else:
            self.register_parameter('running_mean', None)
            self.register_parameter('running_var', None)
            self.register_parameter('num_batches_tracked', None)
        self.reset_parameters()

如以上代码16-18行,这一行定义的三个参数是不参与模型学习的,所以定义在buffer中,buffer的定义方法为self.register_buffer(),所以模型不参与学习和更新的参数是这样定义的、

你可能感兴趣的:(#,pytorch,#,BERT,Python)