当前位置:   article > 正文

Pytorch中state_dict()、named_parameters()和parameters()的区别_model_state()和parameters()的区别

model_state()和parameters()的区别

序言

  • Pytorch中有3个功能极其类似的方法,分别是model.parameters()model.named_parameters()model.state_dict(),下面就来探究一下这三种方法的区别。

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

    1. 返回值类型不同

    2. 存储的模型参数的种类不同

    3. 返回的值的require_grad属性不同

测试代码准备工作

import torch
import torch.nn as nn
import torch.optim as optim
import random
import os
import numpy as np

def seed_torch(seed=1029):
	random.seed(seed)
	os.environ['PYTHONHASHSEED'] = str(seed) # 为了禁止hash随机化,使得实验可复现
	np.random.seed(seed)
	torch.manual_seed(seed)
	torch.cuda.manual_seed(seed)
	torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
	torch.backends.cudnn.benchmark = False
	torch.backends.cudnn.deterministic = True

seed_torch() # 固定随机数

# 定义一个网络
class net(nn.Module):
    def __init__(self, num_class=10):
        super(net, self).__init__()
        self.pool1 = nn.AvgPool1d(2)
        self.bn1 = nn.BatchNorm1d(3)
        self.fc1 = nn.Linear(12, 4)
        

    
    def forward(self, x):
        x = self.pool1(x)
        x = self.bn1(x)
        x = x.reshape(x.size(0), -1)
        x = self.fc1(x)

        return x


# 定义网络
model = net()

# 定义loss
loss_fn = nn.CrossEntropyLoss()

# 定义优化器
optimizer = optim.SGD(model.parameters(), lr=1e-2)

# 定义训练数据
x = torch.randn((3, 3, 8))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

两个概念

可学习参数

  1. 可学习参数也可叫做模型参数,其就是要参与学习和更新的,特别注意这里的参数更新是指在优化器的optim.step步骤里更新参数,即需要反向传播更新的参数

  2. 使用nn.parameter.Parameter()创建的变量是可学习参数(模型参数)

  3. 模型中的可学习参数的数据类型都是nn.parameter.Parameter

  4. optim.step只能更新nn.parameter.Parameter类型的参数

  5. nn.parameter.Parameter类型的参数的特点是默认requires_grad=True,也就是说训练过程中需要反向传播的,就需要使用这个

  6. 示例:

    在上述定义的网络中,self.fc1层中的参数(weightbias)是可学习参数,要在训练过程中进行学习与更新

    print(type(model.fc1.weight))
    
    • 1
    (bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
    <class 'torch.nn.parameter.Parameter'>
    
    • 1
    • 2

不可学习参数

  1. 不可学习参数不参与学习和在优化器中的更新,即不需要参与反向传播

  2. 不可学习参数将会通过Module.register_parameter()注册在self._buffers中,self._buffers是一个OrderedDict

    举例:上述定义的模型中,self.bn1层中的参数running_meanrunning_varnum_batches_tracked均是不可学习参数

    self.register_parameter('running_mean', None)
    
    • 1
  3. 存储在self._buffers中的不可学习参数不能通过optim.step()更新参数,但例如上述的self.bn1层中的不可学习参数也会更新,其更新是发生在forward的过程中

  4. 示例:

    在上述定义的网络中,self.bn1层中的参数(running_mean)是不可学习参数

    print(type(model.bn1.running_mean))
    
    • 1
    (bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
    <class 'torch.Tensor'>
    
    • 1
    • 2

named_parameters()

总述

  1. model.named_parameters()返回的是一个生成器(generator),该生成器中只保存了可学习、可被优化器更新的参数的参数名和具体的参数,可通过循环迭代打印参数名和参数(参见代码示例一)
  2. 该方法可以用来改变可学习、可被优化器更新参数的requires_grad属性,因此可用于锁住某些层的参数,让其在训练的时候不更新参数(参见代码示例二)

代码示例一

# model.named_parameters()的用法
print(type(model.named_parameters()))

for name, param in model.named_parameters():
    print(name)
    print(param)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
<class 'generator'>
bn1.weight
Parameter containing:
tensor([1., 1., 1.], requires_grad=True)
bn1.bias
Parameter containing:
tensor([0., 0., 0.], requires_grad=True)
fc1.weight
Parameter containing:
tensor([[ 0.0036,  0.1960,  0.2315, -0.2408,  0.1217,  0.2579, -0.0676, -0.1880,
         -0.2855, -0.1587,  0.0409,  0.0312],
        [ 0.1057,  0.1348, -0.0590, -0.1538,  0.2505,  0.0651, -0.2461, -0.1856,
          0.2498, -0.1969,  0.0013,  0.1979],
        [-0.1812,  0.1153,  0.2723, -0.2190,  0.0371, -0.0341,  0.2282,  0.1461,
          0.1890,  0.1762,  0.2657, -0.0827],
        [-0.0188,  0.0081, -0.2674, -0.1858,  0.1296,  0.1728, -0.0770,  0.1444,
         -0.2360, -0.1793,  0.1921, -0.2791]], requires_grad=True)
fc1.bias
Parameter containing:
tensor([-0.0020,  0.0985,  0.1859, -0.0175], requires_grad=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

代码示例二

print(model.fc1.weight.requires_grad)  # 可学习参数fc1.weight的requires_grad属性

for name, param in model.named_parameters():
    if ("fc1" in name):
        param.requires_grad = False

print(model.fc1.weight.requires_grad)  # 修改后可学习参数fc1.weight的requires_grad属性
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
True
False
  • 1
  • 2
  • 3

parameters()

总述

  1. model.parameters()返回的是一个生成器,该生成器中只保存了可学习、可被优化器更新的参数的具体的参数,可通过循环迭代打印参数。(参见代码示例一)
  2. model.named_parameters()相比,model.parameters()不会保存参数的名字。
  3. 该方法可以用来改变可学习、可被优化器更新参数的requires_grad属性,但由于其只有参数,没有对应的参数名,所以当要修改指定的某些层的requires_grad属性时,没有model.named_parameters()方便。(参见代码示例二)

代码示例一

# model.parameters()的用法
print(type(model.parameters()))

for param in model.parameters():
    print(param)
  • 1
  • 2
  • 3
  • 4
  • 5
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
<class 'generator'>
Parameter containing:
tensor([1., 1., 1.], requires_grad=True)
Parameter containing:
tensor([0., 0., 0.], requires_grad=True)
Parameter containing:
tensor([[ 0.0036,  0.1960,  0.2315, -0.2408,  0.1217,  0.2579, -0.0676, -0.1880,
         -0.2855, -0.1587,  0.0409,  0.0312],
        [ 0.1057,  0.1348, -0.0590, -0.1538,  0.2505,  0.0651, -0.2461, -0.1856,
          0.2498, -0.1969,  0.0013,  0.1979],
        [-0.1812,  0.1153,  0.2723, -0.2190,  0.0371, -0.0341,  0.2282,  0.1461,
          0.1890,  0.1762,  0.2657, -0.0827],
        [-0.0188,  0.0081, -0.2674, -0.1858,  0.1296,  0.1728, -0.0770,  0.1444,
         -0.2360, -0.1793,  0.1921, -0.2791]], requires_grad=True)
Parameter containing:
tensor([-0.0020,  0.0985,  0.1859, -0.0175], requires_grad=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

代码示例二

print(model.fc1.weight.requires_grad)

for param in model.parameters():
    param.requires_grad = False

print(model.fc1.weight.requires_grad)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
True
False
  • 1
  • 2
  • 3

state_dict()

总述

  1. model.state_dict()返回的是一个有序字典OrderedDict该有序字典中保存了模型所有参数的参数名和具体的参数值,所有参数包括可学习参数和不可学习参数,可通过循环迭代打印参数,因此,该方法可用于保存模型,当保存模型时,会将不可学习参数也存下,当加载模型时,也会将不可学习参数进行赋值。(参见代码示例一)

  2. 一般在使用model.state_dict()会使用该函数的默认参数model.state_dict()源码如下:

    # torch.nn.modules.module.py
    class Module(object):
        def state_dict(self, destination=None, prefix='', keep_vars=False):
            if destination is None:
                destination = OrderedDict()
                destination._metadata = OrderedDict()
            destination._metadata[prefix[:-1]] = local_metadata = dict(version=self._version)
            for name, param in self._parameters.items():
                if param is not None:
                    destination[prefix + name] = param if keep_vars else param.data
            for name, buf in self._buffers.items():
                if buf is not None:
                    destination[prefix + name] = buf if keep_vars else buf.data
            for name, module in self._modules.items():
                if module is not None:
                    module.state_dict(destination, prefix + name + '.', keep_vars=keep_vars)
            for hook in self._state_dict_hooks.values():
                hook_result = hook(self, destination, prefix, local_metadata)
                if hook_result is not None:
                    destination = hook_result
            return destination
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  3. 在默认参数下,model.state_dict()保存参数时只会保存参数(Tensor对象)的data属性,不会保存参数的requires_grad属性,因此,其保存的参数的requires_grad的属性变为False,没有办法改变requires_grad的属性,所以改变requires_grad的属性只能通过上面的两种方式。(参见代码示例二)

  4. model.state_dict()本质上是浅拷贝,即返回的OrderedDict对象本身是新创建的对象,但其中的param参数的引用仍是模型参数的data属性的地址,又因为Tensor是可变对象,因此,若对param参数进行修改(在原地址变更数据内容),会导致对应的模型参数的改变。(参见代码示例三)

代码示例一

# model.state_dict()的用法
print(model.state_dict())

for name, param in model.state_dict().items():
    print(name)
    print(param)
    print(param.requires_grad)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
OrderedDict([('bn1.weight', tensor([1., 1., 1.])), ('bn1.bias', tensor([0., 0., 0.])), ('bn1.running_mean', tensor([0., 0., 0.])), ('bn1.running_var', tensor([1., 1., 1.])), ('bn1.num_batches_tracked', tensor(0)), ('fc1.weight', tensor([[ 0.0036,  0.1960,  0.2315, -0.2408,  0.1217,  0.2579, -0.0676, -0.1880,
         -0.2855, -0.1587,  0.0409,  0.0312],
        [ 0.1057,  0.1348, -0.0590, -0.1538,  0.2505,  0.0651, -0.2461, -0.1856,
          0.2498, -0.1969,  0.0013,  0.1979],
        [-0.1812,  0.1153,  0.2723, -0.2190,  0.0371, -0.0341,  0.2282,  0.1461,
          0.1890,  0.1762,  0.2657, -0.0827],
        [-0.0188,  0.0081, -0.2674, -0.1858,  0.1296,  0.1728, -0.0770,  0.1444,
         -0.2360, -0.1793,  0.1921, -0.2791]])), ('fc1.bias', tensor([-0.0020,  0.0985,  0.1859, -0.0175]))])
bn1.weight
tensor([1., 1., 1.])
False
bn1.bias
tensor([0., 0., 0.])
False
bn1.running_mean
tensor([0., 0., 0.])
False
bn1.running_var
tensor([1., 1., 1.])
False
bn1.num_batches_tracked
tensor(0)
False
fc1.weight
tensor([[ 0.0036,  0.1960,  0.2315, -0.2408,  0.1217,  0.2579, -0.0676, -0.1880,
         -0.2855, -0.1587,  0.0409,  0.0312],
        [ 0.1057,  0.1348, -0.0590, -0.1538,  0.2505,  0.0651, -0.2461, -0.1856,
          0.2498, -0.1969,  0.0013,  0.1979],
        [-0.1812,  0.1153,  0.2723, -0.2190,  0.0371, -0.0341,  0.2282,  0.1461,
          0.1890,  0.1762,  0.2657, -0.0827],
        [-0.0188,  0.0081, -0.2674, -0.1858,  0.1296,  0.1728, -0.0770,  0.1444,
         -0.2360, -0.1793,  0.1921, -0.2791]])
False
fc1.bias
tensor([-0.0020,  0.0985,  0.1859, -0.0175])
False
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

代码示例二

# model.state_dict()的用法
print(model.bn1.weight.requires_grad)
model.bn1.weight.requires_grad = False
print(model.bn1.weight.requires_grad)

for name, param in model.state_dict().items():
    if (name == "bn1.weight"):
        param.requires_grad = True

print(model.bn1.weight.requires_grad)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
True
False
False
  • 1
  • 2
  • 3
  • 4

代码示例三

# model.state_dict()的用法
print(model.bn1.weight)

for name, param in model.state_dict().items():
    if (name == "bn1.weight"):
        param[0] = 1000

print(model.bn1.weight)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
结果
(bbn) jyzhang@admin2-X10DAi:~/test$ python net.py
Parameter containing:
tensor([1., 1., 1.], requires_grad=True)
Parameter containing:
tensor([1000.,    1.,    1.], requires_grad=True)
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/260390?site
推荐阅读
相关标签
  

闽ICP备14008679号