介绍
PyTorch 中张量的 .unsqueeze() 方法,是给张量(Tensor)增加一个维度,在深度学习中非常常用,比如匹配维度、批量处理数据时都会用到。
PyTorch 也支持 torch.unsqueeze(x, dim) 写法,和 x.unsqueeze(dim) 效果完全一致。
语法
在指定的 dim 维度位置,给张量新增一个大小为 1 的维度。
unsqueeze(dim)
dim 的取值规则
dim可以是正数:从 0 开始,对应张量的第dim个维度前插入新维度;dim可以是负数:从 -1 开始(表示最后一个维度),比如对 shape [3] 的张量,dim=-1等价于dim=1,dim=-2等价于dim=0;- 取值范围:
[-len(shape)-1, len(shape)],超出会报错。
返回值
返回新张量
注意
unsqueeze()返回新张量,不会修改原张量(除非用inplace版本unsqueeze_());- 新增维度的大小始终是 1,不会改变张量的元素总数;
例子
import torch
# 原始张量:一维,shape [3]
x = torch.tensor([1, 2, 3])
print("原始张量 x:", x)
print("原始 shape:", x.shape) # 输出 torch.Size([3])
# 在维度 0 处增加维度:shape [1, 3]
x_0 = x.unsqueeze(0)
print("\nunsqueeze(0) 后:", x_0)
print("shape:", x_0.shape) # 输出 torch.Size([1, 3])
# 在维度 1 处增加维度:shape [3, 1]
x_1 = x.unsqueeze(1)
print("\nunsqueeze(1) 后:", x_1)
print("shape:", x_1.shape) # 输出 torch.Size([3, 1])
输出结果:
原始张量 x: tensor([1, 2, 3])
原始 shape: torch.Size([3])
unsqueeze(0) 后: tensor([[1, 2, 3]])
shape: torch.Size([1, 3])
unsqueeze(1) 后: tensor([[1],
[2],
[3]])
shape: torch.Size([3, 1])
多维张量的例子
# 二维张量:shape [2, 3]
y = torch.tensor([[1,2,3], [4,5,6]])
print("原始 shape:", y.shape) # torch.Size([2, 3])
# 在维度 1 处插入维度:shape [2, 1, 3]
y_1 = y.unsqueeze(1)
print("unsqueeze(1) shape:", y_1.shape) # torch.Size([2, 1, 3])
使用场景
匹配张量维度(广播机制)
当两个张量维度不匹配但需要运算时,用 unsqueeze() 增加维度实现广播:
a = torch.tensor([1, 2, 3]) # shape [3]
b = torch.tensor([[4], [5], [6]]) # shape [3, 1]
# a 先 unsqueeze(0) 变成 [1, 3],再和 b 相加(广播)
c = a.unsqueeze(0) + b
print(c)
# 输出:
# tensor([[5, 6, 7],
# [6, 7, 8],
# [7, 8, 9]])
批量处理单条数据
模型输入通常要求「批量维度(batch dim)」,单条数据需要增加 batch 维度(dim=0):
# 单张图片:shape [3, 224, 224](通道、高、宽)
img = torch.randn(3, 224, 224)
# 增加 batch 维度:shape [1, 3, 224, 224]
img_batch = img.unsqueeze(0)
# 此时可传入要求批量输入的模型
# model(img_batch)
和 squeeze() 配合使用
squeeze() 是 unsqueeze() 的逆操作,用于删除大小为 1 的维度:
x = torch.tensor([[1,2,3]]) # shape [1, 3]
x_squeeze = x.squeeze(0) # 删除 dim=0 的维度,shape [3]
print(x_squeeze.shape) # torch.Size([3])
总结
unsqueeze(dim)核心作用是在指定维度位置给张量新增一个大小为 1 的维度;- 常用场景:匹配维度实现广播、给单条数据增加 batch 维度;
dim支持正负索引,取值需在合法范围,且操作不改变原张量(除非用unsqueeze_())。