注:本文是笔者结合自己阅读和使用pytorch的经验,又系统学习了一遍https://github.com/chenyuntc/pytorch-book的过程中,将自己认为有必要掌握和记住的知识整理成的学习笔记,并非系统的教程,主要目的是为了方便自己梳理、记忆知识,以及方便有相同需求的读者查阅某些知识。
1、使用torch.Tensor创建
根据参数不同,具体分为两种
(1)如果参数直接是int,那么表示创建此形状
In [1]: torch.Tensor(2,3,4)
Out[1]: 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.]]])
(2)如果参数是list或tuple,表示将这个list或tuple转为tensor
In [1]: torch.Tensor([[1,2,3],[4,5,6]])
Out[1]: tensor([[1., 2., 3.],
[4., 5., 6.]])
2、使用torch.tensor创建:
参数只能是list或tuple,与torch.Tensor中情况(2)相似
In [1]: torch.tensor([[1,2,3], [4,5,6]])
Out[1]: tensor([[1, 2, 3],
[4, 5, 6]])
3、使用其他的函数,比如torch.ones, torch.zero, torch.arange等时,参数只能用int表示形状,即torch.Tensor的前一种
1、torch.view:
e.g. a = torch.randn(2,3),b = a.view(-1,6),此时a的形状并没有变,但ab已经共享了内存,如果修改a[1][2],那么b[0][5]也会跟着变
In [1]: a = torch.randn(2,3)
In [2]: b = a.view(-1,6)
In [3]: a[1][2] = 100
In [4]: b
Out[4]: tensor([[ -2.6326, -0.5585, 0.9266, 1.5645, 1.2182, 100.0000]])
1、区分“变形”和“变维”:形状为(2,3,4)的tensor变成(2,3,2),只“变形”,不“变维”,因为维度仍然是3维
2、用下标进行索引的话,如果其中某一维指定为了一个数而不是一个区间的话,得到的tensor会降维,比如a = torch.randn(2,3,4),则a[:,0,:]的size为(2,4),可见该tensor是降维了;如果所有下标都是区间,那么只可能变形,不可能降维,比如a[:,:2,1:4]的size为(2,2,3),在下标都是区间时,有a[:] = a[:,:],也就是说不说明的维度默认是全部拉满
3、在使用下标进行索引时,可以用None实现增加维度,原则是 哪里写None哪里增加维度:e.g. a = torch.randn(3,4),则a[:,None,:,None,None]的size为(3,1,4,1,1),注意a[None]表示在最前面增维,即a[None]的size为(1,3,4)
4、index_select函数:
index_select(x, dim, index)
x是原始tensor,dim是一个int,表示在哪一维上取数,index是一个一维的LongTensor,里面放的是全部在第dim维要索引的内容;index_select后得到的结果与x相比只变形,不变维,哪怕index里只有一个数
In [1]: a = torch.randn(2,3)
In [2]: a
Out[2]: tensor([[ 8.7729e-01, -1.0760e-03, -4.6932e-01],
[-8.6138e-02, 1.8144e+00, 1.1691e+00]])
In [3]: indices = torch.LongTensor([0])
In [4]: b = torch.index_select(a, 0, indices)
In [5]: b, b.size()
Out[5]: (tensor([[ 0.8773, -0.0011, -0.4693]]), torch.Size([1, 3]))
5、mask式取值:
mask取值的目的是从一个tensor(假设叫a)中取出其中的一部分值,这些取出的值将构成一个一维的tensor,注意mask式取值的结果一定是一个一维的tensor。至于取哪些值,我们需要一个mask,这个mask与a同形,且它的dtype要求是uint8。比如我们希望从a中取出所有大于0的值
In [1]: a = torch.randn(3,4)
In [2]: a
Out[2]: tensor([[-0.4152, 1.4335, 0.2631, -0.6139],
[-0.8419, -0.1434, 0.3215, 1.1045],
[ 0.5557, -1.7449, -0.0087, 0.3759]])
在pytorch中,一个tensor与数字比较得到的就是一个dtype是uint8的同形tensor
In [3]: a > 0
Out[3]: tensor([[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 0, 0]], dtype=torch.uint8)
在有了原张量a和mask张量后,两种方法可以实现mask式取值
In [4]: a[a>1] #方法一
Out[4]: tensor([1.4335, 1.1045])
In [5]: torch.masked_select(a, a>1) #方法二
Out[5]: tensor([1.4335, 1.1045])
6、对tensor的任何索引操作仍是一个tensor,想要获取标准的python对象数值,需要调用tensor.item()
, 这个方法只对包含一个元素的tensor适用
对于一个tensor x,假设其维数为dim,可以用dim个等长的列表进行索引
In [1]: x = torch.arange(0,27).view(3,3,3)
In [2]: x
Out[2]: tensor([[[ 0., 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.]]])
In [3]: x[[1, 2], [1, 2], [2, 0]] # x[1,1,2]和x[2,2,0]
Out[3]: tensor([ 14., 24.])
如果dim个列表不等长,则相当于做一个多重的for进行枚举
In [4]: x[[2, 1, 0], [0], [1]] # x[2,0,1],x[1,0,1],x[0,0,1]
Out[4]: tensor([ 19., 10., 1.])
还可以使用...,此时返回的不再是一维的tensor
In [5]: x[[0, 2], ...] # x[0] 和 x[2]
Out[5]: tensor([[[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.]],
[[ 18., 19., 20.],
[ 21., 22., 23.],
[ 24., 25., 26.]]])
根据tensor中元素的数据类型的不同,tensor又分为诸如32位浮点数、64位浮点数、8位整数、16位整数等多种类型;其中,每个数据类型又对应CPU版本和GPU版本两种。第一列表示的就是所有的数据类型。
1、默认的tensor类型
默认的tensor类型为32位的浮点数类型,也就是第一行。可以通过torch.set_default_tensor_type函数设置默认的tensor类型,其参数是第三列或第四列中的对应值,比如torch.set_default_tensor_type('torch.IntTensor')可以使32位int型tensor作为默认的tensor数据类型
2、特定数据类型tensor的创建
对应本文最开始tensor的创建,创建特定类型的tensor的方式也是有着对应的两种:
(1)使用第三四列创建:比如torch.DoubleTensor(3,4)创建一个3*4的张量,或者torch.LongTensor([2,3,4])创建一个一维张量;其实torch.Tensor创建张量就是这种方法的一个特例,其类型为默认类型
(2)使用torch.tensor方法创建tensor:这时可以通过制定一个参数dtype为第二列中的某一个,实现创建特定数据类型的tensor,比如torch.tensor([[1,4,3], [2,3,6]], dtype=torch.int64)
3、不同数据类型tensor的转换
可以直接调用tensor的type方法,其参数为第三列或第四列中对应的类型
In [1]: a = torch.Tensor(2,3)
In [2]: a.dtype
Out[2]: torch.float32
In [3]: a = a.type(torch.DoubleTensor)
Out[3]: torch.float64
4、GPU与CPU版本的转换
对于一个张量a,在GPU与CPU之间主要有两种方法:
(1)a.cpu() 转换为CPU版本,a.cuda()转换为GPU版本
(2)a.to(device)转换为相应的版本