基本数据:Tensor
Tensor,即张量,是PyTorch中的基本操作对象,可以看成是包含单一数据类型元素的多维矩阵。
一、Tensor数据类型
-
定义:Tensor在使用时可以有不同的数据类型,官方给出了7种CPU Tensor类型和8种GPU Tensor类型,在使用时可以根据网络模型所需要的精度与显存容量,合理选取。
-
torch.set_default_tensor_type():设置默认使用的Tensor类型。
torch.set_default_tensor_type('torch.DoubleTensor')
-
Tensor之间类型转换:通过type(new_type)、type_as()、int()等多种方法操作
import torch torch.set_default_tensor_type('torch.FloatTensor') a = torch.Tensor(2,2) print(a) # 使用double()转换 b = a.double() print(b) # 使用type() c = a.type(torch.DoubleTensor) print(c) # 使用type_as() d = a.type_as(b) print(b)
二、Tensor的创建与维度查看
-
Tensor的创建有多种方法
import torch # 最基础的Tensor()函数创建方法 a = torch.Tensor(2,2) print(a) # 使用Python的list序列进行创建 b = torch.Tensor([[1, 2], [3, 4]]) print(b) # 使用zeros()函数,所有元素均为0,类似的有ones() c = torch.zeros(2, 2) print(c) # 使用eye()函数,对角线均为1,不要求行列数相同,生成二维矩阵 d = torch.eye(2, 2) print(b) # 使用randn()函数,生成随机矩阵 e = torch.randn(2, 2) print(e) # 使用arange(start,end,step)函数,表示从start到end,间距为step的一维向量 f = torch.arange(1, 6, 2) print(f) # 使用linspace(start,end,steps)函数,表示从stat到end,一个steps份的一维向量 g = torch.linspace(1, 7, 3) print(g) # 使用randperm(num)函数,生成长度为num的随机排列向量 h = torch.randperm(10) print(h)
输出:
tensor([[-1.8399e+19, 4.5909e-41], [-1.8399e+19, 4.5909e-41]]) tensor([[1., 2.], [3., 4.]]) tensor([[0., 0.], [0., 0.]]) tensor([[1., 2.], [3., 4.]]) tensor([[4.2157e-04, 8.0940e-01], [5.4407e-01, 7.1835e-01]]) tensor([1, 3, 5]) tensor([1., 4., 7.]) tensor([6, 3, 1, 0, 8, 9, 2, 4, 7, 5])
-
使用Tansor.shape或者size()函数查看每一维的大小,两者等价
import torch a = torch.Tensor(2, 2) print(a) print(a.shape) print(a.size())
输出:
tensor([[1.4013e-45, 0.0000e+00], [0.0000e+00, 0.0000e+00]]) torch.Size([2, 2]) torch.Size([2, 2])
-
查看Tensor的元素个数,使用Tensor.numel()或者Tensor.nelement()函数,两者等价
三、Tensor的组合与分块
-
组合操作是指将不同的Tensor叠起来,主要有Tensor.cat()和Tensor,stack()两个函数;
import torch a = torch.Tensor([[1, 2], [3, 4]]) print(a) b = torch.Tensor([[5, 6], [7, 8]]) print(b) # 以第一维进行拼接,变成4x2的矩阵 print(torch.cat([a, b], 0)) # 以第二维进行拼接,变成2x4的矩阵 print(torch.cat([a, b], 1))
输出:
tensor([[1., 2.], [3., 4.]]) tensor([[5., 6.], [7., 8.]]) tensor([[1., 2.], [3., 4.], [5., 6.], [7., 8.]]) tensor([[1., 2., 5., 6.], [3., 4., 7., 8.]])
-
分块操作与组合操作相反,指将Tensor分割成不同 子Tensor,主要有tensor.chunk()与tensor.split()两个函数;
import torch a = torch.Tensor([[1, 2, 3], [4, 5, 6]]) print(a) # 使用chunk,沿0维进行分块,一共分两块,因此分割为1x3的Tesnsor print(torch.chunk(a, 2, 0)) # 沿1维进行,分割成两个Tensor,当不能整除的时候,最后一个的维数会小于前面的 # 因此,分割成2x2和2x1的两个矩阵 print(torch.chunk(a, 2, 1)) # 使用split,沿着第0维,每一维度为2,由于第1维的维度为2,因此相当于没有分割 print(torch.split(a, 2, 0)) # 使用split,沿着第1维,每一维度为2,分割成2x2和2x1的两个矩阵 print(torch.split(a, 2, 1))
输出:
tensor([[1., 2., 3.], [4., 5., 6.]]) (tensor([[1., 2., 3.]]), tensor([[4., 5., 6.]])) (tensor([[1., 2.], [4., 5.]]), tensor([[3.], [6.]])) (tensor([[1., 2., 3.], [4., 5., 6.]]),) (tensor([[1., 2.], [4., 5.]]), tensor([[3.], [6.]]))
四、Tensor的索引
-
索引主要包括下标索引、表达式索引,使用torch.where()和Tensor.clamp()的选择性索引。
-
下标索引和表达式索引
import torch a = torch.Tensor([[0, 1], [2, 3]]) print(a) # 根据下标进行索引 print(a[1]) print(a[0, 1]) # 选择a中大于0的元素,返回和a相同大小的Tensor,符合条件的置1,否则置0 print(a > 0) # 选择非0座标,并返回 print(torch.nonzero(a))
输出:
tensor([[0., 1.], [2., 3.]]) tensor([2., 3.]) tensor(1.) tensor([[False, True], [ True, True]]) tensor([[0, 1], [1, 0], [1, 1]])
-
torch.where()和Tensor.clamp()
import torch a = torch.Tensor([[0, 1], [2, 3]]) print(a) # torch.where(condition, x, y),满足condition的位置输出x,否则输出y print(torch.where(a > 1, torch.full_like(a, 1), a)) # 对Tensor元素进行限制可以使用clamp()函数,示例如下,限制最小值为1,最大值为2 print(a.clamp(1, 2))
输出:
tensor([[0., 1.], [2., 3.]]) tensor([[0., 1.], [1., 1.]]) tensor([[1., 1.], [2., 2.]])
五、Tensor的变形
-
变形操作是指改变Tensor的维度,以适应在深度学习的计算中,数据维度经常变换的需求。在PyTorch中主要有4类不同的变形方法。
-
view()、resize()和reshape()函数:可以在不改变Tensor数据的前提下任意改变Tensor的形状,必须保证调整前后的元素个数相同,并且调整前后共享内存,三者的作用基本相同。
import torch a = torch.arange(1, 5) print(a) # 使用view() print(a.view(2, 2)) # 使用resize_() print(a.resize_(4, 1)) # 使用reshape() print(a.reshape(1, 4))
输出:
tensor([1, 2, 3, 4]) tensor([[1, 2], [3, 4]]) tensor([[1], [2], [3], [4]]) tensor([[1, 2, 3, 4]])
-
transpose()和permute()函数:transpose()函数可以将指定的两个维度的元素进行转置, permute()函数则可以按照给定的维度进行变换。
import torch a = torch.randn(2, 2, 2) print(a) # 将0维和1维的元素进行转置 print(a.transpose(0, 1)) # 按照2、1、0的维度顺序重新进行元素排列 print(a.permute(2, 1, 0))
输出:
tensor([[[-1.5178, 0.9670], [ 0.4453, -1.0351]], [[-0.1473, 0.1650], [-0.1403, 0.0548]]]) tensor([[[-1.5178, 0.9670], [-0.1473, 0.1650]], [[ 0.4453, -1.0351], [-0.1403, 0.0548]]]) tensor([[[-1.5178, -0.1473], [ 0.4453, -0.1403]], [[ 0.9670, 0.1650], [-1.0351, 0.0548]]])
-
squeeze()和unsqueeze()函数:在实际应用中,经常需要增加或减少Tensor的维度。前者用于去除size为1的维度,而后者则是将指定的维度size变为1。
import torch a = torch.arange(1, 4) print(a) print(a.shape) print(a.unsqueeze(0)) print(a.unsqueeze(0).shape) print(a.unsqueeze(0).squeeze(0)) print(a.unsqueeze(0).squeeze(0).shape)
输出:
tensor([1, 2, 3]) torch.Size([3]) tensor([[1, 2, 3]]) torch.Size([1, 3]) tensor([1, 2, 3]) torch.Size([3])
- expand()和expand_as()函数:有时候需要采用复制的形式来扩展Tensor的维度,expand()函数将size为1的维度扩展为指定大小,也可以使用expand_as()函数指定。
import torch a = torch.randn(2, 2, 1) print(a) # 将第2维的维度由1变为3,则复制该维的元素,并扩展为3 print(a.expand(2, 2, 3))
输出:
tensor([[[ 0.5300], [ 0.8920]], [[-0.2896], [-0.2523]]]) tensor([[[ 0.5300, 0.5300, 0.5300], [ 0.8920, 0.8920, 0.8920]], [[-0.2896, -0.2896, -0.2896], [-0.2523, -0.2523, -0.2523]]])