Hexo

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

PyTorch——nn.Parameter类


整体说明

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

    1
    2
    3
    class Parameter(torch.Tensor, metaclass=_ParameterMeta):
    """..."""
    def __init__ ...
  • nn.Parameter是最常用的模型参数类,其他许多高级封装的层(如nn.Linear和nn.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.Parameter 是 torch.Tensor 的子类,默认启用梯度计算(requires_grad=True)
    • 在反向传播时,PyTorch 会自动计算其梯度
  • torch.Tensor :

    • 默认情况下,torch.Tensor 的 requires_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.Parameter 是 torch.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.Linear、nn.Conv2d等)中包含的nn.Parameter对象参数会自动被识别并注册为模型参数,开发者可以通过parameters()方法访问这些参数。

PyTorch——PyTorch中的高级索引


整体说明

  • PyTorch 的高级索引操作允许以非常灵活和强大的方式选择和修改张量中的元素
  • 高级索引包括整数索引、切片(slicing)、布尔索引和整数数组索引等
  • PyTorch 中的索引使用(包括基础索引和高级索引)和 Numpy 中基本一致
  • 可用于选择元素,也可以用于修改元素
  • 高级索引一般不共享存储区(普通索引一般共享存储区)
    • 普通索引一般可以通过修改 Tensor 的偏移量(offset)、步长(stride)或形状实现,不需要修改存储区的数据(使用共享存储区可以节省内存和处理速度)
    • 高级索引则一般都是不规则的变化 ,需要修改存储区,故而不使用共享存储区
    • 这也是高级索引与切片的最大差别
  • 检索维度匹配要求 :多个索引数组的维度必须能够广播成一致的形状,否则报错
  • 高级索引的判定方式:
    • 在 PyTorch 中,当索引对象是一个非元组序列对象、一个 Tensor(数据类型为整数或布尔,在 NumPy 中为 ndarray),或一个至少包含一个序列对象或 Tensor(数据类型为整数或布尔,在 NumPy 中为 ndarray)的元组时,会触发高级索引判定

基础索引回顾

  • 在深入高级索引之前,我们先快速回顾一下基础索引:
    • 单个整数索引 : 选取特定位置的单个元素
    • 切片 : 选取连续的子范围。例如 a[start:end:step]
    • 省略号 (...) : 表示选择所有剩余的维度
      • 这在张量维度较多时非常有用,可以避免写出冗长的 :
  • 基础索引的 Demo:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import torch
    a = torch.arange(27).reshape(3, 3, 3)
    print("原始张量 a:\n", a)
    # 输出:
    # tensor([[[ 0, 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]]])

    print("a[0, 1, 2]:", a[0, 1, 2]) # 输出:tensor(5)(第一个维度第0个,第二个维度第1个,第三个维度第2个)
    print("a[1, :, 0]:\n", a[1, :, 0]) # 输出:tensor([ 9, 12, 15])(第一个维度第1个,第二个维度所有,第三个维度第0个)
    print("a[..., 1]:\n", a[..., 1]) # 选取所有维度,最后一个维度第1个,等价于 a[:,:,1]
    # 输出:
    # tensor([[ 1, 4, 7],
    # [10, 13, 16],
    # [19, 22, 25]])

高级索引-整数数组索引 (Integer Array Indexing)

  • 当使用 torch.Tensor (类型为 torch.long 或 torch.int) 或 Python 列表作为索引时,这被称为整数数组索引(高级索引的一种)

    • 第一步:广播 : 如果有多个整数数组索引,并且它们的形状不同,PyTorch 会尝试对它们进行广播(broadcasting),广播为相同形状
    • 第二步:返回结果 : 整数数组索引的返回张量的形状由广播后的索引张量的形状决定 ,当部分维度没有被索引时,默认保留该维度的所有值
  • 示例 1 : 在一个维度上使用整数数组索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import torch

    a = torch.arange(12).reshape(3, 4)
    print("原始张量 a:\n", a)
    # 输出:
    # tensor([[ 0, 1, 2, 3],
    # [ 4, 5, 6, 7],
    # [ 8, 9, 10, 11]])

    # 选取第0行和第2行
    indices = torch.tensor([0, 2])
    result = a[indices]
    print("\na[torch.tensor([0, 2])]:\n", result)
    # 输出:
    # tensor([[ 0, 1, 2, 3],
    # [ 8, 9, 10, 11]])

    # 选取第1列和第3列
    result = a[:, torch.tensor([1, 3])]
    print("\na[:, torch.tensor([1, 3])]:\n", result)
    # 输出:
    # tensor([[ 1, 3],
    # [ 5, 7],
    # [ 9, 11]])
  • 示例 2: 在多个维度上使用整数数组索引(“坐标”式选择)

    • 注:当你在多个维度上同时使用整数数组索引时,它们会被解释为坐标对(这与 NumPy 的行为非常相似)
      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
      import torch

      a = torch.arange(12).reshape(3, 4)
      print("原始张量 a:\n", a)

      # 选取 (0, 1), (1, 3), (2, 0) 这些位置的元素
      row_indices = torch.tensor([0, 1, 2])
      col_indices = torch.tensor([1, 3, 0])
      result = a[row_indices, col_indices]
      print("\na[torch.tensor([0, 1, 2]), torch.tensor([1, 3, 0])]:", result)
      # 解释:
      # 结果的第一个元素是 a[0, 1]
      # 结果的第二个元素是 a[1, 3]
      # 结果的第三个元素是 a[2, 0]
      # 输出: tensor([ 1, 7, 8])

      # 索引张量形状不一致时会进行广播
      a = torch.arange(27).reshape(3, 3, 3)
      print("\n原始张量 a (3x3x3):\n", a)

      # 选取多个坐标,例如:
      # 维度0取索引0和2
      # 维度1取索引1和2
      # 维度2取索引0和1
      idx0 = torch.tensor([[0], [2]]) # shape (2, 1)
      idx1 = torch.tensor([1, 2]) # shape (2,)
      idx2 = torch.tensor([0, 1]) # shape (2,)

      # PyTorch 会尝试广播这些索引
      # idx0: [[0], [2]] -> 广播为 [[0, 0], [2, 2]] (因为 idx1 和 idx2 的大小是2)
      # idx1: [1, 2] -> 广播为 [[1, 2], [1, 2]]
      # idx2: [0, 1] -> 广播为 [[0, 1], [0, 1]]

      # 最终会选择以下坐标的元素:
      # (0, 1, 0), (0, 2, 1)
      # (2, 1, 0), (2, 2, 1)
      result = a[idx0, idx1, idx2]
      print("\na[idx0, idx1, idx2]:\n", result)
      # 输出:
      # tensor([[ 3, 5], # a[0,1,0], a[0,2,1]
      # [21, 23]]) # a[2,1,0], a[2,2,1]

布尔索引 (Boolean Indexing)

  • 当使用一个布尔张量作为索引时,PyTorch 会选择布尔张量中值为 True 的所有元素
    • 形状要求 :布尔张量的形状必须与被索引张量的一个或多个维度匹配
    • 返回结果 :布尔张量索引的结果张量通常是 1 维的张量,包含所有满足条件(True)的元素
    • 特别说明:布尔张量通常被称为“掩码”
  • 布尔张量的 Demo:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import torch

    a = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print("原始张量 a:\n", a)

    # 选取所有大于 5 的元素
    mask = a > 5
    print("\n布尔掩码 (a > 5):\n", mask)
    # 输出:
    # tensor([[False, False, False],
    # [False, False, True],
    # [ True, True, True]])

    result = a[mask]
    print("\na[a > 5]:", result)
    # 输出: tensor([6, 7, 8, 9])
    # 注意以上输出是 1 维的

混合索引操作:a[index1, :, index2] 和 a[index1, index2, :]

  • 特别说明广播机制:当索引数组的维度不匹配时,PyTorch 会尝试运用广播规则来使它们的维度变得兼容,即使混合索引也适用,详情如下:

    1
    2
    3
    4
    5
    # 行索引是[0, 2],列索引对所有行都是0
    rows = torch.tensor([0, 2]) # 形状为(2,)
    cols = torch.tensor([0]) # 形状为(1,)
    result = a[rows, :, cols] # 广播后形状变为(2, 3, 1)
    print(result.shape) # 输出: torch.Size([2, 3, 1])
  • 关于索引后的形状:

    • 若高级索引没被隔离,则正常覆盖高级索引所在的维度区域
    • 若高级索引被隔离,则对齐维度后,高级索引需要合并,并放到最前面(注意:不是第一个高级索引所在的位置,而是从第 0 维开始的最前面几维)
  • 这种索引方式是在多个维度上混合使用高级索引和切片操作

    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
    50
    51
    52
    53
    54
    import torch
    a = torch.arange(27).reshape(3, 3, 3)
    print(a)
    # 输出:
    # tensor([[[ 0, 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]]])

    index1 = torch.tensor([[0, 2]]) # 使用 [[0,2]] 也可以
    index2 = torch.tensor([[0]]) # 1)使用 [[0]] 也可以;2)[0] 也可以得到相同结果,因为广播后结果是一样的
    result = a[index1, index2, :]
    print(result.shape) # 输出: torch.Size([1, 2, 3])
    print(result)
    # 输出:
    # tensor([[[ 0, 1, 2],
    # [18, 19, 20]]])
    # 理解:index1和index2广播以后是shape=[1,2],结果中,第0,1维的[3,3]会被[1,2]替换

    index1 = torch.tensor([[0, 2]]) # 使用 [[0,2]] 也可以
    index2 = torch.tensor([[0]]) # 1)使用 [[0]] 也可以;2)[0] 也可以得到相同结果,因为广播后结果是一样的
    result = a[index1, :, index2]
    print(result.shape) # 输出: torch.Size([1, 2, 3])
    print(result)
    # 输出:
    # tensor([[[ 0, 3, 6],
    # [18, 21, 24]]])
    # 理解:相当于先调用 a.transpose_(2,1) 对齐索引维度,然后再调用 a[index1,index2,:],因为 高级索引需要合并到一起去广播并放到最前面
    # # 也可以用permute替代transpose,但permute不能inplace
    # 测试下面的代码替换 result = a[index1, :, index2] 后与上述输出一致
    # a.transpose_(2,1)
    # result = a[index1, index2, :]


    index1 = torch.tensor([0, 2])
    index2 = torch.tensor([0, 2])
    result = a[index1, :, index2]
    print(result.shape) # 输出: torch.Size([2, 3])
    print(result)
    # 输出:
    # tensor([[[ 0, 3, 6],
    # [20, 23, 26]]])
    # tensor([[ 0, 3, 6],
    # [20, 23, 26]])
    # 理解1:index1和index2广播以后是shape=[2],结果中,第0,1维的[3,3]会被[2]替换
    # 理解2:相当于先调用 a.transpose_(2,1) 对齐索引维度,然后再调用 a[index1,index2,:],因为 高级索引需要合并到一起去广播并放到最前面
    # 说明:已经测试下面的代码替换 result = a[index1, :, index2] 后与上述输出一致
    # a.transpose_(2,1)
    # result = a[index1, index2, :]
  • 高级索引被隔离的补充实验 Demo:

    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
    import torch
    a = torch.arange(3*4*5*6).reshape(3, 4, 5, 6)
    # print(a)

    index1 = torch.tensor([[0, 2]])
    index2 = torch.tensor([[0, 2]])
    result = a[:, index1, :, index2]
    print(result.shape) # 输出:torch.Size([1, 2, 3, 3])
    print(result)
    # 输出:
    # tensor([[[[ 0, 6, 12, 18, 24],
    # [120, 126, 132, 138, 144],
    # [240, 246, 252, 258, 264]],
    #
    # [[ 62, 68, 74, 80, 86],
    # [182, 188, 194, 200, 206],
    # [302, 308, 314, 320, 326]]]])

    index1 = torch.tensor([[0, 2]])
    index2 = torch.tensor([[0, 2]])
    a = a.permute(1,3,0,2)
    result = a[index1,index2,:,:]
    print(result.shape) # 输出:torch.Size([1, 2, 3, 3])
    print(result)
    # 输出:
    # tensor([[[[ 0, 6, 12, 18, 24],
    # [120, 126, 132, 138, 144],
    # [240, 246, 252, 258, 264]],
    #
    # [[ 62, 68, 74, 80, 86],
    # [182, 188, 194, 200, 206],
    # [302, 308, 314, 320, 326]]]])

    # 理解1:高级索引index1和index2被基础索引隔断了,index1和index2广播后为shape=[1,2],然后高级索引的维度会替换所在维度的[3,3]后放到最前面
    # 理解2:相当于先执行 a = a.permute(1,3,0,2)(注意permute操作不能inplace),然后再执行 result = a[index1,index2,:,:]
    # 测试说明:从上面的代码输出可以看到,result = a[:, index1, :, index2] 替换为下面语句后,结果一致:
    # a = a.permute(1,3,0,2)
    # result = a[index1,index2,:,:]

附录:高级索引的一些常见用法

批量数据选择

  • 在处理批量数据时,可以利用高级索引为每个样本选择不同的元素
    1
    2
    3
    4
    5
    6
    7
    8
    batch_size = 4
    features = 10
    data = torch.randn(batch_size, features)

    # 为每个样本选择不同的特征
    indices = torch.tensor([2, 5, 1, 8]) # 为4个样本分别选择第2、5、1、8个特征
    selected = data[torch.arange(batch_size), indices]
    print(selected.shape) # 输出: torch.Size([4])

并行更新

  • 借助高级索引,能够并行地更新张量中的多个位置
    1
    2
    3
    4
    5
    6
    7
    x = torch.zeros(5, 5)
    rows = torch.tensor([0, 1, 2])
    cols = torch.tensor([1, 2, 3])
    values = torch.tensor([10, 20, 30])

    x[rows, cols] = values # 将(0,1)、(1,2)、(2,3)位置的值分别更新为10、20、30
    print(x)

附录:高级索引出发条件总结

  • 在 PyTorch 中,当索引对象是一个非元组序列对象、一个 Tensor(数据类型为整数或布尔,在 NumPy 中为 ndarray),或一个至少包含一个序列对象或 Tensor(数据类型为整数或布尔,在 NumPy 中为 ndarray)的元组时,会触发高级索引判定

  • 以下是会触发高级索引判定的情况

  • 索引对象为单个高维数组或张量 :索引对象不是一个元组序列,而是一个高维数组或者张量,其中布尔型比整数型更常见

    • 举例:

      1
      2
      x = torch.arange(24)
      y = x.reshape(6, 4)[x.reshape(6, 4) > 10] # y.shape = torch.Size([13]),以为数组
    • 这里 torch.arange(24) > 10 是布尔型张量,会触发高级索引

  • 索引对象为整数型数组或张量组成的元组序列 :索引对象是一个元组序列,并且元组序列完全由整数型高维数组或者整数型张量组成

    • 举例:

      1
      2
      3
      4
      x = torch.randn(3, 4)
      rows = torch.tensor([0, 2])
      cols = torch.tensor([1, 3])
      y = x[(rows, cols)] # y.shape = torch.Size([2])
    • 其中 (rows, cols) 构成的元组序列就是由整数型张量组成,会触发高级索引

  • 索引对象为列表序列组成的元组序列 :索引对象是一个元组序列,并且元组序列完全由列表序列组成

    • 举例:

      1
      2
      x = torch.randn(3, 4)
      y = x[([0, 2], [1, 3])] # y.shape = torch.Size([2])
    • 这里 ([0, 2], [1, 3]) 是由 列表序列组成的元组 ,会触发高级索引

  • 索引对象为混合组成的元组序列(包含数组或张量与序列对象) :索引对象是一个元组序列,元组序列不仅包含高维整数型数组或者高维整数型张量,还包括序列对象

    • 举例:

      1
      2
      3
      x = torch.randn(3, 4)
      rows = torch.tensor([0, 2])
      y = x[(rows, [1, 3])] # y.shape = torch.Size([2])
    • 此元组序列中既有整数型张量rows,又有列表[1, 3],会触发高级索引

  • 索引对象为混合组成的元组序列(包含数组或张量与整数标量) :索引对象是一个元组序列,元组序列不仅包含高维整数型数组或者高维整数型张量,还包括整数标量

    • 举例:

      1
      2
      3
      x = torch.randn(3, 4)
      rows = torch.tensor([0, 2])
      y = x[(rows, 2)] # y.shape = torch.Size([2])
    • 元组序列中包含整数型张量 rows 和整数标量2,会触发高级索引

  • 索引对象为混合组成的元组序列(包含数组、张量、标量和序列对象) :索引对象是一个元组序列,元组序列包含高维整数型数组或者高维整数型张量、整数标量和序列对象

    • 举例:

      1
      2
      3
      x = torch.randn(3, 4, 5)
      rows = torch.tensor([0, 2])
      y = x[(rows, 2, [1, 3])] # y.shape = torch.Size([2])
    • 这种情况同样会触发高级索引

1…199200201…352
San Ye

San Ye

Stay Hungry. Stay Foolish.

704 posts
53 tags
© 2026 San Ye
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4