pytorch学习笔记2

注:本文是笔者结合自己阅读和使用pytorch的经验,又系统学习了一遍https://github.com/chenyuntc/pytorch-book的过程中,将自己认为有必要掌握和记住的知识整理成的学习笔记,并非系统的教程,主要目的是为了方便自己梳理、记忆知识,以及方便有相同需求的读者查阅某些知识。

逐元素操作

1、在pytorch中,不仅仅针对逐元素的操作,tensor的计算往往具有两种形式,比如torch.mul(a, b)与a.mul(b)二者是等价的

2、记住这些逐元素运算对应的符号:

绝对值 / 平方根 / 取模 / 求幂 / 乘法 / 除法 / 以e为底求指数 / 取ln / 向上取整 / 向下取整 / 四舍五入 / 取整数部分 / 取小数部分 / 正弦 / 余弦 

abs / sqrt / fmod / pow / mul / div / exp / log / ceil / floor / round / trunc / frac / sin / cos

3、mul和div表示的是逐元素乘或逐元素除,不要把mul和矩阵乘搞混了;mul和div在pytorch中被重载为了*和/,也就是说*和/表示的是逐元素乘或者逐元素除,不要把*和矩阵乘搞混了;另外,mul和div要求参与运算的要么是形状完全一致的两个tensor,要么是前者是一个tensor,而后者是一个数字

4、取对数只有torch.log(),torch.log2(),torch.log10(),其他底可以换底公式换出来;求指数exp默认以e为底,但是torch.pow很灵活,假如a = torch.tensor([1,2,3]),既可以torch.pow(a,2)表示tensor([1^2,2^2,3^2]),也可以torch.pow(2,a)表示tensor([2^1,2^2,2^3])。

5、逐元素操作还有torch.sigmoid和torch.tanh等激活函数,但是这些激活函数在torch.nn中也存在

归并操作

1、记住这些归并操作对应的符号:

均值 / 求和 / 中位数 / 众数 / 范数 / 欧式距离 /  标准差 / 方差

mean / sum / median / mode / norm / dist / std / var

2、使用归并操作的时候需要考虑两个参数,dim和keep_dim,当这两个参数都被设置的时候,输出的形状如下:

假设输入形状为(m, n, k),那么根据不同的dim和keep_dim得到的tensor形状如下表

  keep_dim=True keep_dim=False
dim=0 (1, n, k) (n, k)
dim=1 (m, 1, k) (m, k)
dim=2 (m, n, 1) (m, n)

 

3、如果不指定dim,那么得到的会是一个只有一个元素的tensor,比如tensor(100);如果不指定keep_dim,keep_dim默认为False

4、对于dim的理解:假设输入的tensor A形状为(m, n, k),假设做的是求和操作,且指定dim=1,根据2,得到的tensor B的形状是(m, k),A和B满足B_[i, j] = \sum_{t=0}^{n}A_[i, k, j]

In [1]: a = t.arange(24)
In [2]: b = a.view(2, 3, 4)
In [3]: b
Out[3]: 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]]])
In [4]: c = t.sum(b, dim=1)
In [5]: c, c.size()
Out[5]: (tensor([[12, 15, 18, 21],
                 [48, 51, 54, 57]]), torch.Size([2, 4]))

比较操作

1、gt(大于)/  lt(小于)/  ge(大于等于)/ le(小于等于)/ eq(等于)/ ne(不等于),这些分别被重载为了> / < / >= / <= / == / !=,需要注意的是前面提到过的一点,两个tensor通过比较操作得到的是一个ByteTensor(即dtype=torch.uint8),这种tensor是可以以mask的方式直接作为同形状tensor的索引的

2、torch.max和torch.min的使用,以torch.max为例,根据参数不同共有三种用法

(1) torch.max(tensor)       返回的是只含一个元素的tensor,这个元素是输入tensor中最大的元素

(2)torch.max(tensor, dim)      返回指定维上较大的数,以及其所在下标;torch.max在这种输入和上一种输入放在一起看,可以看做是一个归并操作,只是多返回一个较大数所在的下标

(2)torch.max(tensor, tensor)      要求输入的两个tensor同形状,输出也是同形状的,输出的每个位置对应的是两个tensor中那个位置上较大的数

In [1]: a = t.randn(2, 3)
In [2]: a
Out[2]: tensor([[ 1.0437,  0.6610, -0.1947],
                [-1.7523,  1.7876,  0.6388]])
In [3]: b = t.randn(2, 3)
Out[3]: tensor([[-0.3039,  1.0680, -0.2654],
                [ 0.5515, -1.3597, -0.8332]])
In [4]: t.max(a)
Out[4]: tensor(1.7876)
In [5]: t.max(a, dim=1) # 注意输出是一个元组,分别是较大的数和所在的下标
Out[5]: (tensor([1.0437, 1.7876]), tensor([0, 1]))
In [6]: t.max(a, b)
Out[6]: tensor([[ 1.0437,  1.0680, -0.1947],
                [ 0.5515,  1.7876,  0.6388]])

3、torch.topk(input, k, dim=None, largest=True, sorted=True)

参数

input(Tensor)

k(int)

dim(int):假设输入的tensor A形状是(m, n, p),且dim=1,做topk之后得到的tensor B的形状是(m, k, p),其中B[i,:,j]中的k个元素是A[i,:,j]中n个元素中挑出的前k个;不指定dim时,dim默认为最后一维

largest(Boolean):默认为True,为True表示取前k大,为False表示取前k小

sorted(Boolean):默认为True,假设挑出的是前k大,为True时这k个元素按从大到小的顺序排序,为False时只是保证是前k大,并不一定有序

输出:输出一个tuple,里面是两个tensor,前一个tensor是topk的元素,后一个tensor是topk的下标,这两个tensor是同形状的。假设输入的tensor形状为(p, q, m),k=K,dim=1,largest和sorted为True,那么输出的这两个tensor形状均为(p, K, m)。

In [1]: a = t.randn(2, 3)
In [2]: a
Out[2]: tensor([[ 0.5339,  0.2233,  2.5735],
                [-2.0343, -1.5293, -0.1112]])
In [3]: b = t.topk(a, k=2, dim=1)
In [4]: b
Out[4]: (tensor([[ 2.5735,  0.5339],
                 [-0.1112, -1.5293]]), 
        tensor([[2, 0],
                [2, 1]]))
In [5]: c = t.topk(a, k=1, dim=0)
In [6]: c
Out[6]: ( tensor([[0.5339, 0.2233, 2.5735]]), tensor([[0, 0, 0]]) )

4、torch.sort(input, dim=-1, descending=False)

参数

input(Tensor)

dim(int):假设输入的tensor A的形状为(m, n, p),且dim=1,那么排序后的得到的tensor B中,B[i, :, j]是排序后的A[i, :, j],不显式指定时dim默认为最后一维

descending(Boolean):默认为False,为False时元素升序排列,否则降序排列

输出:输出一个tuple,里面有两个tensor,前一个是排序的结果,后一个是排序后tensor对应排序前的下标,两个tensor是同形状的。假设输入tensor的形状为(m, n, p),则输出的两个tensor都是(m, n, p)的。

In [1]: a = t.randn(2, 3)
In [2]: a
Out[2]: tensor([[-0.1060, -0.2755,  1.2596],
                [ 1.2688,  0.1467, -0.4233]])
In [3]: t.sort(a, dim=0)
Out[3]: (tensor([[-0.1060, -0.2755, -0.4233],
                 [ 1.2688,  0.1467,  1.2596]]),
         tensor([[0, 0, 1],
                 [1, 1, 0]]))
In [4]: t.sort(a, dim=1)
Out[4]: (tensor([[-0.2755, -0.1060,  1.2596],
                 [-0.4233,  0.1467,  1.2688]]), 
         tensor([[1, 0, 2],
                 [2, 1, 0]]))

线性代数

1、矩阵转置

对于一个2D的tensor A,A.t()得到其转置,需要注意的是转置后空间不再连续,需要调用.contiguous()方法令其连续

2、mm和bmm和matmul

(1) mm:两个2D的tensor A和B相乘,其中A的形状是(n, p),B的形状是(p, m),输出的形状是(n, m)

(2) bmm:两个3D的tensor A和B相乘,其中A的形状是(batch_size, n, p),B的形状是(batch_size, p, m),输出的形状是(batch_size , n, m),一个batch里的每个矩阵对应相乘

(3) matmul:根据参与运算的两个tensor A和B的形状,有很多种情况,但记忆的时候可以分四类记:

①A和B都是1D的tensor(向量)时,返回的是向量的内积;

②A和B分别是2D的n*p和p*m的矩阵时,返回的矩阵乘法的结果(n*m的矩阵);

③A和B分别是3D的batch_size*n*p和batch_size*p*m的矩阵时,返回的是每个batch中对应矩阵相乘的结果(batch_size*n*m的矩阵)

④其余情况均是A和B维数不等的情况,此时根据广播法则来确定计算方法

广播机制

1、广播机制在pytorch和numpy中均是存在的,广播机制指的是在下面的两个条件成立时,会自动扩展一个向量进行运算:

(1)两个tensor之间进行的操作是一个逐元素操作(当然,大于小于这类比较也算)

(2)两个tensor的维度中尾部的几个维度是一样的,如果tensor A的形状是(Adim1, Adim2, ..., AdimN),tensor B的形状是(Bdim1, Bdim2, ..., BdimM),维度中尾部的几个维度一致是指Adim(N-M+1)=Bdim1, Adim(N-M+2)=Bdim2, ..., AdimN=BdimM

In [1]: a = t.arange(24).view(2, 3, 4)
In [2]: a
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]]])
In [3]: b = t.ones(4, dtype=t.int64)
In [4]: a + b
Out[4]: 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]]])

2、但是,在pytorch中,许多非逐元素的操作也是支持广播机制的,比如上面提到的matmul操作:对于两个参与运算的tensor A和B,如果他们的维数不相等(情况④),那么首先在维数较短的tensor(假设是B)前面补1使得维数一致,然后把B扩展为之前的几份使得补1位置的形状与tensor A一致,最后如果A和B符合的①②③中的任一条,那么就可以进行运算

In [1]: a = t.randn(3, 4)
In [2]: b = t.randn(4)
In [3]: t.matmul(a, b).size()
Out[3]: torch.Size([3])
In [4]: a = t.randn(10, 3, 4)
In [5]: b = t.randn(4, 5)
In [6]: t.matmul(a, b)
Out[6]: torch.Size([10, 3, 5])
In [7]: a = t.randn(2, 10, 3, 4)
In [8]: b = t.randn(4, 5)
In [9]: t.matmul(a, b)
Out[9]: torch.Size([2, 10, 3, 5])

 

tensor和numpy对象转换

1、如果a是numpy对象,可以用b = t.Tensor(a)或b = t.tensor(a)得到tensor,注意前者ab共享内存,后者是拷贝得到不共享内存

2、如果a是tensor对象,可以用b = a.numpy()得到numpy对象,此时ab共享内存

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章