pytorch小记(二十五):全面解读 PyTorch 的 `unsqueeze`:任意位置插入一个长度为 1 的新维度


在深度学习与张量运算中,维度管理是一个常见且容易出错的环节。PyTorch 提供的 unsqueeze 操作,可以让你在张量的任意位置插入一个长度为 1 的新维度,实现批处理、通道对齐、广播扩展等需求。下面,我们从原理、API、示例到常见替代写法,带你深入理解 unsqueeze 的用法与场景。


一、unsqueeze 的核心作用

  • 在指定位置插入维度(长度为 1),张量的元素数不变,只是形状多了一个 1。
  • 返回的是视图(view),无数据拷贝,效率极高。

二、API 签名

# 函数式调用
torch.unsqueeze(input: Tensor, dim: int) → Tensor

# 方法式调用
Tensor.unsqueeze(self, dim: int) → Tensor
  • input / self:待操作的张量
  • dim:插入新维度的位置,整数,可为负数,范围 [-input.ndim-1, input.ndim]

正数 dim: 0 表示最前,input.ndim 表示最后;
负数 dim: -1 等同于最后插入,-input.ndim-1 等同于最前插入。


三、详细示例

我们用一段代码,一步步展示 unsqueeze 在不同维度上的效果,并打印形状与内容。

import torch

def print_info(t: torch.Tensor, name: str):
    print(f"{name:16s} shape={tuple(t.shape)}\n{t}\n")

# 1. 标量(0D 张量)
s = torch.tensor(5)
print_info(s, "s (0D)")

# 在最前面插入新维度 → (1,)
s0 = s.unsqueeze(0)
print_info(s0, "s.unsqueeze(0)")

# 在末尾插入新维度 → (1,)
s1 = s.unsqueeze(1)
print_info(s1, "s.unsqueeze(1)")

# 2. 一维向量(1D 张量)
v = torch.tensor([10, 20, 30])
print_info(v, "v (1D)")

# 插入批量维度 → (1,3)
v0 = v.unsqueeze(0)
print_info(v0, "v.unsqueeze(0)")

# 插入通道维度 → (3,1)
v1 = v.unsqueeze(1)
print_info(v1, "v.unsqueeze(1)")

# 3. 二维矩阵(2D 张量)
M = torch.arange(12).reshape(3, 4)
print_info(M, "M (2D)")

# 在行前插入 → (1,3,4)
M0 = M.unsqueeze(0)
print_info(M0, "M.unsqueeze(0)")

# 在列前插入 → (3,1,4)
M1 = M.unsqueeze(1)
print_info(M1, "M.unsqueeze(1)")

# 在第三维插入 → (3,4,1)
M2 = M.unsqueeze(2)
print_info(M2, "M.unsqueeze(2)")

输出示例:

s (0D)           shape=()
tensor(5)

s.unsqueeze(0)   shape=(1,)
tensor([5])

s.unsqueeze(1)   shape=(1,)
tensor([5])

v (1D)           shape=(3,)
tensor([10, 20, 30])

v.unsqueeze(0)   shape=(1, 3)
tensor([[10, 20, 30]])

v.unsqueeze(1)   shape=(3, 1)
tensor([[10],
        [20],
        [30]])

M (2D)           shape=(3, 4)
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])

M.unsqueeze(0)   shape=(1, 3, 4)
tensor([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]]])

M.unsqueeze(1)   shape=(3, 1, 4)
tensor([[[ 0,  1,  2,  3]],

        [[ 4,  5,  6,  7]],

        [[ 8,  9, 10, 11]]])

M.unsqueeze(2)   shape=(3, 4, 1)
tensor([[[ 0],
         [ 1],
         [ 2],
         [ 3]],

        [[ 4],
         [ 5],
         [ 6],
         [ 7]],

        [[ 8],
         [ 9],
         [10],
         [11]]])

四、常见应用场景

  1. 批量扩展

    • 将 C×H×W 的图像扩成 1×C×H×W,直接送入 BatchNorm 或卷积网络。
  2. 广播对齐

    • 在计算时,通过插入长度 1 的维度,让两个张量的 shape 对齐,实现自动广播。
  3. 矩阵批处理

    • 将 N×M 的矩阵转成 1×N×M,方便用 torch.bmm 做批量矩阵乘法。

五、替代写法

  • 索引插入:

    x = torch.randn(4,5)
    x2 = x[:, None, :]   # 等同 x.unsqueeze(1)
    
  • view/reshape:

    x = torch.randn(4,5)
    x3 = x.view(4,1,5)   # 需要手动列出完整 shape,不够灵活
    

六、小结

  • unsqueeze(dim) 在指定位置插入新维度,不改变数据,仅改变 shape。
  • 返回视图,性能高;常用于批次维度、通道维度插入,以及广播对齐。
  • 对于日常深度学习任务,掌握 unsqueeze 能让你在维度管理上更加游刃有余。

希望这篇文章能帮助你彻底搞懂 PyTorch 中的 unsqueeze,在项目中写出简洁、高效的张量变换代码!欢迎点赞、评论、分享~

更多推荐