PyTorch——nn.Parameter类


整体说明

  • nn.Parametertorch.Tensor 的一个子类,其定义方式如下:

    1
    2
    3
    class Parameter(torch.Tensor, metaclass=_ParameterMeta):
    """..."""
    def __init__ ...
  • nn.Parameter是最常用的模型参数类,其他许多高级封装的层(如nn.Linearnn.Conv2d等)都包含着nn.Parameter对象作为参数


torch.Tensor和nn.Parameter的却别

  • 两者主要区别是是否自动注册为模型参数,具体逻辑见下文:
    特性 nn.Parameter torch.Tensor
    是否自动注册为模型参数
    是否默认启用梯度计算 是 (requires_grad=True) 否 (requires_grad=False)
    是否被优化器自动更新 否(需手动添加到优化器)
    适用场景 可训练参数(如权重、偏置) 中间结果或固定值
  • 在构建神经网络时,通常使用 nn.Parameter 来定义可训练参数,而 torch.Tensor 更适合存储不需要训练的数据

是否自动注册为模型参数

  • nn.Parameter :

    • nn.Parameter 被赋值给 nn.Module 的属性时,它会自动注册为模型的可训练参数
    • 可以通过 model.parameters() 访问这些参数,优化器会自动更新它们
    • 示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      import torch.nn as nn

      class MyModel(nn.Module):
      def __init__(self):
      super(MyModel, self).__init__()
      self.weight = nn.Parameter(torch.randn(2, 2)) # 自动注册为模型参数

      def forward(self, x):
      return x @ self.weight

      model = MyModel()
      for param in model.parameters():
      print(param) # 可以访问到 self.weight

      # Parameter containing:
      # tensor([[-0.1866, 0.6549],
      # [-0.2559, -0.4768]], requires_grad=True)
  • torch.Tensor :

    • 直接使用 torch.Tensor 初始化的张量不会被自动注册为模型参数
    • 无法通过 model.parameters() 访问,优化器也不会更新它
    • 示例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      import torch.nn as nn

      class MyModel(nn.Module):
      def __init__(self):
      super(MyModel, self).__init__()
      self.weight = torch.randn(2, 2) # 只是一个普通的张量,不会注册为参数

      def forward(self, x):
      return x @ self.weight

      model = MyModel()
      for param in model.parameters():
      print(param) # 不会输出 self.weight

      # 无任何输出

是否支持自动梯度计算

  • nn.Parameter :

    • nn.Parametertorch.Tensor 的子类,默认启用梯度计算(requires_grad=True
    • 在反向传播时,PyTorch 会自动计算其梯度
  • torch.Tensor :

    • 默认情况下,torch.Tensorrequires_grad=False,不会计算梯度
    • 如果需要计算梯度,必须手动设置 requires_grad=True
    • 示例:
      1
      self.weight = torch.randn(2, 2, requires_grad=True)  # 手动启用梯度计算

优化器是否能更新

  • nn.Parameter :

    • 优化器可以通过 model.parameters() 获取 nn.Parameter 并更新其值
  • torch.Tensor :

    • 普通的 torch.Tensor 不会被优化器识别,除非手动将其添加到优化器的参数列表中
    • 示例:
      1
      optimizer = torch.optim.SGD([self.weight], lr=0.01)  # 手动添加到优化器

使用场景

  • nn.Parameter :

    • 适用于定义模型的可训练参数(如权重、偏置等)
    • 是构建神经网络时的标准做法
  • torch.Tensor :

    • 适用于存储不需要训练的中间结果或固定值(如常量张量)
    • 如果需要训练,必须手动设置 requires_grad=True 并注册到优化器

示例对比

  • 对比代码:
    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
    import torch
    import torch.nn as nn

    # 使用 nn.Parameter
    class ModelWithParameter(nn.Module):
    def __init__(self):
    super(ModelWithParameter, self).__init__()
    self.weight = nn.Parameter(torch.randn(2, 2)) # 自动注册为参数

    def forward(self, x):
    return x @ self.weight

    # 使用 torch.Tensor
    class ModelWithTensor(nn.Module):
    def __init__(self):
    super(ModelWithTensor, self).__init__()
    self.weight = torch.randn(2, 2, requires_grad=True) # 需要手动设置 requires_grad

    def forward(self, x):
    return x @ self.weight

    # 比较
    model1 = ModelWithParameter()
    print(list(model1.parameters())) # 输出: [Parameter containing...]

    model2 = ModelWithTensor()
    print(list(model2.parameters())) # 输出: []

nn.Linear和nn.Parameter的关系

  • nn.Parametertorch.Tensor 的子类,用于表示模型中的可训练参数,当它被赋值给 nn.Module 的属性时,会自动注册为模型参数,参与反向传播和优化

  • nn.Linear 内部包含两个 nn.Parameter,分别用于存储权重偏置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Linear(Module):
    """...comments..."""
    __constants__ = ['in_features', 'out_features']
    in_features: int
    out_features: int
    weight: Tensor
    def __init__(self, in_features: int, out_features: int, bias: bool = True,
    device=None, dtype=None) -> None:
    factory_kwargs = {'device': device, 'dtype': dtype}
    super(Linear, self).__init__()
    self.in_features = in_features
    self.out_features = out_features
    self.weight = Parameter(torch.empty((out_features, in_features), **factory_kwargs)) # Parameter定义
    if bias:
    self.bias = Parameter(torch.empty(out_features, **factory_kwargs)) # Parameter定义
    else:
    self.register_parameter('bias', None)
    self.reset_parameters()
  • 对上面代码的其他解读:

    • __constants__ = ['in_features', 'out_features']: __constants__ 是 PyTorch 的一个特殊属性,用于声明哪些属性是常量。这些常量在 TorchScript(PyTorch 的 JIT 编译器)中会被优化,并且不会保存在模型的 state_dict
    • in_features: int: 是一个类型注解,声明 in_features 是一个整数类型的类属性。它表示输入特征的数量,即输入向量的维度,这个注解的主要作用是提高代码的可读性和类型检查(例如,使用静态类型检查工具如 mypy
    • out_features: int: 同样是一个类型注解,声明 out_features 是一个整数类型的类属性。它表示输出特征的数量,即输出向量的维度,这个注解的主要作用是提高代码的可读性和类型检查
    • weight: Tensor: 是一个类型注解,声明 weight 是一个 Tensor 类型的类属性。weight 是线性层的权重矩阵,形状为 (out_features, in_features)。它会在 __init__ 方法中被初始化为一个可学习的参数(通过 torch.nn.Parameter 封装)

torch模型参数都是nn.Parameter类吗?

  • 在PyTorch中,模型参数通常是nn.Parameter类的实例,但并非所有模型中的可学习参数都必须是nn.Parameter

  • 模型中不是nn.Parameter类的一些特例和说明:

    • Buffer(缓冲区) :有些模型需要存储一些状态,但这些状态不是可学习的参数。这些状态可以通过register_buffer方法注册为缓冲区,而不是nn.Parameter。缓冲区不会被优化器更新,但会随模型一起保存和加载

      1
      self.register_buffer('running_mean', torch.zeros(num_features))
    • 非可学习参数 :有些参数虽然是模型的一部分,但不需要通过反向传播进行更新。这些参数可以是普通的torch.Tensor,而不是nn.Parameter

    • 自定义参数 :在某些情况下,开发者可能会手动管理参数,而不是使用nn.Parameter。例如,直接使用torch.Tensor并在需要时手动更新

    • 动态生成的临时变量 :在某些复杂的模型中,可能会有动态生成的参数或临时变量,这些可能不是nn.Parameter

    • 注:子模块中间接包含了nn.Parameter对象 :子模块(如nn.Linearnn.Conv2d等)中包含的nn.Parameter对象参数会自动被识别并注册为模型参数,开发者可以通过parameters()方法访问这些参数。