深度学习中常用到的矩阵变换操作,reshape,transpose,permute,view,squeeze和 unsqueeze
·
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, :, :] # 另一种方法
更多推荐


所有评论(0)