小言_互联网的博客

【PyTorch】全方位介绍Tensor

353人阅读  评论(0)

目录

一、Tensor概述

二、创建Tensor

三、修改Tensor形状

四、索引操作

五、广播机制

六、逐元素操作

七、归并操作

八、比较操作

九、矩阵操作

十、PyTorch与Numpy比较


PyTorch的Tensor,它可以是零维(又称为标量或一个数)、一维、二维及多维的数组。Tensor自称为神经网络界的Numpy,它与Numpy相似,二者可以共享内存,且之间的转换非常方便和高效。不过它们也有不同之处,最大的区别就是Numpy会把ndarray放在CPU中进行加速运算,而由Torch产生的Tensor会放在GPU中进行加速运算(假设当前环境有GPU)。

一、Tensor概述

对Tensor的操作很多,从接口的角度来划分,可以分为两类:

  1. torch.function:如torch.sum、torch.add等。
  2. tensor.function:如tensor.view、tensor.add等。

这些操作对大部分Tensor都是等价的,如torch.add(x,y)与x.add(y)等价。在实际使用时,可以根据个人爱好选择。
如果从修改方式的角度来划分,可以分为以下两类:

  1. 不修改自身数据:如x.add(y),x的数据不变,返回一个新的Tensor。
  2. 修改自身数据:如x.add_(y)(运行符带下划线后缀),运算结果存在x中,x被修改。

  
  1. import torch
  2. x = torch.tensor([ 1, 2])
  3. y = torch.tensor([ 3, 4])
  4. z = x.add(y)
  5. print(z)
  6. print(x)
  7. x.add_(y)
  8. print(x)

  
  1. tensor([4, 6])
  2. tensor([1, 2])
  3. tensor([4, 6])

二、创建Tensor

创建Tensor的方法有很多,可以从列表或ndarray等类型进行构建,也可根据指定的形状构建。下表是常见的创建Tensor的方法。

举例:


  
  1. # 根据list数据生成Tensor
  2. t1 = torch.Tensor([[ 1, 2, 3], [ 4, 5, 6]])
  3. # 生成和t1形状一样的张量,元素初始值为1
  4. print(torch.ones(t1.size()))
  5. # torch.ones_like(t1)
  6. t2 = torch.linspace( 1, 10, 10)
  7. t3 = torch.logspace( 1, 10, 10)
  8. print(t2)
  9. print(t3)
  10. t4 = torch.rand(t1.size())
  11. print(t4)
  12. t5 = torch.arange( 1, 10, 1)
  13. print(t5)
  14. import numpy as np
  15. t6 = torch.from_numpy(np.array([ 1, 2, 3]))
  16. print(t6)

  
  1. tensor([[1., 1., 1.],
  2. [1., 1., 1.]])
  3. tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
  4. tensor([1.0000e+01, 1.0000e+02, 1.0000e+03, 1.0000e+04, 1.0000e+05, 1.0000e+06,
  5. 1.0000e+07, 1.0000e+08, 1.0000e+09, 1.0000e+10])
  6. tensor([[0.5150, 0.6570, 0.0718],
  7. [0.8774, 0.7458, 0.3008]])
  8. tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
  9. tensor([1, 2, 3], dtype=torch.int32)

注意torch.Tensor与torch.tensor的几点区别:

  1. torch.Tensor是torch.empty和torch.tensor之间的一种混合,但是,当传入数据时,torch.Tensor使用全局默认dtype(FloatTensor),而torch.tensor是从数据中推断数据类型。
  2. torch.tensor(1)返回一个固定值1,而torch.Tensor(1)返回一个大小为1的张量,它是随机初始化的值。

  
  1. t1 = torch.Tensor( 1)
  2. t2 = torch.tensor( 1)
  3. print( 't1的值{}, t1的数据类型{}'.format(t1, t1.type()))
  4. print( 't2的值{}, t2的数据类型{}'.format(t2, t2.type()))

  
  1. t1的值tensor([0.]), t1的数据类型torch.FloatTensor
  2. t2的值1, t2的数据类型torch.LongTensor

三、修改Tensor形状

在处理数据、构建网络层等过程中,经常需要了解Tensor的形状、修改Tensor的形状。与修改Numpy的形状类似,修改Tenor的形状也有很多类似函数,下表是tensor常用修改形状的函数。

举例: 


  
  1. #生成一个形状为2x3的矩阵
  2. x = torch.randn( 2, 3)
  3. print(x)
  4. print(x.dim()) #查看x的维度
  5. print(x.numel())
  6. #把x变为3x2的矩阵
  7. w = x.view( 3, 2)
  8. print(w)
  9. #把x展平为1维向量
  10. y = x.view( -1)
  11. print(y)
  12. #添加一个维度
  13. z = torch.unsqueeze(y, 0)
  14. print(z)

  
  1. tensor([[ 0.7251, -0.4526, 0.5193],
  2. [ 0.6478, -0.7698, -0.0487]])
  3. 2
  4. 6
  5. tensor([[ 0.7251, -0.4526],
  6. [ 0.5193, 0.6478],
  7. [-0.7698, -0.0487]])
  8. tensor([ 0.7251, -0.4526, 0.5193, 0.6478, -0.7698, -0.0487])
  9. tensor([[ 0.7251, -0.4526, 0.5193, 0.6478, -0.7698, -0.0487]])

torch.view与torch.reshpae的异同:

  1. reshape()可以由torch.reshape(),也可由torch.Tensor.reshape()调用。但view()只可由torch.Tensor.view()来调用。
  2. 对于一个将要被view的Tensor,新的size必须与原来的size与stride兼容。否则,在view之前必须调用contiguous()方法。
  3. 同样也是返回与input数据量相同,但形状不同的Tensor。若满足view的条件,则不会copy,若不满足,则会copy。
  4. 如果你只想重塑张量,请使用torch.reshape。如果你还关注内存使用情况并希望确保两个张量共享相同的数据,请使用torch.view

四、索引操作

Tensor的索引操作与Numpy类似,一般情况下索引结果与源数据共享内存。从Tensor获取元素除了可以通过索引,也可以借助一些函数,下表是常用选择操作函数。

举例:


  
  1. #设置一个随机种子
  2. torch.manual_seed( 100)
  3. #生成一个形状为2x3的矩阵
  4. x = torch.randn( 2, 3)
  5. print(x)
  6. #根据索引获取第1行,所有数据
  7. print(x[ 0, :])
  8. #获取最后一列数据
  9. print(x[:, -1])
  10. #生成是否大于0的Byter张量
  11. mask = x> 0
  12. print(mask)
  13. #获取大于0的值
  14. print(torch.masked_select(x, mask))
  15. #获取非0下标,即行,列索引
  16. torch.nonzero(mask)
  17. #获取指定索引对应的值,输出根据以下规则得到
  18. #out[i][j] = input[index[i][j]][j] # if dim == 0
  19. #out[i][j] = input[i][index[i][j]] # if dim == 1
  20. index1 = torch.LongTensor([[ 0, 1, 1]])
  21. print(torch.gather(x, 0, index1))
  22. index2 = torch.LongTensor([[ 0, 1, 1], [ 1, 1, 1]])
  23. a = torch.gather(x, 1, index2)
  24. print(a)
  25. #把a的值返回到一个2x3的0矩阵中
  26. z = torch.zeros( 2, 3)
  27. print(z.scatter_( 1, index2, a))

  
  1. tensor([[ 0.3607, -0.2859, -0.3938],
  2. [ 0.2429, -1.3833, -2.3134]])
  3. tensor([ 0.3607, -0.2859, -0.3938])
  4. tensor([-0.3938, -2.3134])
  5. tensor([[1, 0, 0],
  6. [1, 0, 0]], dtype=torch.uint8)
  7. tensor([0.3607, 0.2429])
  8. tensor([[ 0.3607, -1.3833, -2.3134]])
  9. tensor([[ 0.3607, -0.2859, -0.2859],
  10. [-1.3833, -1.3833, -1.3833]])
  11. tensor([[ 0.3607, -0.2859, 0.0000],
  12. [ 0.0000, -1.3833, 0.0000]])

五、广播机制

广播机制是向量运算的重要技巧。PyTorch也支持广播机制,以下通过几个示例进行说明。


  
  1. import torch
  2. import numpy as np
  3. A = np.arange( 0, 40, 10).reshape( 4, 1)
  4. B = np.arange( 0, 3)
  5. print(A)
  6. print(B)
  7. #把ndarray转换为Tensor
  8. A1 = torch.from_numpy(A) #形状为4x1
  9. B1 = torch.from_numpy(B) #形状为3
  10. #Tensor自动实现广播
  11. C1 = A1+B1
  12. print(C1)
  13. #我们可以根据广播机制,手工进行配置
  14. #根据规则1,B1需要向A1看齐,把B变为(1,3)
  15. B2 = B1.unsqueeze( 0) #B2的形状为1x3
  16. print(B2)
  17. #使用expand函数重复数组,分别的4x3的矩阵
  18. A2=A1.expand( 4, 3)
  19. B3=B2.expand( 4, 3)
  20. #然后进行相加,C1与C结果一致
  21. C2 = A2 + B3
  22. print(C2)

  
  1. [[ 0]
  2. [10]
  3. [20]
  4. [30]]
  5. [0 1 2]
  6. tensor([[ 0, 1, 2],
  7. [10, 11, 12],
  8. [20, 21, 22],
  9. [30, 31, 32]], dtype=torch.int32)
  10. tensor([[0, 1, 2]], dtype=torch.int32)
  11. tensor([[ 0, 1, 2],
  12. [10, 11, 12],
  13. [20, 21, 22],
  14. [30, 31, 32]], dtype=torch.int32)

六、逐元素操作

与Numpy一样,Tensor也有逐元素操作(Element-Wise),且操作内容相似,但使用函数可能不尽相同。大部分数学运算都属于逐元素操作,其输入与输出的形状相同。下表是常见的逐元素操作。

举例:


  
  1. t = torch.randn( 1, 3)
  2. print(t)
  3. t1 = torch.randn( 3, 1)
  4. t2 = torch.randn( 1, 3)
  5. #t+0.1*(t1/t2)
  6. print(torch.addcdiv(t, 0.1, t1, t2))
  7. #计算sigmoid
  8. print(torch.sigmoid(t))
  9. #将t限制在[0,1]之间
  10. print(torch.clamp(t, 0, 1))
  11. #t+2进行就地运算
  12. t.add_( 2)
  13. print(t)

  
  1. tensor([[-0.2586, -0.2510, 0.4770]])
  2. tensor([[-0.3861, -0.1857, 0.6969],
  3. [-0.3915, -0.1830, 0.7061],
  4. [-0.1649, -0.2989, 0.3154]])
  5. tensor([[0.4357, 0.4376, 0.6170]])
  6. tensor([[0.0000, 0.0000, 0.4770]])
  7. tensor([[1.7414, 1.7490, 2.4770]])

这些操作均会创建新的Tensor,如果需要就地操作,可以使用这些方法的下划线版本,例如abs_。

七、归并操作

归并操作顾名思义,就是对输入进行归并或合计等操作,这类操作的输入输出形状一般并不相同,而且往往是输入大于输出形状。归并操作可以对整个Tensor,也可以沿着某个维度进行归并。下表是常见的归并操作。

归并操作一般涉及一个dim参数,指定沿哪个维进行归并。另一个参数是keepdim,说明输出结果中是否保留维度1,缺省情况是False,即不保留。

举例:
 


  
  1. # 生成一个含6个数的向量
  2. a = torch.linspace( 0, 10, 6)
  3. #使用view方法,把a变为2x3矩阵
  4. a = a.view(( 2, 3))
  5. print(a)
  6. #沿y轴方向累加,即dim=0
  7. b = a.sum()
  8. print(b)
  9. #沿y轴方向累加,即dim=0,并保留含1的维度
  10. c = a.sum(dim= 0, keepdim= True)
  11. print(c)
  12. print(torch.cumprod(a, 0))
  13. print(torch.cumprod(a, 1))
  14. print(torch.cumsum(a, 1))
  15. print(torch.mean(a, 1))

  
  1. tensor([[ 0., 2., 4.],
  2. [ 6., 8., 10.]])
  3. tensor(30.)
  4. tensor([[ 6., 10., 14.]])
  5. tensor([[ 0., 2., 4.],
  6. [ 6., 8., 10.]])
  7. tensor([[ 0., 2., 4.],
  8. [ 0., 16., 40.]])
  9. tensor([[ 0., 0., 0.],
  10. [ 6., 48., 480.]])
  11. tensor([[ 0., 2., 6.],
  12. [ 6., 14., 24.]])
  13. tensor([2., 8.])

八、比较操作

比较操作一般是进行逐元素比较,有些是按指定方向比较。下表是常用的比较函数。

举例:


  
  1. x = torch.linspace( 0, 12, 12).view( 4, 3)
  2. print(x)
  3. #求所有元素的最大值
  4. print(torch.max(x))
  5. #求y轴方向的最大值
  6. print(torch.max(x, dim= 1))
  7. #求最大的2个元素
  8. print(torch.topk(x, 2, dim= 0))

  
  1. tensor([[ 0.0000, 1.0909, 2.1818],
  2. [ 3.2727, 4.3636, 5.4545],
  3. [ 6.5455, 7.6364, 8.7273],
  4. [ 9.8182, 10.9091, 12.0000]])
  5. tensor(12.)
  6. torch.return_types.max(
  7. values=tensor([ 2.1818, 5.4545, 8.7273, 12.0000]),
  8. indices=tensor([2, 2, 2, 2]))
  9. torch.return_types.topk(
  10. values=tensor([[ 9.8182, 10.9091, 12.0000],
  11. [ 6.5455, 7.6364, 8.7273]]),
  12. indices=tensor([[3, 3, 3],
  13. [2, 2, 2]]))

九、矩阵操作

机器学习和深度学习中存在大量的矩阵运算,常用的算法有两种:一种是逐元素乘法,另外一种是点积乘法。下表是PyTorch中常用的矩阵函数。

【说明】

  1. Torch的dot与Numpy的dot有点不同,Torch中的dot是对两个为1D张量进行点积运算,Numpy中的dot无此限制。
  2. mm是对2D的矩阵进行点积,bmm对含batch的3D进行点积运算。
  3. 转置运算会导致存储空间不连续,需要调用contiguous方法转为连续。

举例:


  
  1. a = torch.tensor([ 2, 3])
  2. b = torch.tensor([ 3, 4])
  3. print(torch.dot(a, b))
  4. x = torch.randint( 10, ( 2, 3))
  5. y = torch.randint( 6, ( 3, 4))
  6. print(x)
  7. print(x.t())
  8. print(y)
  9. print(torch.mm(x, y))
  10. x = torch.randint( 10, ( 2, 2, 3))
  11. y = torch.randint( 6, ( 2, 3, 4))
  12. print(torch.bmm(x, y))

  
  1. tensor(18)
  2. tensor([[6, 5, 4],
  3. [1, 1, 3]])
  4. tensor([[6, 1],
  5. [5, 1],
  6. [4, 3]])
  7. tensor([[3, 2, 5, 4],
  8. [2, 1, 1, 0],
  9. [4, 4, 2, 1]])
  10. tensor([[44, 33, 43, 28],
  11. [17, 15, 12, 7]])
  12. tensor([[[10, 50, 42, 43],
  13. [ 2, 60, 21, 46]],
  14. [[37, 72, 72, 0],
  15. [ 4, 14, 49, 0]]])

十、PyTorch与Numpy比较

PyTorch与Numpy有很多类似的地方,并且有很多相同的操作函数名称,或虽然函数名称不同但含义相同;当然也有一些虽然函数名称相同,但含义不尽相同。有些很容易混淆,下面我们把一些主要的区别进行汇总。

 

 

 

 


转载:https://blog.csdn.net/weixin_40431584/article/details/105456513
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场