zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【PyTorch】-了解张量(Tensor)

PyTorch 了解 Tensor 张量
2023-09-27 14:26:28 时间

🤖🤖🤖🤖 欢迎浏览本博客 🤖🤖🤖🤖
😆😆😆😆😆😆😆大家好,我是:我菜就爱学😆😆😆😆😆一名刚刚入行的小白👻👻
👻👻从事方向:计算机视觉 😆😆
🔔🔔我菜就爱学,分享有误,欢迎大佬指出🔔🔔
🌏🌏🌏本篇介绍:张量—深度学习的数据结构


说明:我们可以把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])
'''