说明:我们可以把PyTorch简单的看成是Python的深度学习的第三方库,在PyTorch中定义深度学习的基本数据机构——张量。(相当于NumPy中定义的Array和对应的科学计算方法。
1.1 张量(Tensor)的基本创建以及类型
1.1.1 张量的创建
import torch import numpy as np # print(torch.__version__) # 通过列表创建张量,输入的需要是一个序列 t=torch.tensor([1,3]) print(t) # 通过元组创建张量 t=torch.tensor((1,3)) print(t) # 创建的方式与Numpy中的array差不多 a=np.array((1,3)) print(a)
1.1.2 张量的类型
由下述的输出可以看出,张量也是有类型的
t1=torch.tensor(a) print(t1) #tensor([1, 3], dtype=torch.int32)
查看上述创建的变量类型:
1)由下可以看出整型数组默认创建是int32类型,而张量默认创建的是int64类型
print(a.dtype) print(t.dtype) print(t1.dtype) #int32 # torch.int64 # torch.int32
2)相对的,创建浮点数组时,张量默认是float32(单精度浮点型),而Array则是默认float64(双精度浮点型)
a=np.array((1.2,1.5)) print(a.dtype) # float64 b=torch.tensor((1.2,1.5)) print(b.dtype) # torch.float32 c=torch.tensor(a) print(c.dtype) # torch.float64
3)创建指定类型的张量
a=torch.tensor((1,2.2),dtype=torch.int16) print(a.dtype) #torch.int16
1.1.3 张量类型的转化
1)张量类型的隐士转化
a=torch.tensor((1.1,2)) print(a) print(a.dtype) # tensor([1.1000, 2.0000]) #都转化为浮点型 # torch.float32
2)张量的转化方法
- 通过.float()、.int()等方法对张量类型进行转化
a=torch.tensor((1,2)) print(a) b=a.float() print(b) c=a.double() print(c) d=a.short() print(d) # tensor([1, 2]) # tensor([1., 2.]) # tensor([1., 2.], dtype=torch.float64) # tensor([1, 2], dtype=torch.int16)
1.2 张量的维度与形变
说明:张量作为一组数的结构化表示,也有维度的概念。向量是一维数组,而矩阵就是二维数组。
1.2.1 不同维度的张量
1)用简单序列创建一维数组
t1=torch.tensor((1,2)) print(t1) # tensor([1, 2]) # 使用ndim属性查看张量的维度 print(t1.ndim) # 1 # 使用shape查看形状 print(t1.shape) #torch.Size([2])
2)用序列的序列创建二维张量(可以等价看成一个矩阵)
t=torch.tensor([[1,2],[3,4]]) print(t) print(t.ndim) print(t.shape) #torch.Size([2, 2]),二行二列 # len函数的返回结果代表t是由两个一维张量构成 print(len(t)) # numel方法返回的结果是t由4个数构成 print(t.numel())
3)零维张量
说明:该类型的张量只包含一个元素,但又不是单独一个数。同样,我们可以把零维张量视为拥有张量属性的一个数。张量可以在GPU上运行,Python原生的数值型对象不行,但零维张量可以
# 创建一个只有一个数单独一维张量 t1=torch.tensor([1]) # 创建零维张量 t2=torch.tensor(1) print(t1) print(t2) # tensor([1]) # tensor(1) # 查看张量长度 print(t1.ndim) print(t2.ndim) # 1 # 0
4)高维张量
说明:一般来说三维及以上的张量,我们称为高维张量。
a1=np.array([[1,2,3],[3,4,4]]) a2=np.array([[5,6,6],[7,8,8]]) print(a1) print(a2) t=torch.tensor([a1,a2]) print(t) ''' tensor([[[1, 2, 3], [3, 4, 4]], [[5, 6, 6], [7, 8, 8]]], dtype=torch.int32) ''' print(t.ndim) # 查看维度 # 3 print(t.shape) #torch.Size([2, 2, 3])解读方式: # 方式一: 2:2个矩阵构成;(2,3):每个矩阵都是2行3列 # 方式二:另一种解读方式:该张量是2个2维张量构成,每个2维张量又是由一维张量构成,每个一维张量有三个元素 # 拉平 print(t.reshape(t.numel())) # tensor([1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8], dtype=torch.int32)
1.2.2 张量的形变
1)flatten拉平:将任意维度张量转化为一维张量
t=torch.tensor([[1,2,3],[4,5,6]]) print(t) ''' tensor([[1, 2, 3], [4, 5, 6]]) ''' t1=t.flatten() print(t1) # tensor([1, 2, 3, 4, 5, 6]) 按行排列 # 注意:若是零维张量,也会转化为一维张量 a=torch.tensor(1) a1=a.flatten() print(a) print(a1) print(a.ndim) print(a1.ndim) # tensor(1) # tensor([1]) # 0 # 1
2)reshape方法:任意变形
t=torch.tensor([1,2]) print(t) # 转化为二行一列的张量 t1=t.reshape(2,1) print(t1) ''' tensor([1, 2]) tensor([[1], [2]]) ''' # 转化为一维张量 t3=t1.reshape(2) print(t3) # tensor([1, 2])
1.3 张量的索引、分片、合并以及维度调整
说明:张量作为有序的序列,也是具备数值索引的功能,并且基本索引方法与列表、数组一致。唯一区别的是,PyTorch还定义了一种用函数进行索引的方式
1.3.1 张量的符号索引
说明:张量是有序序列,可以根据每个元素在系统内的顺序编号找出特定的元素
1)一维张量索引
基本格式遵循:[start : end : step],step位必须大于0。在其他的step=-1,表示从后到前
t=torch.arange(1,11) print(t) # tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) print(t[0]) # tensor(1) 单独索引出来的结果依然是张量,不是单独一个数 t1=t[1:8] # 索引其中2-8,包含左不包含右 print(t1) # tensor([2, 3, 4, 5, 6, 7, 8]) # 隔两个取一个 print(t[1:8:2]) # tensor([2, 4, 6, 8]) # 从第二个开始索引,一直到结尾,并且每隔两个取一个 print(t[1::2]) # tensor([ 2, 4, 6, 8, 10])
2)二维张量索引
说明:二维张量的索引和一维张量索引逻辑基本相同,二维张量可以视为两个一维张量组合而成,在实际的索引过程中,需要用逗号进行分隔,分别表示对那个一维张量进行索引。
t=torch.arange(1,10).reshape(3,3) print(t) ''' tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) ''' # 索引第一行第二列元素 print(t[0,1]) # tensor(2) print(t[2,2]) # tensor(9) # 表示索引第一行 print(t[0,]) print(t[0,::2]) # tensor([1, 2, 3]) # tensor([1, 3])
3)三维张量的索引
说明:与二维张量操作差不多
t=torch.arange(1,28).reshape(3,3,3) #print(t) ''' tensor([[[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]]) ''' # 取14 print(t[1,1,1]) # tensor(14)
1.3.2 张量的函数索引
说明:使用index_select函数,通过指定index来对张量进行索引
t=torch.arange(1,11) print(t) # 查看t是几维的? print(t.ndim) print(t.shape) # 1 # torch.Size([10]) # 在index_select函数中,第二个参数实际表示索引的的维度,如下解释 indices=torch.tensor([0,1]) # 创建一个包含1,2两个数的一维张量 # 索引下标值为1,2的数 print(torch.index_select(t,0,indices)) # tensor([2, 3]) t1=torch.arange(12).reshape(4,3) print(t1) ''' tensor([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) ''' # 此处0 表示取(4,3)中的4,也就是行做参数 print(torch.index_select(t1,0,indices)) ''' tensor([[3, 4, 5], [6, 7, 8]]) ''' # 此处0 表示取(4,3)中的3,也就是列做参数 print(torch.index_select(t1,1,indices))
1.3.3 tensor.view()方法
说明:该方法类似视图的结果。该结构和原张量对象共享一块数据存储空间,并且通过.view()方法改变对象结构,生成不同的结构,但共享一个存储空间的张量。修改其中一个,另一个也做修改
t=torch.arange(6).reshape(2,3) #print(t) ''' tensor([[0, 1, 2], [3, 4, 5]]) ''' te=t.view(3,2) #print(te) ''' tensor([[0, 1], [2, 3], [4, 5]]) ''' t[0]=1 #0维全变成1 print(t) print(te) ''' tensor([[1, 1, 1], [3, 4, 5]]) tensor([[1, 1], [1, 3], [4, 5]]) '''
1.3.4 张量的分片函数
1)分块:chunk函数
说明:chunk函数能够按照某维度,对张量进行均匀切分,并且返回结果是原张量的视图
注意:若张量不能均匀等分,chunk不会报错,但会返回次级等分的结果
t=torch.arange(12).reshape(4,3) # print(t) ''' tensor([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) ''' # 在某零个维度(按行)进行四等分 tc=torch.chunk(t,4,dim=0) #dim=0表示安装行就行分割4块 print(tc) # 得到的还是二维张量 #(tensor([[0, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]]))
2)拆分:split函数
说明:split既能进行均分,也能进行自定义切分。与chunk一样,split返回结果也是view
t=torch.arange(12).reshape(4,3) # print(t) ''' tensor([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) ''' # 2:表示均分几份 0:表示切分的维度。0表示行,1表示列 print(torch.split(t,2,0)) ''' (tensor([[0, 1, 2], [3, 4, 5]]), tensor([[ 6, 7, 8], [ 9, 10, 11]])) ''' # 按照1:3的比例进行切分 print(torch.split(t,[1,3],0)) ''' (tensor([[0, 1, 2]]), tensor([[ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])) ''' # 按照1:1:1:1分 print(torch.split(t,[1,1,1,1],0)) ''' (tensor([[0, 1, 2]]), tensor([[3, 4, 5]]), tensor([[6, 7, 8]]), tensor([[ 9, 10, 11]])) ''' # 按照1:1:2分 print(torch.split(t,[1,1,2],0)) ''' (tensor([[0, 1, 2]]), tensor([[3, 4, 5]]), tensor([[ 6, 7, 8], [ 9, 10, 11]])) '''
1.3.5 张量的合并操作
说明:张量的合并操作类似与列表的追加元素,可以拼接,也可以堆叠
1)拼接函数:cat
注意:拼接注意形状的匹配
a=torch.zeros(2,3) # print(a) ''' tensor([[0., 0., 0.], [0., 0., 0.]]) ''' b=torch.ones(2,3) # print(b) ''' tensor([[1., 1., 1.], [1., 1., 1.]]) ''' c=torch.zeros(3,3) # print(c) ''' tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]) ''' d=torch.cat([a,b]) #默认按照行进行拼接 print(d) ''' tensor([[0., 0., 0.], [0., 0., 0.], [1., 1., 1.], [1., 1., 1.]]) ''' e=torch.cat([a,b],1) #按照列进行拼接 print(e) ''' tensor([[0., 0., 0., 1., 1., 1.], [0., 0., 0., 1., 1., 1.]]) '''
2)堆叠函数:stack
说明:和拼接不同,堆叠不是将元素拆分重载,而是简单的将各参与堆叠的对象分装到一个更高维度的张量里
注意:两个张量的大小形状必须一致
a=torch.zeros(2,3) # print(a) ''' tensor([[0., 0., 0.], [0., 0., 0.]]) ''' b=torch.ones(2,3) # print(b) ''' tensor([[1., 1., 1.], [1., 1., 1.]]) ''' c=torch.stack([a,b]) print(c) print(c.shape) ''' tensor([[[0., 0., 0.], [0., 0., 0.]], [[1., 1., 1.], [1., 1., 1.]]]) torch.Size([2, 2, 3]) '''