PyTorch 预备知识

1. 版本检查

官网 下载好后,可以按照如下进行版本检查。

  1. import torch
  2.  
  3. print(torch.__version__)

本地输出:

  • 2.4.0+cu124

2. 张量

在 PyTorch 中,基本的数据结构是张量。张量是一个可以包含单一数据类型元素的多维数组。像标量、向量、矩阵都可以看作是张量的特殊形式。

  1. import torch
  2.  
  3. # 创建标量
  4. scalar = torch.tensor(6)
  5. print("标量:", scalar)
  6. print("标量的维度:", scalar.ndim)
  7. print("标量的值:", scalar.item())
  8.  
  9. # 创建向量
  10. vector = torch.tensor([6, 6])
  11. print("\n向量:", vector)
  12. print("向量的维度:", vector.ndim)
  13. print("向量的形状:", vector.shape)
  14.  
  15. # 创建矩阵
  16. matrix = torch.tensor([[7, 8], [9, 10]])
  17. print("\n矩阵:\n", matrix)
  18. print("矩阵的维度:", matrix.ndim)
  19. print("矩阵的第一行:", matrix[0])
  20. print("矩阵的形状:", matrix.shape)
  21.  
  22. # 创建更高维度的张量
  23. tensor = torch.tensor([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
  24. print("\n更高维度的张量:\n", tensor)
  25. print("张量的维度:", tensor.ndim)
  26. print("张量的形状:", tensor.shape)
  27. print("张量的第一个元素(矩阵):\n", tensor[0])

本地输出:

  • 标量: tensor(6)
  • 标量的维度: 0
  • 标量的值: 6
  •  
  • 向量: tensor([6, 6])
  • 向量的维度: 1
  • 向量的形状: torch.Size([2])
  •  
  • 矩阵:
  •  tensor([[ 7,  8],
  •         [ 9, 10]])
  • 矩阵的维度: 2
  • 矩阵的第一行: tensor([7, 8])
  • 矩阵的形状: torch.Size([2, 2])
  •  
  • 更高维度的张量:
  •  tensor([[[1, 2, 3],
  •          [4, 5, 6],
  •          [7, 8, 9]]])
  • 张量的维度: 3
  • 张量的形状: torch.Size([1, 3, 3])
  • 张量的第一个元素(矩阵):
  •  tensor([[1, 2, 3],
  •         [4, 5, 6],
  •         [7, 8, 9]])

张量的维度,从打印的形式上看,是最外层括号的数量。

3. 随机张量

可以使用 torch.rand 创建指定维度的随机张量。

  1. import torch
  2.  
  3. # 生成一个三维的随机张量
  4. random_tensor = torch.rand(2, 3, 4)
  5. print("三维随机张量:\n", random_tensor)
  6. print("张量的维度:", random_tensor.ndim)
  7.  
  8. # 生成一个用于模拟图像数据的张量
  9. random_image_size_tensor = torch.rand(224, 224, 3)
  10. print("\n模拟图像数据的随机张量形状:", random_image_size_tensor.shape)

本地输出:

  • 三维随机张量:
  •  tensor([[[0.2388, 0.8346, 0.5911, 0.5230],
  •          [0.3957, 0.8030, 0.3961, 0.5112],
  •          [0.4403, 0.4927, 0.4487, 0.5864]],
  •  
  •         [[0.6315, 0.8137, 0.6968, 0.7826],
  •          [0.3713, 0.5496, 0.9892, 0.7417],
  •          [0.9595, 0.9671, 0.1762, 0.4017]]])
  • 张量的维度: 3
  •  
  • 模拟图像数据的随机张量形状: torch.Size([224, 224, 3])

三维张量感觉抽象的话,可以结合图像来理解:三个维度分别对应宽、高和 RGB 值。

4. 零张量和单位张量

可以使用 torch.zeros 创建一个所有元素都为 0 的张量;使用 torch.ones 创建一个所有元素都为 1 的张量。

  1. import torch
  2.  
  3. zeros = torch.zeros(size=(3, 4))
  4. print("零张量:\n", zeros)
  5.  
  6. ones = torch.ones(size=(3, 4))
  7. print("单位张量:\n", ones)

本地输出:

  • 零张量:
  •  tensor([[0., 0., 0., 0.],
  •         [0., 0., 0., 0.],
  •         [0., 0., 0., 0.]])
  • 单位张量:
  •  tensor([[1., 1., 1., 1.],
  •         [1., 1., 1., 1.],
  •         [1., 1., 1., 1.]])

5. 其他创建张量方式

torch.arange 可以生成一个等间隔数值的一维张量。

torch.zeros_like 可以根据给定的张量生成一个新的零张量,新张量的形状和数据类型与输入张量相同。

  1. import torch
  2.  
  3. one_to_ten = torch.arange(start=1, end=11, step=1)
  4. print("1到10的整数张量:", one_to_ten)
  5.  
  6. ten_zeros = torch.zeros_like(input=one_to_ten)
  7. print("形状相同的零张量:", ten_zeros)

本地输出:

  • 1到10的整数张量: tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
  • 形状相同的零张量: tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

6. 数据类型

创建的张量,默认使用 float32 类型。可以使用 type() 方法,将张量从一种数据类型转换成另一种。

不同类型之间的张量进行操作,如果能成功,PyTorch 会自动选择更高精度的数据类型,作为结果数据类型。

  1. import torch
  2.  
  3. float_32_tensor = torch.tensor([3.0, 6.0, 9.0])
  4. print("原始张量数据类型:", float_32_tensor.dtype)
  5.  
  6. float_16_tensor = float_32_tensor.type(torch.float16)
  7. print("转换为float16的张量:", float_16_tensor)
  8.  
  9. # 结果张量的数据类型将遵循更精确的类型(这里是float32)
  10. result_tensor = float_32_tensor * float_16_tensor
  11. print("乘法结果张量:", result_tensor)

本地输出:

  • 原始张量数据类型: torch.float32
  • 转换为float16的张量: tensor([3., 6., 9.], dtype=torch.float16)
  • 乘法结果张量: tensor([ 9., 36., 81.])

7. 张量属性

张量的这三个属性很重要:数据类型(dtype)、形状(shape)和设备(device)。

  1. import torch
  2.  
  3. some_tensor = torch.rand(3, 4)
  4.  
  5. print("随机张量:\n", some_tensor)
  6. print(f"张量的数据类型: {some_tensor.dtype}")
  7. print(f"张量的形状: {some_tensor.shape}")
  8. print(f"张量所在的设备: {some_tensor.device}")

本地输出:

  • 随机张量:
  •  tensor([[0.2504, 0.5435, 0.1293, 0.9244],
  •         [0.4105, 0.0778, 0.7599, 0.5284],
  •         [0.7450, 0.4227, 0.0662, 0.6182]])
  • 张量的数据类型: torch.float32
  • 张量的形状: torch.Size([3, 4])
  • 张量所在的设备: cpu

8. 张量运算

张量的基本算术运算:加法(+torch.add);减法(-torch.sub);乘法(*torch.multiply);除法(/torch.div)。以上这些运算都是逐元素的。

乘法有点不同,还有一个矩阵乘法,使用 @torch.matmul

  1. import torch
  2.  
  3. tensor = torch.tensor([1, 2, 3])
  4. print("张量:", tensor)
  5.  
  6. # 张量与标量的加法(逐元素)
  7. print("\n每个元素加 10 :", tensor + 10)
  8. print("使用 torch.add:", torch.add(tensor, 10))
  9.  
  10. # 乘法(逐元素)
  11. print("\n每个元素乘以 10:", tensor * 10)
  12. print("使用 torch.multiply:", torch.multiply(tensor, 10))
  13. print("张量与张量的乘法:", tensor * tensor)
  14.  
  15. # 张量的矩阵乘法
  16. print("\n张量的矩阵乘法:", torch.matmul(tensor, tensor))
  17. print("使用@符号:", tensor @ tensor)

本地输出:

  • 张量: tensor([1, 2, 3])
  •  
  • 每个元素加 10 : tensor([11, 12, 13])
  • 使用 torch.add: tensor([11, 12, 13])
  •  
  • 每个元素乘以 10: tensor([10, 20, 30])
  • 使用 torch.multiply: tensor([10, 20, 30])
  • 张量与张量的乘法: tensor([1, 4, 9])
  •  
  • 张量的矩阵乘法: tensor(14)
  • 使用@符号: tensor(14)

9. 转置

可用使用张量的 .T 属性进行矩阵转置。

  1. import torch
  2.  
  3. tensor_A = torch.tensor([[1, 2],
  4.                          [3, 4],
  5.                          [5, 6]])
  6. tensor_B = torch.tensor([[7, 8],
  7.                          [9, 10],
  8.                          [11, 12]])
  9.  
  10. print("张量 A:\n", tensor_A)
  11. print("张量 B:\n", tensor_B)
  12.  
  13. result = torch.mm(tensor_A, tensor_B.T)
  14. print("A * B^T:\n", result)

torch.mm 也是矩阵乘法。是 torch.matmul 的缩写。

本地输出:

  • 张量 A:
  •  tensor([[1, 2],
  •         [3, 4],
  •         [5, 6]])
  • 张量 B:
  •  tensor([[ 7,  8],
  •         [ 9, 10],
  •         [11, 12]])
  • A * B^T:
  •  tensor([[ 23,  29,  35],
  •         [ 53,  67,  81],
  •         [ 83, 105, 127]])

10. 张量聚合

张量聚合是将张量中的元素合并到一个单一结果或较小张量集的操作。通常涉及计算总和、平均值、最小值、最大值这些统计量。

  1. import torch
  2.  
  3. x = torch.arange(0, 100, 10)
  4. print("张量 x:", x)
  5. print("张量 x 的数据类型:", x.dtype)
  6.  
  7. # 计算并打印张量的最小值
  8. print("\n张量的最小值 (函数调用):", torch.min(x))
  9. print("张量的最小值 (方法调用):", x.min())
  10.  
  11. # 计算并打印张量的最大值
  12. print("\n张量的最大值 (函数调用):", torch.max(x))
  13. print("张量的最大值 (方法调用):", x.max())
  14.  
  15. # 计算并打印张量的平均值
  16. x_float = x.type(torch.float32)
  17. print("\n张量的平均值 (函数调用):", torch.mean(x_float))
  18. print("张量的平均值 (方法调用):", x_float.mean())
  19.  
  20. # 计算并打印张量的总和
  21. print("\n张量的总和 (函数调用):", torch.sum(x))
  22. print("张量的总和 (方法调用):", x.sum())

计算平均值需要是浮点类型。

本地输出:

  • 张量 x: tensor([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
  • 张量 x 的数据类型: torch.int64
  •  
  • 张量的最小值 (函数调用): tensor(0)
  • 张量的最小值 (方法调用): tensor(0)
  •  
  • 张量的最大值 (函数调用): tensor(90)
  • 张量的最大值 (方法调用): tensor(90)
  •  
  • 张量的平均值 (函数调用): tensor(45.)
  • 张量的平均值 (方法调用): tensor(45.)
  •  
  • 张量的总和 (函数调用): tensor(450)
  • 张量的总和 (方法调用): tensor(450)

11. 索引函数

可以使用 .argmin.argmax 找出张量中的最大和最小元素的索引。

  1. import torch
  2.  
  3. x = torch.arange(1, 100, 10)
  4. print("张量:", x)
  5.  
  6. min_index = x.argmin()  # 返回最小元素的索引
  7. max_index = x.argmax()  # 返回最大元素的索引
  8.  
  9. # 打印最小值和最大值的索引
  10. print("张量中最小值的索引:", min_index)
  11. print("张量中最大值的索引:", max_index)

本地输出:

  • 张量: tensor([ 1, 11, 21, 31, 41, 51, 61, 71, 81, 91])
  • 张量中最小值的索引: tensor(0)
  • 张量中最大值的索引: tensor(9)

12. reshape 和 view

reshapeview 都用于改变张量的形状,但它们在内部处理上有所不同。

reshape 可能会返回一个新的张量或一个共享内存视图,取决于原始张量的内存布局。

view 要求原始数据在内存中连续,且总是返回一个共享原始数据的张量视图。

只是改变形状,总元素的数量还需要和原始张量保持一致。

  1. import torch
  2.  
  3. x = torch.arange(1., 10.)
  4. print("原始张量:", x)
  5. print("原始张量的形状:", x.shape)
  6.  
  7. reshaped_tensor = x.reshape(1, 9)
  8. print("\n使用reshape变换后的张量:", reshaped_tensor)
  9. print("变换后的张量形状:", reshaped_tensor.shape)
  10.  
  11. viewed_tensor = x.view(1, 9)
  12. print("\n使用view变换后的张量:", viewed_tensor)
  13. print("变换后的张量形状:", viewed_tensor.shape)
  14.  
  15. # 修改通过view创建的张量中的元素,检查原始张量x的变化
  16. viewed_tensor[:, 0] = 5
  17. print("\n修改viewed_tensor后的张量:", viewed_tensor)
  18. print("查看原始张量x的变化:", x)

本地输出:

  • 原始张量: tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.])
  • 原始张量的形状: torch.Size([9])
  •  
  • 使用reshape变换后的张量: tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
  • 变换后的张量形状: torch.Size([1, 9])
  •  
  • 使用view变换后的张量: tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
  • 变换后的张量形状: torch.Size([1, 9])
  •  
  • 修改viewed_tensor后的张量: tensor([[5., 2., 3., 4., 5., 6., 7., 8., 9.]])
  • 查看原始张量x的变化: tensor([5., 2., 3., 4., 5., 6., 7., 8., 9.])

13. stack

stack 将多个同形状的张量合并堆叠成一个新的维度。

  1. import torch
  2.  
  3. tensor1 = torch.rand(2, 3, 4)
  4. tensor2 = torch.rand(2, 3, 4)
  5. tensor3 = torch.rand(2, 3, 4)
  6.  
  7. # 打印原始张量
  8. print("Original tensor1:\n", tensor1)
  9. print("Original tensor2:\n", tensor2)
  10. print("Original tensor3:\n", tensor3)
  11.  
  12. # 沿不同的维度堆叠这些张量
  13. stacked_dim0 = torch.stack([tensor1, tensor2, tensor3], dim=0)
  14. stacked_dim1 = torch.stack([tensor1, tensor2, tensor3], dim=1)
  15. stacked_dim2 = torch.stack([tensor1, tensor2, tensor3], dim=2)
  16. stacked_dim3 = torch.stack([tensor1, tensor2, tensor3], dim=3)
  17.  
  18. # 打印每种堆叠的张量形状
  19. print("\nStacked along dimension 0 shape:", stacked_dim0.shape)
  20. print("Stacked along dimension 1 shape:", stacked_dim1.shape)
  21. print("Stacked along dimension 2 shape:", stacked_dim2.shape)
  22. print("Stacked along dimension 3 shape:", stacked_dim3.shape)
  23.  
  24. # 打印最终堆叠的张量内容
  25. print("\nContents of Stacked along dimension 0:\n", stacked_dim0)
  26. print("\nContents of Stacked along dimension 1:\n", stacked_dim1)
  27. print("\nContents of Stacked along dimension 2:\n", stacked_dim2)
  28. print("\nContents of Stacked along dimension 3:\n", stacked_dim3)

本地输出:

  1. Original tensor1:
  2.  tensor([[[0.7199, 0.0911, 0.0740, 0.8454],
  3.          [0.3882, 0.7100, 0.8533, 0.9854],
  4.          [0.7674, 0.3643, 0.4862, 0.3112]],
  5.  
  6.         [[0.2545, 0.3064, 0.6618, 0.5085],
  7.          [0.8557, 0.7248, 0.4626, 0.8404],
  8.          [0.6944, 0.4044, 0.1186, 0.3678]]])
  9. Original tensor2:
  10.  tensor([[[0.4120, 0.8468, 0.1986, 0.6609],
  11.          [0.1452, 0.7707, 0.0474, 0.3399],
  12.          [0.3705, 0.4415, 0.1923, 0.8661]],
  13.  
  14.         [[0.3099, 0.5840, 0.0212, 0.6477],
  15.          [0.7680, 0.0792, 0.3609, 0.6135],
  16.          [0.4450, 0.5942, 0.9047, 0.2399]]])
  17. Original tensor3:
  18.  tensor([[[0.3059, 0.0484, 0.4267, 0.6936],
  19.          [0.0041, 0.2334, 0.0086, 0.1341],
  20.          [0.2003, 0.1958, 0.7369, 0.2554]],
  21.  
  22.         [[0.3188, 0.6289, 0.3392, 0.3064],
  23.          [0.9468, 0.3915, 0.4709, 0.6216],
  24.          [0.6450, 0.9173, 0.1603, 0.3267]]])
  25.  
  26. Stacked along dimension 0 shape: torch.Size([3, 2, 3, 4])
  27. Stacked along dimension 1 shape: torch.Size([2, 3, 3, 4])
  28. Stacked along dimension 2 shape: torch.Size([2, 3, 3, 4])
  29. Stacked along dimension 3 shape: torch.Size([2, 3, 4, 3])
  30.  
  31. Contents of Stacked along dimension 0:
  32.  tensor([[[[0.7199, 0.0911, 0.0740, 0.8454],
  33.           [0.3882, 0.7100, 0.8533, 0.9854],
  34.           [0.7674, 0.3643, 0.4862, 0.3112]],
  35.  
  36.          [[0.2545, 0.3064, 0.6618, 0.5085],
  37.           [0.8557, 0.7248, 0.4626, 0.8404],
  38.           [0.6944, 0.4044, 0.1186, 0.3678]]],
  39.  
  40.  
  41.         [[[0.4120, 0.8468, 0.1986, 0.6609],
  42.           [0.1452, 0.7707, 0.0474, 0.3399],
  43.           [0.3705, 0.4415, 0.1923, 0.8661]],
  44.  
  45.          [[0.3099, 0.5840, 0.0212, 0.6477],
  46.           [0.7680, 0.0792, 0.3609, 0.6135],
  47.           [0.4450, 0.5942, 0.9047, 0.2399]]],
  48.  
  49.  
  50.         [[[0.3059, 0.0484, 0.4267, 0.6936],
  51.           [0.0041, 0.2334, 0.0086, 0.1341],
  52.           [0.2003, 0.1958, 0.7369, 0.2554]],
  53.  
  54.          [[0.3188, 0.6289, 0.3392, 0.3064],
  55.           [0.9468, 0.3915, 0.4709, 0.6216],
  56.           [0.6450, 0.9173, 0.1603, 0.3267]]]])
  57.  
  58. Contents of Stacked along dimension 1:
  59.  tensor([[[[0.7199, 0.0911, 0.0740, 0.8454],
  60.           [0.3882, 0.7100, 0.8533, 0.9854],
  61.           [0.7674, 0.3643, 0.4862, 0.3112]],
  62.  
  63.          [[0.4120, 0.8468, 0.1986, 0.6609],
  64.           [0.1452, 0.7707, 0.0474, 0.3399],
  65.           [0.3705, 0.4415, 0.1923, 0.8661]],
  66.  
  67.          [[0.3059, 0.0484, 0.4267, 0.6936],
  68.           [0.0041, 0.2334, 0.0086, 0.1341],
  69.           [0.2003, 0.1958, 0.7369, 0.2554]]],
  70.  
  71.  
  72.         [[[0.2545, 0.3064, 0.6618, 0.5085],
  73.           [0.8557, 0.7248, 0.4626, 0.8404],
  74.           [0.6944, 0.4044, 0.1186, 0.3678]],
  75.  
  76.          [[0.3099, 0.5840, 0.0212, 0.6477],
  77.           [0.7680, 0.0792, 0.3609, 0.6135],
  78.           [0.4450, 0.5942, 0.9047, 0.2399]],
  79.  
  80.          [[0.3188, 0.6289, 0.3392, 0.3064],
  81.           [0.9468, 0.3915, 0.4709, 0.6216],
  82.           [0.6450, 0.9173, 0.1603, 0.3267]]]])
  83.  
  84. Contents of Stacked along dimension 2:
  85.  tensor([[[[0.7199, 0.0911, 0.0740, 0.8454],
  86.           [0.4120, 0.8468, 0.1986, 0.6609],
  87.           [0.3059, 0.0484, 0.4267, 0.6936]],
  88.  
  89.          [[0.3882, 0.7100, 0.8533, 0.9854],
  90.           [0.1452, 0.7707, 0.0474, 0.3399],
  91.           [0.0041, 0.2334, 0.0086, 0.1341]],
  92.  
  93.          [[0.7674, 0.3643, 0.4862, 0.3112],
  94.           [0.3705, 0.4415, 0.1923, 0.8661],
  95.           [0.2003, 0.1958, 0.7369, 0.2554]]],
  96.  
  97.  
  98.         [[[0.2545, 0.3064, 0.6618, 0.5085],
  99.           [0.3099, 0.5840, 0.0212, 0.6477],
  100.           [0.3188, 0.6289, 0.3392, 0.3064]],
  101.  
  102.          [[0.8557, 0.7248, 0.4626, 0.8404],
  103.           [0.7680, 0.0792, 0.3609, 0.6135],
  104.           [0.9468, 0.3915, 0.4709, 0.6216]],
  105.  
  106.          [[0.6944, 0.4044, 0.1186, 0.3678],
  107.           [0.4450, 0.5942, 0.9047, 0.2399],
  108.           [0.6450, 0.9173, 0.1603, 0.3267]]]])
  109.  
  110. Contents of Stacked along dimension 3:
  111.  tensor([[[[0.7199, 0.4120, 0.3059],
  112.           [0.0911, 0.8468, 0.0484],
  113.           [0.0740, 0.1986, 0.4267],
  114.           [0.8454, 0.6609, 0.6936]],
  115.  
  116.          [[0.3882, 0.1452, 0.0041],
  117.           [0.7100, 0.7707, 0.2334],
  118.           [0.8533, 0.0474, 0.0086],
  119.           [0.9854, 0.3399, 0.1341]],
  120.  
  121.          [[0.7674, 0.3705, 0.2003],
  122.           [0.3643, 0.4415, 0.1958],
  123.           [0.4862, 0.1923, 0.7369],
  124.           [0.3112, 0.8661, 0.2554]]],
  125.  
  126.  
  127.         [[[0.2545, 0.3099, 0.3188],
  128.           [0.3064, 0.5840, 0.6289],
  129.           [0.6618, 0.0212, 0.3392],
  130.           [0.5085, 0.6477, 0.3064]],
  131.  
  132.          [[0.8557, 0.7680, 0.9468],
  133.           [0.7248, 0.0792, 0.3915],
  134.           [0.4626, 0.3609, 0.4709],
  135.           [0.8404, 0.6135, 0.6216]],
  136.  
  137.          [[0.6944, 0.4450, 0.6450],
  138.           [0.4044, 0.5942, 0.9173],
  139.           [0.1186, 0.9047, 0.1603],
  140.           [0.3678, 0.2399, 0.3267]]]])

堆叠理解起来有点绕,参数中还需要指定堆叠的维度。但从堆叠之后的形状上看,是比较好理解的,就是将新维度“插入”指定的位置。

Stacked along dimension 0 shape: torch.Size([3, 2, 3, 4])

Stacked along dimension 1 shape: torch.Size([2, 3, 3, 4])

Stacked along dimension 2 shape: torch.Size([2, 3, 3, 4])

Stacked along dimension 3 shape: torch.Size([2, 3, 4, 3])

具体堆叠的对象,针对这个用例,我是这么理解的:

dim=0,堆叠的对象是[[[]]]。

dim=1,堆叠的对象是[[]]。

dim=2,堆叠的对象是[]。

dim=3,堆叠的对象是单一元素。

14. squeeze/unsqueeze 和 permute

squeeze 用于移除张量中所有的单一维度(维度大小为 1 的维度)。unsqueeze 用于在指定位置添加一个新的维度。

permute 用于重排张量的维度顺序。比如,图片数据是宽度x高度x通道,可以重排成通道x宽度x高度。

  1. import torch
  2.  
  3. x = torch.arange(1., 10.)
  4. print("原始张量 x:", x)
  5. print("原始张量的形状:", x.shape)
  6.  
  7. x_reshaped = x.reshape(1, 9)
  8. print("\nx_reshaped:", x_reshaped)
  9. print("变换后的张量形状:", x_reshaped.shape)
  10.  
  11. x_squeezed = x_reshaped.squeeze()
  12. print("\n使用squeeze移除单一维度后的张量:", x_squeezed)
  13.  
  14. x_unsqueezed = x_squeezed.unsqueeze(dim=0)
  15. print("\n使用unsqueeze添加新维度后的张量:", x_unsqueezed)
  16.  
  17. # 创建一个具有随机值的3通道图像张量 (224x224x3)
  18. x_original = torch.rand(size=(224, 224, 3))
  19. x_permuted = x_original.permute(2, 0, 1)
  20.  
  21. print("\n原始图像张量的形状:", x_original.shape)
  22. print("重排维度后的图像张量形状:", x_permuted.shape)

本地输出:

  • 原始张量 x: tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.])
  • 原始张量的形状: torch.Size([9])
  •  
  • x_reshaped: tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
  • 变换后的张量形状: torch.Size([1, 9])
  •  
  • 使用squeeze移除单一维度后的张量: tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.])
  •  
  • 使用unsqueeze添加新维度后的张量: tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
  •  
  • 原始图像张量的形状: torch.Size([224, 224, 3])
  • 重排维度后的图像张量形状: torch.Size([3, 224, 224])

15. PyTorch 和 NumPy 转换

torch.from_numpy() 用于将 NumPy 数组转换成 PyTorch 张量。这个转换是内存共享的。

.numpy() 用于将 PyTorch 张量转换成 NumPy 数组。这个转换也是内存共享的。

  1. import torch
  2. import numpy as np
  3.  
  4. # 创建一个NumPy数组
  5. array = np.arange(1.0, 8.0)
  6. tensor = torch.from_numpy(array)
  7. print("原始的 NumPy 数组:", array)
  8. print("从 NumPy 数组创建的 PyTorch 张量:", tensor)
  9.  
  10. array[0] = 100
  11. print("修改后的 NumPy 数组:", array)
  12. print("PyTorch 张量:", tensor)
  13.  
  14. # 创建一个PyTorch张量
  15. tensor = torch.ones(7)
  16. numpy_tensor = tensor.numpy()
  17. print("\n原始的 PyTorch 张量:", tensor)
  18. print("从 PyTorch 张量创建的 NumPy 数组:", numpy_tensor)
  19. print("NumPy 数组的数据类型:", numpy_tensor.dtype)
  20.  
  21. tensor[0] = 200
  22. print("修改后的 PyTorch 张量:", tensor)
  23. print("NumPy 数组:", numpy_tensor)

本地输出:

  • 原始的 NumPy 数组: [1. 2. 3. 4. 5. 6. 7.]
  • 从 NumPy 数组创建的 PyTorch 张量: tensor([1., 2., 3., 4., 5., 6., 7.], dtype=torch.float64)
  • 修改后的 NumPy 数组: [100.   2.   3.   4.   5.   6.   7.]
  • PyTorch 张量: tensor([100.,   2.,   3.,   4.,   5.,   6.,   7.], dtype=torch.float64)
  •  
  • 原始的 PyTorch 张量: tensor([1., 1., 1., 1., 1., 1., 1.])
  • 从 PyTorch 张量创建的 NumPy 数组: [1. 1. 1. 1. 1. 1. 1.]
  • NumPy 数组的数据类型: float32
  • 修改后的 PyTorch 张量: tensor([200.,   1.,   1.,   1.,   1.,   1.,   1.])
  • NumPy 数组: [200.   1.   1.   1.   1.   1.   1.]

转换的类型是自动对应的。注意,NumPy 默认类型是 float64;PyTorch 默认类型是 float32。

16. 随机种子

在 PyTorch 中,通过设定随机种子,可以确保随机操作的可重现性。

  1. import torch
  2.  
  3. # 创建两个随机张量并比较它们
  4. random_tensor_A = torch.rand(3, 4)
  5. random_tensor_B = torch.rand(3, 4)
  6.  
  7. print("随机张量 A:\n", random_tensor_A)
  8. print("随机张量 B:\n", random_tensor_B)
  9. print("随机张量 A 和 B 是否相等:\n", random_tensor_A == random_tensor_B)
  10.  
  11. # 设置随机种子以确保随机数生成的可重复性
  12. RANDOM_SEED = 42
  13. torch.manual_seed(RANDOM_SEED)
  14. random_tensor_C = torch.rand(3, 4)
  15.  
  16. torch.manual_seed(RANDOM_SEED)
  17. random_tensor_D = torch.rand(3, 4)
  18.  
  19. print("\n随机张量 C:\n", random_tensor_C)
  20. print("随机张量 D:\n", random_tensor_D)
  21. print("随机张量 C 和 D 是否相等:\n", random_tensor_C == random_tensor_D)

本地输出:

  • 随机张量 A:
  •  tensor([[0.5061, 0.4897, 0.8705, 0.7014],
  •         [0.1571, 0.3166, 0.7212, 0.8622],
  •         [0.7175, 0.4205, 0.8970, 0.8726]])
  • 随机张量 B:
  •  tensor([[0.5317, 0.2673, 0.6956, 0.2626],
  •         [0.4935, 0.6814, 0.8929, 0.3707],
  •         [0.4432, 0.5911, 0.1168, 0.6377]])
  • 随机张量 A 和 B 是否相等:
  •  tensor([[False, False, False, False],
  •         [False, False, False, False],
  •         [False, False, False, False]])
  •  
  • 随机张量 C:
  •  tensor([[0.8823, 0.9150, 0.3829, 0.9593],
  •         [0.3904, 0.6009, 0.2566, 0.7936],
  •         [0.9408, 0.1332, 0.9346, 0.5936]])
  • 随机张量 D:
  •  tensor([[0.8823, 0.9150, 0.3829, 0.9593],
  •         [0.3904, 0.6009, 0.2566, 0.7936],
  •         [0.9408, 0.1332, 0.9346, 0.5936]])
  • 随机张量 C 和 D 是否相等:
  •  tensor([[True, True, True, True],
  •         [True, True, True, True],
  •         [True, True, True, True]])

17. CUDA 支持

在使用 PyTorch 时,可以利用 GPU 提升计算效率。torch.cuda.is_available() 检查当前环境是否支持 CUDA。torch.cuda.device_count() 获取可用的 GPU 数量。

  1. import torch
  2.  
  3. cuda_available = torch.cuda.is_available()
  4. print("CUDA 是否可用:", cuda_available)
  5.  
  6. if cuda_available:
  7.     gpu_count = torch.cuda.device_count()
  8.     print("可用的 GPU 数量:", gpu_count)
  9. else:
  10.     print("没有检测到可用的 GPU 设备")

本地输出:

  • CUDA 是否可用: True
  • 可用的 GPU 数量: 1

18. 数据迁移

在 PyTorch 中,数据可以在 CPU 和 GPU 之间迁移。

  1. import torch
  2.  
  3. tensor = torch.tensor([1, 2, 3])
  4. print("原始张量:", tensor, "位于设备:", tensor.device)
  5.  
  6.  
  7. device = "cuda" if torch.cuda.is_available() else "cpu"
  8. print("\n使用的设备:", device)
  9.  
  10. tensor_on_gpu = tensor.to(device)
  11. print("\n移至", device, "后的张量:", tensor_on_gpu)
  12.  
  13. tensor_back_on_cpu = tensor_on_gpu.cpu()
  14. print("\n移回 cpu 后的张量:", tensor_back_on_cpu)

本地输出:

  • 原始张量: tensor([1, 2, 3]) 位于设备: cpu
  •  
  • 使用的设备: cuda
  •  
  • 移至 cuda 后的张量: tensor([1, 2, 3], device='cuda:0')
  •  
  • 移回 cpu 后的张量: tensor([1, 2, 3])