当前位置:   article > 正文

张量计算和操作

张量计算和操作

一、数据操作

1、基础

  1. import torch
  2. x = torch.arange(12)
  3. # x:tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
  4. x.shape
  5. # torch.Size([12])
  6. x.numel()
  7. # 12
  8. x = x.reshape(3, 4)
  9. # tensor([[ 0, 1, 2, 3],
  10. # [ 4, 5, 6, 7],
  11. # [ 8, 9, 10, 11]])
  12. torch.zeros((2, 3, 4))
  13. # tensor([[[0., 0., 0., 0.],
  14. # [0., 0., 0., 0.],
  15. # [0., 0., 0., 0.]],
  16. # [[0., 0., 0., 0.],
  17. # [0., 0., 0., 0.],
  18. # [0., 0., 0., 0.]]])
  19. torch.ones((2, 3, 4))
  20. # tensor([[[1., 1., 1., 1.],
  21. # [1., 1., 1., 1.],
  22. # [1., 1., 1., 1.]],
  23. # [[1., 1., 1., 1.],
  24. # [1., 1., 1., 1.],
  25. # [1., 1., 1., 1.]]])
  26. # 从某个特定的概率分布中随机采样来得到张量中每个元素的值。
  27. # 随机初始化参数的值。
  28. torch.randn(3, 4)
  29. # tensor([[-0.0135, 0.0665, 0.0912, 0.3212],
  30. # [ 1.4653, 0.1843, -1.6995, -0.3036],
  31. # [ 1.7646, 1.0450, 0.2457, -0.7732]])
  32. torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
  33. # tensor([[2, 1, 4, 3],
  34. # [1, 2, 3, 4],
  35. # [4, 3, 2, 1]])

2、运算符

在相同形状的两个张量上执行按元素操作

  1. import torch
  2. +-*/**运算
  3. x = torch.tensor([1.0, 2, 4, 8])
  4. y = torch.tensor([2, 2, 2, 2])
  5. x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
  6. #(tensor([ 3., 4., 6., 10.]),
  7. # tensor([-1., 0., 2., 6.]),
  8. # tensor([ 2., 4., 8., 16.]),
  9. # tensor([0.5000, 1.0000, 2.0000, 4.0000]),
  10. # tensor([ 1., 4., 16., 64.]))
  11. 计算e^x
  12. torch.exp(x)
  13. #tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])
  14. 张量连结,端对端地叠形成一个更大的张量
  15. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  16. Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
  17. torch.cat((X, Y), dim=0)
  18. # tensor([[ 0., 1., 2., 3.],
  19. # [ 4., 5., 6., 7.],
  20. # [ 8., 9., 10., 11.],
  21. # [ 2., 1., 4., 3.],
  22. # [ 1., 2., 3., 4.],
  23. # [ 4., 3., 2., 1.]])
  24. torch.cat((X, Y), dim=1)
  25. # tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
  26. # [ 4., 5., 6., 7., 1., 2., 3., 4.],
  27. # [ 8., 9., 10., 11., 4., 3., 2., 1.]])
  28. 通过逻辑运算符构建二元张量
  29. X == Y
  30. # tensor([[False, True, False, True],
  31. # [False, False, False, False],
  32. # [False, False, False, False]])
  33. 对张量中的所有元素进行求和,会产生一个单元素张量。
  34. X.sum()
  35. # tensor(66.)

3、广播机制

在不同形状的两个张量上执行操作

1. 通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状;

2. 对生成的数组执行按元素操作。

  1. import torch
  2. a = torch.arange(3)
  3. #tensor([0, 1, 2])
  4. a = torch.arange(3).reshape((3, 1))
  5. #tensor([[0],
  6. # [1],
  7. # [2]])
  8. b = torch.arange(2)
  9. #tensor([0, 1])
  10. b = torch.arange(2).reshape((1, 2))
  11. #tensor([[0, 1]])
  12. a和b分别是3×11×2矩阵,如果让它们相加,它们的形状不匹配,可以将两个矩阵广播为一个更大的3×2矩阵。
  13. 矩阵a将复制列,矩阵b将复制行(这个过程程序自动执行),然后再按元素相加。
  14. a
  15. # tensor([[0, 0],
  16. # [1, 1],
  17. # [2, 2]])
  18. b
  19. # tensor([[0, 1],
  20. # [0, 1],
  21. # [0, 1]])
  22. a+b
  23. # tensor([[0, 1],
  24. # [1, 2],
  25. # [2, 3]])

4、索引和切片

张量中的元素可以通过索引访问

第一个元素 的索引是0,最后一个元素索引是‐1;

可以指定范围以包含第一个元素和最后一个之前的元素。

  1. import torch
  2. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  3. print(X)
  4. # tensor([[ 0., 1., 2., 3.],
  5. # [ 4., 5., 6., 7.],
  6. # [ 8., 9., 10., 11.]])
  7. print(X[-1])
  8. # tensor([ 8., 9., 10., 11.])
  9. print(X[1:3])
  10. # tensor([[ 4., 5., 6., 7.],
  11. # [ 8., 9., 10., 11.]])
  12. X[1, 2] = 9
  13. print(X)
  14. # tensor([[ 0., 1., 2., 3.],
  15. # [ 4., 5., 9., 7.],
  16. # [ 8., 9., 10., 11.]])
  17. X[0:2, :] = 12
  18. print(X)
  19. # tensor([[12., 12., 12., 12.],
  20. # [12., 12., 12., 12.],
  21. # [ 8., 9., 10., 11.]])

5、节省内存

运行一些操作可能会导致为新结果分配内存。

例如,如果我们用Y = X + Y,我们将取消引用Y指向的张量, 而是指向新分配的内存处的张量。

  1. import torch
  2. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  3. Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
  4. #Python的id()函数提供了内存中引用对象的确切地址。
  5. before = id(Y)
  6. Y = Y + X
  7. print(id(Y) == before)
  8. # False

这可能是不可取的,原因有两个:

(1)首先,我们不想总是不必要地分配内存。在机器学习中,我们可能有数百兆的参数,并且在一秒内多次更新所有参数。通常情况下,我们希望原地执行这些更新;

(2)如果我们不原地更新,其他引用仍然会指向旧的内存位置,这样我们的某些代码可能会无意中引用旧的参数。

执行原地操作非常简单,使用切片表示法将操作的结果分配给先前分配的数组。

例如Z[:] = <expression>

  1. import torch
  2. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  3. Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
  4. Z = torch.zeros_like(Y) #创建一个新的矩阵Z,其形状与X/Y相同
  5. print('id(Z):', id(Z))
  6. # id(Z): 140070288237104
  7. Z[:] = X + Y
  8. print('id(Z):', id(Z))
  9. # id(Z): 140070288237104

如果在后续计算中没有重复使用X,可以使用X[:] = X + Y或X += Y来减少操作的内存开销。

  1. import torch
  2. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  3. Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
  4. before = id(X)
  5. X += Y
  6. print(id(X) == before)
  7. # True

6、转换为其他Python对象

张量tensor转换为数组张量numpy很容易,反之也同样容易。

torch张量和numpy数组将共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量。

  1. import torch
  2. X = torch.arange(12, dtype=torch.float32).reshape((3,4))
  3. # tensor([[ 0., 1., 2., 3.],
  4. # [ 4., 5., 6., 7.],
  5. # [ 8., 9., 10., 11.]])
  6. tensor转numpy
  7. A = X.numpy()
  8. # array([[ 0., 1., 2., 3.],
  9. # [ 4., 5., 6., 7.],
  10. # [ 8., 9., 10., 11.]], dtype=float32)
  11. numpy转tensor
  12. B = torch.tensor(A)
  13. # tensor([[ 0., 1., 2., 3.],
  14. # [ 4., 5., 6., 7.],
  15. # [ 8., 9., 10., 11.]])
  16. print(type(A))
  17. # <class 'numpy.ndarray'>
  18. print(type(B))
  19. # <class 'torch.Tensor'>

两者之间的区别

  • PyTorch Tensors:PyTorch 中的 tensor 是这个深度学习框架的基础数据结构,可以在GPU上运行以加速计算。
  • NumPy Arrays:NumPy 的 ndarray 是 Python 中用于科学计算的一个基本库的核心组件。它们被广泛用于各种数值计算任务,并且通常在 CPU 上运行。
  • PyTorch tensors 支持自动微分,这对于训练神经网络来说是非常重要的。而 NumPy arrays 没有内建的自动微分功能。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/42128
推荐阅读
相关标签
  

闽ICP备14008679号