1. reshape(重塑)

  • numpy和pytorch都有此操作,改变数组的形状(维度),但不改变底层数据的顺序

示例:

import numpy as np

# 原始数组:2x3 (6个元素)
arr = np.array([[1, 2, 3],
                [4, 5, 6]])
print(arr.shape) # (2, 3)

# 重塑为 3x2
reshaped = arr.reshape(3, 2)
print(reshaped)
# 输出:
# [[1 2]
#  [3 4]
#  [5 6]]
# 注意数据的顺序被保留了:1, 2, 3, 4, 5, 6。

2.transpose(转置)

2.1PyTorch 中:

transpose只能交换两个轴,permute可以任意重新排列所有轴

import torch

# 创建 4D 张量: (batch, channel, height, width) = (2, 3, 4, 5)
x = torch.randn(2, 3, 4, 5)

# transpose: 只能交换两个维度
y1 = x.transpose(1, 3)  # 形状: (2, 5, 4, 3)

2.2在numpy中:

对于 N 维数组,如果不指定 axes参数,transpose()会反转所有轴的顺序。

# 创建一个 2x3x4 的三维数组
arr_3d = np.arange(24).reshape(2, 3, 4)
print("原始三维数组形状:", arr_3d.shape)  # (2, 3, 4)

# 默认转置:反转轴顺序
default_transpose = np.transpose(arr_3d)
print("默认转置后的形状:", default_transpose.shape)  # (4, 3, 2)

通过 axes参数,可以精确控制每个轴的新位置。

# 原始数组形状为 (2, 3, 4)
# 轴索引:0, 1, 2

# 将轴重新排列为 (1, 2, 0)
transposed_custom = np.transpose(arr_3d, (1, 2, 0))
print("自定义转置后的形状:", transposed_custom.shape)  # (3, 4, 2)

# 将轴重新排列为 (2, 0, 1)
transposed_custom2 = np.transpose(arr_3d, (2, 0, 1))
print("另一种自定义转置后的形状:", transposed_custom2.shape)  # (4, 2, 3)

3.Permute(置换/重排轴)

  •  只在pytorch中有,numpy没有此操作,是transpose的通用形式。它允许你任意指定轴的新顺序

# 原始3D数组:形状 (2, 3, 4)
# 可以理解为 (深度, 高度, 宽度)
arr_3d = np.random.rand(2, 3, 4)
print(arr_3d.shape) # (2, 3, 4)

# 我们想要新形状为 (高度, 宽度, 深度) -> (3, 4, 2)
# 原来的轴索引是:0(深度), 1(高度), 2(宽度)
# 我们想要的新顺序是:(1, 2, 0)
permuted = np.transpose(arr_3d, (1, 2, 0)) # 在NumPy中使用transpose指定轴顺序
print(permuted.shape) # (3, 4, 2)

# 在 PyTorch 中,有专门的 permute() 函数:
# tensor.permute(1, 2, 0)

4.view

view是 PyTorch 中特有的方法,NumPy 中没有直接对应的方法。它是形状变换操作,功能与 reshape类似

import torch

# 创建一个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])
print("原始形状:", x.shape)  # torch.Size([2, 3])

# 使用 view 改变形状
x_view = x.view(3, 2)  # 变为 3x2
print("view后形状:", x_view.shape)  # torch.Size([3, 2])

# 也可以使用 -1 自动计算维度大小
x_auto = x.view(-1)  # 展平为一维
print("自动展平:", x_auto.shape)  # torch.Size([6])

x_auto2 = x.view(2, -1)  # 保持第一维为2,自动计算第二维
print("自动计算:", x_auto2.shape)  # torch.Size([2, 3])

但是view 要求张量在内存中是连续的

# view 要求张量在内存中是连续的
x = torch.tensor([[1, 2, 3], [4, 5, 6]])

# 转置操作会使张量不连续
x_t = x.t()  # 转置
print("转置后是否连续:", x_t.is_contiguous())  # False

# 使用 view 会报错
try:
    x_t.view(3, 2)  # 错误!因为转置后的张量不连续
except RuntimeError as e:
    print("view 错误:", e)

# 使用 reshape 可以正常工作
x_reshaped = x_t.reshape(3, 2)  # 正常
print("reshape 成功:", x_reshaped.shape)

常见用法

# 在神经网络中常见用法
batch_size, seq_len, hidden_size = 32, 10, 128
x = torch.randn(batch_size, seq_len, hidden_size)

# 将序列长度和批次维度合并,用于全连接层
x_reshaped = x.view(batch_size * seq_len, hidden_size)
print("合并批次和序列:", x_reshaped.shape)  # torch.Size([320, 128])

# 处理后再恢复原始形状
output = x_reshaped.view(batch_size, seq_len, -1)
print("恢复形状:", output.shape)  # torch.Size([32, 10, 128])

5.squeeze和 unsqueeze

unsqueeze- 添加维度

import torch

# 创建一个 1D 张量
x = torch.tensor([1, 2, 3])
print("原始形状:", x.shape)  # torch.Size([3])

# 在不同位置添加维度
x_0 = x.unsqueeze(0)  # 在维度0添加
x_1 = x.unsqueeze(1)  # 在维度1添加
x_neg1 = x.unsqueeze(-1)  # 在最后一个维度添加

print("unsqueeze(0):", x_0.shape)  # torch.Size([1, 3])
print("unsqueeze(1):", x_1.shape)  # torch.Size([3, 1])
print("unsqueeze(-1):", x_neg1.shape)  # torch.Size([3, 1])

#实际应用
# 广播操作:让两个张量形状匹配以便进行运算
a = torch.randn(3, 4)      # 形状: (3, 4)
b = torch.randn(4)         # 形状: (4,)

# 需要将 b 从 (4,) 变为 (1, 4) 或 (4, 1) 才能与 a 运算
b_expanded = b.unsqueeze(0)  # 形状: (1, 4)
result = a + b_expanded    # 可以广播为 (3, 4)
print("广播结果形状:", result.shape)  # torch.Size([3, 4])

squeeze- 移除维度

# 创建一个有多个大小为1的维度的张量
x = torch.randn(1, 3, 1, 4, 1)
print("原始形状:", x.shape)  # torch.Size([1, 3, 1, 4, 1])

# 移除所有大小为1的维度
x_squeezed = x.squeeze()
print("squeeze():", x_squeezed.shape)  # torch.Size([3, 4])

# 移除指定位置的大小为1的维度
x_squeeze_0 = x.squeeze(0)  # 移除第0维
print("squeeze(0):", x_squeeze_0.shape)  # torch.Size([3, 1, 4, 1])

x_squeeze_2 = x.squeeze(2)  # 移除第2维
print("squeeze(2):", x_squeeze_2.shape)  # torch.Size([1, 3, 4, 1])

# 如果指定维度大小不为1,则不变
x_squeeze_1 = x.squeeze(1)  # 第1维大小为3,不会移除
print("squeeze(1):", x_squeeze_1.shape)  # torch.Size([1, 3, 1, 4, 1]) - 不变

NumPy 中没有直接的 unsqueeze/squeeze,但有等效操作

import numpy as np

# NumPy 中的等效操作
arr = np.random.rand(3, 1, 4)

# squeeze 等效
arr_squeezed = np.squeeze(arr)  # 形状: (3, 4)
arr_squeezed_axis = np.squeeze(arr, axis=1)  # 形状: (3, 4)

# unsqueeze 等效
arr_expanded = np.expand_dims(arr, axis=0)  # 形状: (1, 3, 1, 4)
arr_expanded2 = arr[:, np.newaxis, :, :]  # 另一种方法

更多推荐