目录
前言
Tensor,又名张量,读者可能对这个名词似曾相识,因它不仅在PyTorch中出现过,它也是Theano、TensorFlow、 Torch和MxNet中重要的数据结构。关于张量的本质不乏深度的剖析,但从工程角度来讲,可简单地认为它就是一个数组,且支持高效的科学计算。它可以是一个数(标量)、一维数组(向量)、二维数组(矩阵)和更高维的数组(高阶数据)。Tensor和Numpy的ndarrays类似,但PyTorch的tensor支持GPU加速。
从接口的角度来讲,对tensor的操作可分为两类:
torch.function
,如torch.save
等。- 另一类是
tensor.function
,如tensor.view
等。
创建Tensor
# 指定tensor的形状
a = t.Tensor(2, 3)
a # 数值取决于内存空间的状态,print时候可能overflow
# 用list的数据创建tensor
b = t.Tensor([[1,2,3],[4,5,6]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[1., 2., 3.],
[4., 5., 6.]])
b.tolist() # 把tensor转为list
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
tensor.size()
返回torch.Size
对象,它是tuple的子类,但其使用方式与tuple略有区别
b_size = b.size()
b_size
torch.Size([2, 3])
b.numel() # b中元素总个数,2*3,等价于b.nelement()
6
# 创建一个和b形状一样的tensor
c = t.Tensor(b_size)
# 创建一个元素为2和3的tensor
d = t.Tensor((2, 3))
c, d
c.shape
(tensor([[ 0.0000e+00, -3.6893e+19, 0.0000e+00],
[-3.6893e+19, 1.1210e-44, 0.0000e+00]]),
tensor([2., 3.]))
torch.Size([2, 3])
需要注意的是,t.Tensor(*sizes)
创建tensor时,系统不会马上分配空间,只是会计算剩余的内存是否足够使用,使用到tensor时才会分配,而其它操作都是在创建完tensor之后马上进行空间分配。其它常用的创建tensor的方法举例如下。
t.ones(2, 3)
t.zeros(2, 3)
t.arange(1, 6, 2)
t.linspace(1, 10, 3)
t.randn(2, 3, device=t.device('cpu'))
t.randperm(5) # 长度为5的随机排列
t.eye(2, 3, dtype=t.int) # 对角线为1, 不要求行列数一致
matrix = t.tensor([[0.1, 1.2], [2.2, 3.1], [4.9, 5.2]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([1, 3, 5])
tensor([ 1.0000, 5.5000, 10.0000])
tensor([[-1.8092, 0.3073, 1.1810],
[ 0.4181, -0.8576, -0.2911]])
tensor([0, 2, 1, 3, 4])
tensor([[1, 0, 0],
[0, 1, 0]], dtype=torch.int32)
tensor([[0.1000, 1.2000],
[2.2000, 3.1000],
[4.9000, 5.2000]])
二、Tensor的常用操作
通过tensor.view
方法可以调整tensor的形状,但必须保证调整前后元素总数一致。view
不会修改自身的数据,返回的新tensor与源tensor共享内存,也即更改其中的一个,另外一个也会跟着改变。在实际应用中可能经常需要添加或减少某一维度,这时候squeeze
和unsqueeze
两个函数就派上用场了。
a = t.arange(0, 6)
a.view(2, 3)
b = a.view(-1, 3) # 当某一维为-1的时候,会自动计算它的大小
b.shape
tensor([[0, 1, 2],
[3, 4, 5]])
torch.Size([2, 3])
b.unsqueeze(1) # 注意形状,在第1维(下标从0开始)上增加“1”
#等价于 b[:,None]
b[:, None].shape
b.unsqueeze(-2) # -2表示倒数第二个维度
c = b.view(1, 1, 1, 2, 3)
c.squeeze(0) # 压缩第0维的“1”
c.squeeze() # 把所有维度为“1”的压缩
torch.Size([2, 1, 3])
tensor([[[1., 2., 3.]],
[[4., 5., 6.]]])
tensor([[[[1., 2., 3.],
[4., 5., 6.]]]])
tensor([[1., 2., 3.],
[4., 5., 6.]])
a[1] = 100
b # a修改,b作为view之后的,也会跟着修改
tensor([[ 0, 100, 2],
[ 3, 4, 5]])
resize
是另一种可用来调整size
的方法,但与view
不同,它可以修改tensor的大小。如果新大小超过了原大小,会自动分配新的内存空间,而如果新大小小于原大小,则之前的数据依旧会被保存,看一个例子。
b.resize_(1, 3)
b
b.resize_(3, 3) # 旧的数据依旧保存着,多出的大小会分配新空间
b
tensor([[ 0, 100, 2]])
tensor([[ 0, 100, 2],
[ 3, 4, 5],
[ 0, 0, 0]])
总结
本节为tensor的基础操作,包括创建Tensor以及部分常用操作