暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一文详解PyTorch常用tensor操作

南极Python 2021-04-06
1158

图源: Ricardo Gomez Angel on Unsplash


#二话不说,先把包导入进来~
import torch

tensor初始化

#定义一个tensor
my_tensor=torch.tensor([[1,2,3],[4,5,6]])
print(my_tensor)

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

#指定tensor的数据类型
my_tensor=torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float32)
print(my_tensor)

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

#指定device
my_tensor=torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float32,device='cuda')
print(my_tensor)

tensor([[1., 2., 3.],
[4., 5., 6.]], device='cuda:0')

#如果有gpu则使用gpu,此时device='cuda',否则使用cpu
device="cuda" if torch.cuda.is_available() else "cpu"
print(device)

cuda

#requires_grad:是否可被求导
#一般来说,神经网络学习的权重是可导的(requires_grad=True)
my_tensor=torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float32,device='cuda',requires_grad=True)
print(my_tensor)

tensor([[1., 2., 3.],
[4., 5., 6.]], device='cuda:0', requires_grad=True)

print(my_tensor.device)
print(my_tensor.requires_grad)
print(my_tensor.dtype)
print(my_tensor.shape)

cuda:0
True
torch.float32
torch.Size([2, 3])

x=torch.empty(size=(3,3))
print(x)

tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])

#全0张量
x=torch.zeros((3,3))
print(x)

#全1张良
x=torch.ones((3,3))
print(x)

tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])

#元素为随机数的张量
x=torch.rand((3,3))
print(x)

tensor([[0.4704, 0.6278, 0.2294],
[0.1838, 0.4951, 0.8452],
[0.7331, 0.8264, 0.9475]])

#从0到9之间随机采样整数组成张量的元素
x=torch.randint(10, (22))#等价于torch.randint(0,10, (2, 2))
print(x)

tensor([[7, 8],
[9, 3]])

#从标准正态分布中采样随机数
x = torch.randn(23)
print(x)

tensor([[ 0.7711, -1.2354, -0.6476],
[ 1.2426, -0.8406, -1.1450]])

#单位阵
x=torch.eye(5,5)
print(x)

tensor([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])

#整数序列
x=torch.arange(start=0,end=5,step=1)
print(x)

tensor([0, 1, 2, 3, 4])

#将从start到end之间的steps个数字作为张量x的元素
x=torch.linspace(start=0.1,end=1,steps=10)
print(x)

tensor([0.1000, 0.2000, 0.3000, 0.4000, 0.5000, 0.6000, 0.7000, 0.8000, 0.9000,
1.0000])

#从标准正态分布中随机采样
x=torch.empty(size=(1,5)).normal_(mean=0,std=1)
print(x)

tensor([[ 0.3601, -1.2583, -0.1399,  0.9521,  1.1094]])

#从均匀分布中随机采样
x=torch.empty(size=(1,5)).uniform_(0,1)
print(x)

tensor([[0.7726, 0.3465, 0.3890, 0.4156, 0.4586]])

#输入是一个向量,返回一个以输入向量为对角线元素的对角阵
x=torch.diag(torch.ones(3))
print(x)

#或者输入一个矩阵,返回一个向量
xx=torch.diag(torch.ones(3,6))
print(xx)

tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
tensor([1., 1., 1.])

tensor数据类型转换

#tensor数据类型转换
tensor=torch.arange(4)
print('tensor:',tensor)
print('tensor.bool:',tensor.bool())
print('tensor.short():',tensor.short())
print('tensor.long():',tensor.long())
print('tensor.long().dtype:',tensor.long().dtype)
print('tensor.half():',tensor.half())
print('tensor.float():',tensor.float())
print('tensor.float().dtype:',tensor.float().dtype)
print('tensor.double():',tensor.double())

tensor: tensor([0, 1, 2, 3])
tensor.bool: tensor([False, True, True, True])
tensor.short(): tensor([0, 1, 2, 3], dtype=torch.int16)
tensor.long(): tensor([0, 1, 2, 3])
tensor.long().dtype: torch.int64
tensor.half(): tensor([0., 1., 2., 3.], dtype=torch.float16)
tensor.float(): tensor([0., 1., 2., 3.])
tensor.float().dtype: torch.float32
tensor.double(): tensor([0., 1., 2., 3.], dtype=torch.float64)

tensor与np array 互转

import numpy as np
np_array=np.zeros((5,5))

#从np.array转tensor
tensor=torch.from_numpy(np_array)
print(tensor)

tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]], dtype=torch.float64)

#tensor转np.array
np_array_back=tensor.numpy()
print(np_array_back)

[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]

tensor的数学运算

x=torch.tensor([1,2,3])
y=torch.tensor([9,8,7])

z1=torch.empty(3)
#tensor加法
z1=torch.add(x,y,out=z1)
print(z1)

#也可以这样做加法
z2=torch.add(x,y)
print(z2)

#更常用的加法操作是这个
z=x+y
print(z)

tensor([10., 10., 10.])
tensor([10, 10, 10])
tensor([10, 10, 10])

#tensor减法
z=x-y
print(z)

tensor([-8, -6, -4])

#逐点除法
z=torch.true_divide(x,y)
print(z)

tensor([0.1111, 0.2500, 0.4286])

#inplace operations
#直接在原位置修改(inplace:原地修改),无需开副本
t=torch.zeros(3)
t.add_(x)
print(t)

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

#高阶运算
x=torch.tensor([1,2,3])
z=x.pow(2)
print(z)

#也可以这样,和Python一样操作
z=x**2
print(z)

tensor([1, 4, 9])
tensor([1, 4, 9])

#比较
x=torch.tensor([1,0,3])
z=x>0
print(z)

tensor([ True, False,  True])

#矩阵乘法
x1=torch.rand((2,5))
x2=torch.rand((5,3))
x3=torch.mm(x1,x2) #shape:2*3,等价于x3=x1.mm(x2)
print(x3.shape)

torch.Size([2, 3])

#高阶矩阵操作
#matrix_exp=torch.rand((5,5))
matrix_exp=torch.tensor([[1,2],[3,4]],dtype=torch.float)
print(matrix_exp.matrix_power(3))

#上面等价于矩阵做3次自身乘法
torch.mm(matrix_exp,matrix_exp).mm(matrix_exp)

tensor([[ 37.,  54.],
[ 81., 118.]])


tensor([[ 37., 54.],
[ 81., 118.]])

# 向量点乘(相当于把其中一个向量转置,然后两个向量做矩阵乘法)
x=torch.tensor([1,2,3])
y=torch.tensor([9,8,7])
z=torch.dot(x,y)
print(z)

tensor(46)

#点对点矩阵乘法
x=torch.tensor([1,2,3])
y=torch.tensor([9,8,7])
z=x*y
print(z)

tensor([ 9, 16, 21])

# 批量矩阵乘法
batch=32
n=10
m=20
p=30

tensor1=torch.rand((batch,n,m))
tensor2=torch.rand(batch,m,n)
out_bmm=torch.bmm(tensor1,tensor2)
print(out_bmm.shape)#(batch,n,n)

torch.Size([32, 10, 10])

#广播
x1=torch.tensor([[1,2,3],[4,5,6]])
x2=torch.tensor([2,3,1])

#自动复制x2作为新的一行

z=x1-x2
print(z)

zz=x1**x2
print(zz)

tensor([[-1, -1,  2],
[ 2, 2, 5]])
tensor([[ 1, 8, 3],
[ 16, 125, 6]])

#Other  useful tensor operations
x=torch.tensor([[5,2,3],[4,5,-1]])
y=torch.tensor([[5,2,3],[4,7,6]])

#按照dim0对tensor求和
su_x=torch.sum(x,dim=0)
print('su_x:',su_x)

#求tensor中最大值及其索引
values,indices=torch.max(x,dim=0)
print('values:{},indices:{}'.format(values,indices))

#求tensor的绝对值
abs_x=torch.abs(x)
print('abs_x:',abs_x)

#最大值索引
argmax=torch.argmax(x,dim=0)
print('argmax:',argmax)

#最小值索引
argmin=torch.argmin(x,dim=0)
print('argmin:',argmin)

#按照dim0求均值
mean_x=torch.mean(x.float(),dim=0)#必须是float
print('mean_x:',mean_x)

#比较两个tensor元素值是否相等,返回布尔值
eq=torch.eq(x,y)
print('eq:',eq)

#按dim0对y进行排序,在处理目标检测框时常用
print('sort:',torch.sort(y,dim=0,descending=False))

#超出[0,10]的全部改成0或10,小于0-->0,大于0-->10
print('x after clamp:',torch.clamp(x,min=0,max=10))

su_x: tensor([9, 7, 2])
values:tensor([5, 5, 3]),indices:tensor([0, 1, 0])
abs_x: tensor([[5, 2, 3],
[4, 5, 1]])
argmax: tensor([0, 1, 0])
argmin: tensor([1, 0, 1])
mean_x: tensor([4.5000, 3.5000, 1.0000])
eq: tensor([[ True, True, True],
[ True, False, False]])
sort: torch.return_types.sort(
values=tensor([[4, 2, 3],
[5, 7, 6]]),
indices=tensor([[1, 0, 0],
[0, 1, 1]]))
x after clamp: tensor([[5, 2, 3],
[4, 5, 0]])

x=torch.tensor([1,0,1,1,1],dtype=torch.bool)

#x中只要有一个为True,z就是True
z=torch.any(x)
print(z)

#x中全部为True才返回True
zz=torch.all(x)
print(zz)

tensor(True)
tensor(False)

tensor索引

batch_size=10
features=25
x=torch.rand((batch_size,features))

print(x.shape)
print(x[0].shape)

torch.Size([10, 25])
torch.Size([25])

print(x[:,0].shape)

torch.Size([10])

print(x[2,0:10].shape)

torch.Size([10])

x[0,0]=10
print(x[0,0])

tensor(10.)

#fancy indexing
x=torch.arange(10)
print(x)

#取下标为2,5,8位置处的元素
indices=[2,5,8]
print(x[indices])

tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
tensor([2, 5, 8])

x=torch.tensor([[1,2,3,4],[5,6,7,8],[9,8,7,6]])
rows=torch.tensor([1,0])
cols=torch.tensor([2,0])
#取(1,2),(0,0)索引对应元素,注意下标从0开始
print(x[rows,cols])

tensor([7, 1])

x=torch.arange(10)
print(x[(x<2)|(x>8)])
print(x[(x<2)&(x>8)])#没有满足这个条件的元素
print(x[x.remainder(2)==0])#取模2得0的元素

tensor([0, 1, 9])
tensor([], dtype=torch.int64)
tensor([0, 2, 4, 6, 8])

#uselful operations
x=torch.arange(10)
#对于x中的每个元素,大于5的不变,其余乘以2
print(torch.where(x>5,x,x*2))

tensor([ 0,  2,  4,  6,  8, 10,  6,  7,  8,  9])

#去重
print(torch.tensor([0,0,1,2,2,3]).unique())

tensor([0, 1, 2, 3])

x=torch.rand((4,5,3))
print(x.ndimension())#总共有几维
print(x.numel())#计算元素总个数:4*5*3=60

3
60

tesnor reshape

x=torch.arange(9)
#view只能改变类型为contiguous的张量
#如果tensor使用过transpose, permute等操作,会使得tensor变得在内存中不连续
#而reshape没有这个限制
x2=x.reshape(3,3)
print(x1)
print(x2)

tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

x=torch.arange(9)
y=x1.t()#转置
print(y)

yy=x1.t()
print(yy)

tensor([[0, 3, 6],
[1, 4, 7],
[2, 5, 8]])
tensor([[0, 3, 6],
[1, 4, 7],
[2, 5, 8]])

x1=torch.rand(2,5)
x2=torch.rand(2,5)
#在特定axis上做拼接
print(torch.cat((x1,x2),dim=0).shape)
print(torch.cat((x1,x2),dim=1).shape)

torch.Size([4, 5])
torch.Size([2, 10])

#相当于flatten
z=x1.view(-1)
print(z.shape)

torch.Size([10])

#相当于做批量flatten
batch=64
x=torch.rand((batch,2,5))
z=x.view(batch,-1)
print(z.shape)

torch.Size([64, 10])

#改变维度所在axis,类似于二维的转置
z=x.permute(0,2,1)
print(z.shape)

torch.Size([64, 5, 2])

#维度压缩
x=torch.arange(10)
print(x.unsqueeze(0).shape)
print(x.unsqueeze(1).shape)
print(x.shape)

torch.Size([1, 10])
torch.Size([10, 1])
torch.Size([10])

#维度扩增
x=torch.arange(10).unsqueeze(0).unsqueeze(1)
print(x.shape)
z=x.squeeze(1)#去掉axis1
print(z.shape)

torch.Size([1, 1, 10])
torch.Size([1, 10])

以上内容大部分总结自一个YouTube小哥的视频,大家可以去看一下:https://www.youtube.com/watch?v=x9JiIFvlUwk

当然,为了照顾无法科学上网的小伙伴,我已经将其搬运到了万能的B站:https://www.bilibili.com/video/BV19v411j7Xd/

多年以后,

在一个风和日丽的午后,

一个老人躺在摇椅上晒着太阳,

有一个小孩大叫道:“爷爷,爷爷,你的推文有人点赞啦!”

文章转载自南极Python,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论