pytorch学习8:Tensor

作者: bdb87b292706 | 来源:发表于2018-08-02 10:48 被阅读271次

    虽然我在前面写到没有必要去阅读整个官方文档,但是在开发过程中发现,如果对整个文档特别是关于tensor的操作和函数有一定的了解,那么实际运用起来是事半功倍的。只能说一句“真香”来概括我现在的心情了。所以后面还是会详细的把官方文档中所有的函数做一个学习和总结。这一部分工程量很大,不知道啥时候可以完成。。。。

    Tensors

    属性相关

    torch.is_tensor(obj)
    

    用来判断obj是否为一个tensor变量。同样的还有torch.is_storage(obj)用于判断变量是否为一个storage变量。

    torch.set_default_dtype(d)
    

    用于改变tensor中数据的默认类型,如下面的例子:

    >>> torch.tensor([1.2, 3]).dtype           # initial default for floating point is torch.float32
    torch.float32
    >>> torch.set_default_dtype(torch.float64)
    >>> torch.tensor([1.2, 3]).dtype           # a new floating point tensor
    torch.float64
    

    所有支持的数据类型如下表所示:


    tensor数据类型

    想要得到tensor中默认的数据类型,可以使用:torch.get_default_dtype(),如下面的这个例子:

    >>> torch.get_default_dtype()  # initial default for floating point is torch.float32
    torch.float32
    >>> torch.set_default_dtype(torch.float64)
    >>> torch.get_default_dtype()  # default is now changed to torch.float64
    torch.float64
    >>> torch.set_default_tensor_type(torch.FloatTensor)  # setting tensor type also affects this
    >>> torch.get_default_dtype()  # changed to torch.float32, the dtype for torch.FloatTensor
    torch.float32
    

    同时也提供了设置默认的tensor的数据类型的函数,但是我没看懂这个和前面的做法有什么区别:

    torch.set_default_tensor_type(t)
    

    例子如下:

    >>> torch.tensor([1.2, 3]).dtype    # initial default for floating point is torch.float32
    torch.float32
    >>> torch.set_default_tensor_type(torch.DoubleTensor)
    >>> torch.tensor([1.2, 3]).dtype    # a new floating point tensor
    torch.float64
    

    为了得到tensor中所有的元素个数可以使用:

    torch.numel(input)
    

    函数返回一个int型的数据,例子如下:

    >>> a = torch.randn(1, 2, 3, 4, 5)
    >>> torch.numel(a)
    120
    >>> a = torch.zeros(4,4)
    >>> torch.numel(a)
    16
    

    当你需要输出tensor查看的时候,或许需要设置一下默认的输出选项:

    torch.set_printoptions(precision=None, threshold=None, edgeitems=None, linewidth=None, profile=None)
    

    其中precision是每一个元素的输出精度,默认是八位;threshold是输出时的阈值,当tensor中元素的个数大于该值时,进行缩略输出,默认时1000;edgeitems是输出的维度,默认是3;linewidth字面意思,每一行输出的长度;profile=None,修正默认设置(不太懂,感兴趣的可以试试))

    为了防止一些不正常的元素产生,比如特别小的数,pytorch支持如下设置:

    torch.set_flush_denormal(mode)
    

    mode中可以填true或者false
    例子如下:

    >>> torch.set_flush_denormal(True)
    True
    >>> torch.tensor([1e-323], dtype=torch.float64)
    tensor([ 0.], dtype=torch.float64)
    >>> torch.set_flush_denormal(False)
    True
    >>> torch.tensor([1e-323], dtype=torch.float64)
    tensor(9.88131e-324 *
           [ 1.0000], dtype=torch.float64)
    

    可以看出设置了之后,当出现极小数时,直接置为0了。文档中提出该功能必须要系统支持。

    Creation Ops

    这一部分主要介绍tensor的生成。首先直接赋值:

    torch.tensor(data, dtype=None, device=None, requires_grad=False)
    

    具体的结果如下例子所示:

    >>> torch.tensor([[0.1, 1.2], [2.2, 3.1], [4.9, 5.2]])
    tensor([[ 0.1000,  1.2000],
            [ 2.2000,  3.1000],
            [ 4.9000,  5.2000]])
    
    >>> torch.tensor([0, 1])  # Type inference on data
    tensor([ 0,  1])
    
    >>> torch.tensor([[0.11111, 0.222222, 0.3333333]],
                     dtype=torch.float64,
                     device=torch.device('cuda:0'))  # creates a torch.cuda.DoubleTensor
    tensor([[ 0.1111,  0.2222,  0.3333]], dtype=torch.float64, device='cuda:0')
    
    >>> torch.tensor(3.14159)  # Create a scalar (zero-dimensional tensor)
    tensor(3.1416)
    
    >>> torch.tensor([])  # Create an empty tensor (of size (0,))
    tensor([])
    

    当然不能忘了tensor和numpy之间可以相互转换,这个在前面基础部分就有介绍,使用torch.from_numpy即可。

    >>> a = numpy.array([1, 2, 3])
    >>> t = torch.from_numpy(a)
    >>> t
    tensor([ 1,  2,  3])
    >>> t[0] = -1
    >>> a
    array([-1,  2,  3])
    

    如果要生成全为0的tensor,我们使用torch.zeros(),参数如下:

    torch.zeros(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
    

    其中size可以是任意维度的list或tuple。如下所示:

    >>> torch.zeros(2, 3)
    tensor([[ 0.,  0.,  0.],
            [ 0.,  0.,  0.]])
    
    >>> torch.zeros(5)
    tensor([ 0.,  0.,  0.,  0.,  0.])
    

    另外还有一个zeros_like函数,从函数名不难猜到,这个函数是用于生成和输入tensor大小相同的全零tensor的。
    处理生成全零的tensor,还有one()函数,用于生成全为1的tensor。也有one_like函数。
    下面这个函数和python中的range类似,用于产生一个一维的tensor,在给定的区间下依据给定的步长。

    torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
    

    例子如下所示:

    >>> torch.arange(5)
    tensor([ 0.,  1.,  2.,  3.,  4.])
    >>> torch.arange(1, 4)
    tensor([ 1.,  2.,  3.])
    >>> torch.arange(1, 2.5, 0.5)
    tensor([ 1.0000,  1.5000,  2.0000])
    

    注意这里生成的tensor中是不包含上界的,如果要包含上界,可以使用range替代。当然也可以通过设定上下界和元素的个数来避免步长的设定。使用linspace就行了:

    >>> torch.linspace(3, 10, steps=5)
    tensor([  3.0000,   4.7500,   6.5000,   8.2500,  10.0000])
    >>> torch.linspace(-10, 10, steps=5)
    tensor([-10.,  -5.,   0.,   5.,  10.])
    >>> torch.linspace(start=-10, end=10, steps=5)
    tensor([-10.,  -5.,   0.,   5.,  10.])
    

    既然有线性空间,那么log空间自然也是支持的。(虽然我暂时不知道这个可以用来干嘛?画图吗?)
    将上面的linspace换为logspace即可:

    >>> torch.logspace(start=-10, end=10, steps=5)
    tensor([ 1.0000e-10,  1.0000e-05,  1.0000e+00,  1.0000e+05,  1.0000e+10])
    >>> torch.logspace(start=0.1, end=1.0, steps=5)
    tensor([  1.2589,   2.1135,   3.5481,   5.9566,  10.0000])
    

    单位矩阵在矩阵运算中起到了很关键的作用,需要生成一个单位阵,可以使用如下语句:

    >>> torch.eye(3)
    tensor([[ 1.,  0.,  0.],
            [ 0.,  1.,  0.],
            [ 0.,  0.,  1.]])
    

    当然如果特殊需要,单位阵也是支持设置宽的:

    >>> torch.eye(3,7)
    tensor([[ 1.,  0.,  0.,  0.,  0.,  0.,  0.],
            [ 0.,  1.,  0.,  0.,  0.,  0.,  0.],
            [ 0.,  0.,  1.,  0.,  0.,  0.,  0.]])
    

    除了单位阵,还可以生成未初始化的矩阵,调用empty即可,数字是随机的:

    >>> torch.empty(2, 3)
    tensor(1.00000e-08 *
           [[ 6.3984,  0.0000,  0.0000],
            [ 0.0000,  0.0000,  0.0000]])
    

    该函数同样有兄弟:empty_like()
    前面介绍了可以生成全为0和1的tensor,那么如果我要生成全为2的呢?
    首先你可以拿全为1的乘以一个常数,其次,你可以使用full()函数:

    >>> torch.full((2, 3), 3.141592)
    tensor([[ 3.1416,  3.1416,  3.1416],
            [ 3.1416,  3.1416,  3.1416]])
    

    同样full函数有基友full_like()。
    以上是pytorch目前支持的所有tensor生成方法,下面介绍关于tensor的一系列“矩阵操作”。

    Indexing, Slicing, Joining, Mutating Ops

    这一部分将介绍目前pytorch支持的所有关于tensor的各种变换操作。首先是多个tensor的连接,这里和caffe的concat layer作用应该类似,但是不得不感叹,pytorch的实现简洁太多了啊。函数如下:

    torch.cat(seq, dim=0, out=None)
    

    例子如下,做的事二维的,当然高维的同样也可以,不过你必须保证连接的维度上的长度事匹配的。

    >>> x = torch.randn(2, 3)
    >>> x
    tensor([[ 0.6580, -1.0969, -0.4614],
            [-0.1034, -0.5790,  0.1497]])
    >>> torch.cat((x, x, x), 0)
    tensor([[ 0.6580, -1.0969, -0.4614],
            [-0.1034, -0.5790,  0.1497],
            [ 0.6580, -1.0969, -0.4614],
            [-0.1034, -0.5790,  0.1497],
            [ 0.6580, -1.0969, -0.4614],
            [-0.1034, -0.5790,  0.1497]])
    >>> torch.cat((x, x, x), 1)
    tensor([[ 0.6580, -1.0969, -0.4614,  0.6580, -1.0969, -0.4614,  0.6580,
             -1.0969, -0.4614],
            [-0.1034, -0.5790,  0.1497, -0.1034, -0.5790,  0.1497, -0.1034,
             -0.5790,  0.1497]])
    

    通过设置参数dim来选择按哪一个维度相连。
    还有另外一种连接的方法:

    torch.stack(seq, dim=0, out=None) 
    

    该函数跟cat基本相同。不过stack要求连接的tensor每一个维度都相同。

    同样可以将一个tensor分割开来,函数如下:

    torch.chunk(tensor, chunks, dim=0) 
    

    例子如下:

    >>> print(a)
    tensor([[ 0.6253,  0.8666, -0.1230,  0.3984,  0.2968],
            [-1.1441,  1.1067, -0.0283,  0.4503, -0.4435],
            [ 0.4108, -0.2321,  0.2295,  0.2917,  0.1316],
            [ 1.4066, -0.2489,  0.2258, -0.5783, -0.6589],
            [-1.9384,  0.8134,  0.2353, -0.1845, -1.1675],
            [-0.7617,  0.6622,  0.6844,  0.0229, -0.7072],
            [ 0.7110, -0.8292, -0.1205,  1.3795, -1.3677],
            [-0.0562,  1.6998, -0.2817, -0.7298,  0.2130],
            [ 0.4300,  0.8207, -1.1832,  0.9723, -0.0193],
            [-0.3227,  0.1291, -0.1117, -0.2469, -0.5320]])
    >>> torch.chunk(a,2,0)
    (tensor([[ 0.6253,  0.8666, -0.1230,  0.3984,  0.2968],
            [-1.1441,  1.1067, -0.0283,  0.4503, -0.4435],
            [ 0.4108, -0.2321,  0.2295,  0.2917,  0.1316],
            [ 1.4066, -0.2489,  0.2258, -0.5783, -0.6589],
            [-1.9384,  0.8134,  0.2353, -0.1845, -1.1675]]), tensor([[-0.7617,  0.6622,  0.6844,  0.0229, -0.7072],
            [ 0.7110, -0.8292, -0.1205,  1.3795, -1.3677],
            [-0.0562,  1.6998, -0.2817, -0.7298,  0.2130],
            [ 0.4300,  0.8207, -1.1832,  0.9723, -0.0193],
            [-0.3227,  0.1291, -0.1117, -0.2469, -0.5320]]))
    >>> torch.chunk(a,2,1)
    (tensor([[ 0.6253,  0.8666, -0.1230],
            [-1.1441,  1.1067, -0.0283],
            [ 0.4108, -0.2321,  0.2295],
            [ 1.4066, -0.2489,  0.2258],
            [-1.9384,  0.8134,  0.2353],
            [-0.7617,  0.6622,  0.6844],
            [ 0.7110, -0.8292, -0.1205],
            [-0.0562,  1.6998, -0.2817],
            [ 0.4300,  0.8207, -1.1832],
            [-0.3227,  0.1291, -0.1117]]), tensor([[ 0.3984,  0.2968],
            [ 0.4503, -0.4435],
            [ 0.2917,  0.1316],
            [-0.5783, -0.6589],
            [-0.1845, -1.1675],
            [ 0.0229, -0.7072],
            [ 1.3795, -1.3677],
            [-0.7298,  0.2130],
            [ 0.9723, -0.0193],
            [-0.2469, -0.5320]]))
    

    返回的值是一个tuple。将其依次复制给需要的变量即可。
    同样还有另外一个划分的方法,重写的split函数,功能相似:

    torch.split(tensor, split_size_or_sections, dim=0)
    

    其中split_size_or_sections用于设定划分规则,dim用于设定划分的维度。如下例:

    >>> x = torch.randn(5, 5, 5)
    >>> x
    tensor([[[-0.8347,  2.2014,  0.2768,  0.8642,  0.7517],
             [-1.0237,  1.1800, -1.9238,  0.7537, -0.7155],
             [-0.5800, -0.0527,  1.1536,  0.8828,  0.0136],
             [ 0.1452, -0.5878, -1.9840,  0.8288,  1.1804],
             [-0.0514,  0.6633, -1.0233, -1.6492,  0.2422]],
    
            [[-0.1809,  0.0115, -0.1156,  0.4199, -0.6424],
             [ 1.0098,  0.2440,  0.2432,  1.5793, -0.4407],
             [-0.5316,  1.6012, -0.4609,  2.3206,  1.1053],
             [ 0.0999, -0.3938, -1.4438,  0.4003, -0.6948],
             [-1.5991, -0.2188,  0.8460,  1.2603, -0.4484]],
    
            [[ 0.1010,  1.8040,  0.3617,  0.5746, -0.0840],
             [-0.0948, -0.7579,  1.4936, -1.1720, -0.0606],
             [ 0.9900, -0.8400,  0.5351, -0.5388, -1.7400],
             [-0.5397, -0.1141, -0.3179, -0.2871, -0.8846],
             [ 0.3530,  0.5373,  0.2718,  1.2432, -1.3468]],
    
            [[ 0.5830,  0.4154,  0.9897,  1.6300,  1.5950],
             [ 0.4810, -1.1237, -0.2133,  0.5659, -0.4047],
             [ 0.0257, -0.3569,  1.4560, -0.8150, -0.3167],
             [ 1.8086,  0.1829, -0.7073, -1.1966,  0.3805],
             [ 0.0532, -0.2976,  0.3080, -1.3165, -1.0769]],
    
            [[ 1.8177, -0.6848,  0.1681, -1.0104,  0.9661],
             [-1.1784, -1.7252,  0.5589, -1.5597,  1.1723],
             [ 0.5254, -1.3278,  2.0289, -1.6005, -0.9900],
             [-0.2772, -0.4890,  1.1362,  0.9137,  1.0255],
             [-0.3162, -0.6244,  0.9933, -1.7472,  0.5968]]])
    >>> torch.split(x,2,0)
    (tensor([[[-0.8347,  2.2014,  0.2768,  0.8642,  0.7517],
             [-1.0237,  1.1800, -1.9238,  0.7537, -0.7155],
             [-0.5800, -0.0527,  1.1536,  0.8828,  0.0136],
             [ 0.1452, -0.5878, -1.9840,  0.8288,  1.1804],
             [-0.0514,  0.6633, -1.0233, -1.6492,  0.2422]],
    
            [[-0.1809,  0.0115, -0.1156,  0.4199, -0.6424],
             [ 1.0098,  0.2440,  0.2432,  1.5793, -0.4407],
             [-0.5316,  1.6012, -0.4609,  2.3206,  1.1053],
             [ 0.0999, -0.3938, -1.4438,  0.4003, -0.6948],
             [-1.5991, -0.2188,  0.8460,  1.2603, -0.4484]]]), tensor([[[ 0.1010,  1.8040,  0.3617,  0.5746, -0.0840],
             [-0.0948, -0.7579,  1.4936, -1.1720, -0.0606],
             [ 0.9900, -0.8400,  0.5351, -0.5388, -1.7400],
             [-0.5397, -0.1141, -0.3179, -0.2871, -0.8846],
             [ 0.3530,  0.5373,  0.2718,  1.2432, -1.3468]],
    
            [[ 0.5830,  0.4154,  0.9897,  1.6300,  1.5950],
             [ 0.4810, -1.1237, -0.2133,  0.5659, -0.4047],
             [ 0.0257, -0.3569,  1.4560, -0.8150, -0.3167],
             [ 1.8086,  0.1829, -0.7073, -1.1966,  0.3805],
             [ 0.0532, -0.2976,  0.3080, -1.3165, -1.0769]]]), tensor([[[ 1.8177, -0.6848,  0.1681, -1.0104,  0.9661],
             [-1.1784, -1.7252,  0.5589, -1.5597,  1.1723],
             [ 0.5254, -1.3278,  2.0289, -1.6005, -0.9900],
             [-0.2772, -0.4890,  1.1362,  0.9137,  1.0255],
             [-0.3162, -0.6244,  0.9933, -1.7472,  0.5968]]]))
    >>> torch.split(x,(3,2),0)
    (tensor([[[-0.8347,  2.2014,  0.2768,  0.8642,  0.7517],
             [-1.0237,  1.1800, -1.9238,  0.7537, -0.7155],
             [-0.5800, -0.0527,  1.1536,  0.8828,  0.0136],
             [ 0.1452, -0.5878, -1.9840,  0.8288,  1.1804],
             [-0.0514,  0.6633, -1.0233, -1.6492,  0.2422]],
    
            [[-0.1809,  0.0115, -0.1156,  0.4199, -0.6424],
             [ 1.0098,  0.2440,  0.2432,  1.5793, -0.4407],
             [-0.5316,  1.6012, -0.4609,  2.3206,  1.1053],
             [ 0.0999, -0.3938, -1.4438,  0.4003, -0.6948],
             [-1.5991, -0.2188,  0.8460,  1.2603, -0.4484]],
    
            [[ 0.1010,  1.8040,  0.3617,  0.5746, -0.0840],
             [-0.0948, -0.7579,  1.4936, -1.1720, -0.0606],
             [ 0.9900, -0.8400,  0.5351, -0.5388, -1.7400],
             [-0.5397, -0.1141, -0.3179, -0.2871, -0.8846],
             [ 0.3530,  0.5373,  0.2718,  1.2432, -1.3468]]]), tensor([[[ 0.5830,  0.4154,  0.9897,  1.6300,  1.5950],
             [ 0.4810, -1.1237, -0.2133,  0.5659, -0.4047],
             [ 0.0257, -0.3569,  1.4560, -0.8150, -0.3167],
             [ 1.8086,  0.1829, -0.7073, -1.1966,  0.3805],
             [ 0.0532, -0.2976,  0.3080, -1.3165, -1.0769]],
    
            [[ 1.8177, -0.6848,  0.1681, -1.0104,  0.9661],
             [-1.1784, -1.7252,  0.5589, -1.5597,  1.1723],
             [ 0.5254, -1.3278,  2.0289, -1.6005, -0.9900],
             [-0.2772, -0.4890,  1.1362,  0.9137,  1.0255],
             [-0.3162, -0.6244,  0.9933, -1.7472,  0.5968]]]))
    >>> torch.split(x,(3,2),1)
    (tensor([[[-0.8347,  2.2014,  0.2768,  0.8642,  0.7517],
             [-1.0237,  1.1800, -1.9238,  0.7537, -0.7155],
             [-0.5800, -0.0527,  1.1536,  0.8828,  0.0136]],
    
            [[-0.1809,  0.0115, -0.1156,  0.4199, -0.6424],
             [ 1.0098,  0.2440,  0.2432,  1.5793, -0.4407],
             [-0.5316,  1.6012, -0.4609,  2.3206,  1.1053]],
    
            [[ 0.1010,  1.8040,  0.3617,  0.5746, -0.0840],
             [-0.0948, -0.7579,  1.4936, -1.1720, -0.0606],
             [ 0.9900, -0.8400,  0.5351, -0.5388, -1.7400]],
    
            [[ 0.5830,  0.4154,  0.9897,  1.6300,  1.5950],
             [ 0.4810, -1.1237, -0.2133,  0.5659, -0.4047],
             [ 0.0257, -0.3569,  1.4560, -0.8150, -0.3167]],
    
            [[ 1.8177, -0.6848,  0.1681, -1.0104,  0.9661],
             [-1.1784, -1.7252,  0.5589, -1.5597,  1.1723],
             [ 0.5254, -1.3278,  2.0289, -1.6005, -0.9900]]]), tensor([[[ 0.1452, -0.5878, -1.9840,  0.8288,  1.1804],
             [-0.0514,  0.6633, -1.0233, -1.6492,  0.2422]],
    
            [[ 0.0999, -0.3938, -1.4438,  0.4003, -0.6948],
             [-1.5991, -0.2188,  0.8460,  1.2603, -0.4484]],
    
            [[-0.5397, -0.1141, -0.3179, -0.2871, -0.8846],
             [ 0.3530,  0.5373,  0.2718,  1.2432, -1.3468]],
    
            [[ 1.8086,  0.1829, -0.7073, -1.1966,  0.3805],
             [ 0.0532, -0.2976,  0.3080, -1.3165, -1.0769]],
    
            [[-0.2772, -0.4890,  1.1362,  0.9137,  1.0255],
             [-0.3162, -0.6244,  0.9933, -1.7472,  0.5968]]]))
    

    下面这个函数应该是到目前为止,第一个不太好理解的。

    torch.gather(input, dim, index, out=None) 
    

    直接上例子吧,详细的解释和应用可以去这个博客,因为我确实没有用到过,所以只能从算法上简单的解释一下了。
    这个函数的意义在于按照一个给定的轴收集原tensor中的值,并得到一个新的tensor,其中dim = 0 是按照y轴,dim = 1是按照x轴,按照哪个轴在原tensor和index对应的tensor中都是按照相同的轴读取。输出也按照该轴输出。这一点是没法一眼看懂这个函数的原因所在。例子如下:

    >>> t = torch.tensor([[1,2],[3,4]])
    >>> torch.gather(t, 1, torch.tensor([[0,0],[1,0]]))
    tensor([[ 1,  1],
            [ 4,  3]])
    >>> torch.gather(t, 0, torch.tensor([[0,0],[1,0]]))
    tensor([[ 1,  2],
            [ 3,  2]])
    

    当dim为1时,按照x轴(行)读取,index对应的第一行为0,0所以连续在原tensor中读取两次第一个位置,保存在结果tenser的第一行。第二行同理。
    当dim为0时,按照y轴(列)读取,index对应的第一列为0,1所以分别读取原tensor的第一列的第一个第二个数1和3存在结果tensor的第一列。

    和上面挑tensor中元素的情况类似,我们还能挑选tensor中的一整行和一整列。函数如下:

    torch.index_select(input, dim, index, out=None)
    

    这个例子还是很好理解的,我觉得我不需要过多的解释了。直接上结果:

    >>> x = torch.randn(3, 4)
    >>> x
    tensor([[ 0.1427,  0.0231, -0.5414, -1.0009],
            [-0.4664,  0.2647, -0.1228, -1.1068],
            [-1.1734, -0.6571,  0.7230, -0.6004]])
    >>> indices = torch.tensor([0, 2])
    >>> torch.index_select(x, 0, indices)
    tensor([[ 0.1427,  0.0231, -0.5414, -1.0009],
            [-1.1734, -0.6571,  0.7230, -0.6004]])
    >>> torch.index_select(x, 1, indices)
    tensor([[ 0.1427, -0.5414],
            [-0.4664, -0.1228],
            [-1.1734,  0.7230]])
    

    如果想要挑选出tensor中所有大于一个阈值的量要怎么做呢?
    这里要结合两个函数,ge()和mask_select()这里首先介绍mask_select()函数,ge函数在后面的tensor运算章节会讲。这里只需要知道他讲输入tensor按照一个阈值01化即可(大于阈值设为1)。mask_select函数将按照输入的mask挑选出原tensor中mask上面为1的元素,生成一个一维的向量。
    结果如下:

    >>> x = torch.randn(3, 4)
    >>> x
    tensor([[ 0.3552, -2.3825, -0.8297,  0.3477],
            [-1.2035,  1.2252,  0.5002,  0.6248],
            [ 0.1307, -2.0608,  0.1244,  2.0139]])
    >>> mask = x.ge(0.5)
    >>> mask
    tensor([[ 0,  0,  0,  0],
            [ 0,  1,  1,  1],
            [ 0,  0,  0,  1]], dtype=torch.uint8)
    >>> torch.masked_select(x, mask)
    tensor([ 1.2252,  0.5002,  0.6248,  2.0139])
    

    下面这个函数用于得到tensor中非零元素的位置坐标,返回值的每一行代表一个坐标。如果输入tensor是n维的,其中非零元素个数为k,那么返回值是一个k×n的tensor。函数和示例如下所示:

    torch.nonzero(input, out=None) 
    
    >>> torch.nonzero(torch.tensor([1, 1, 1, 0, 1]))
    tensor([[ 0],
            [ 1],
            [ 2],
            [ 4]])
    >>> torch.nonzero(torch.tensor([[0.6, 0.0, 0.0, 0.0],
                                    [0.0, 0.4, 0.0, 0.0],
                                    [0.0, 0.0, 1.2, 0.0],
                                    [0.0, 0.0, 0.0,-0.4]]))
    tensor([[ 0,  0],
            [ 1,  1],
            [ 2,  2],
            [ 3,  3]])
    

    接下来介绍一个必定经常用到的函数,reshape。该函数用于改变tensor的形状,和其他的reshape一样,参数设为-1时,该维度的元素个数由其他维度计算得到。直接上示例:

    >>> a = torch.arange(4)
    >>> torch.reshape(a, (2, 2))
    tensor([[ 0.,  1.],
            [ 2.,  3.]])
    >>> b = torch.tensor([[0, 1], [2, 3]])
    >>> torch.reshape(b, (-1,))
    tensor([ 0,  1,  2,  3])
    

    有些时候不需要分割tensor,但是需要压缩tensor,pytorch提供了一个自动去掉通道是1的维度的函数:

    torch.squeeze(input, dim=None, out=None)
    

    直接上例子吧,比如我们生成一个维度为3,1,2的tensor

    >>> x = torch.randn(3, 1, 2)
    >>> x
    tensor([[[-0.2863,  0.8594]],
    
            [[-0.4789,  0.9160]],
    
            [[ 1.0955, -1.2205]]])
    

    可以发现实际上他的第二个维度没有什么意义。调用squeeze函数:

    >>> torch.squeeze(x)
    tensor([[-0.2863,  0.8594],
            [-0.4789,  0.9160],
            [ 1.0955, -1.2205]])
    

    如果一个tensor中通道数为1的维度有很多,但是又不想全部去掉,那么可以在函数中通过设定dim参数,选择去掉某一个维度。
    有的时候又需要增加维度,这时可以使用unsqueeze函数:

    torch.unsqueeze(input, dim, out=None) 
    

    该函数将在制定的维度增加一维:

    >>> x = torch.tensor([1, 2, 3, 4])
    >>> torch.unsqueeze(x, 0)
    tensor([[ 1,  2,  3,  4]])
    >>> torch.unsqueeze(x, 1)
    tensor([[ 1],
            [ 2],
            [ 3],
            [ 4]])
    

    squeeze和unsqueeze函数产生的输出和输入都是共享存储空间的,改变其中一个另外一个也会改变。

    既然tensor是矩阵操作,那么肯定少不了矩阵的转置:

    torch.t(input, out=None)
    

    例子很简单,函数也只有一个参数,那就是输入tensor:

    >>> x = torch.randn(2, 3)
    >>> x
    tensor([[ 0.4875,  0.9158, -0.5872],
            [ 0.3938, -0.6929,  0.6932]])
    >>> torch.t(x)
    tensor([[ 0.4875,  0.3938],
            [ 0.9158, -0.6929],
            [-0.5872,  0.6932]])
    

    前面介绍过取部分元素的函数,这里再增加一个,用起来比较简单,但是在使用时可能人为需要计算的就多一点了:

    torch.take(input, indices)
    

    该函数将输入tensor转换为一个一维的向量,然后在该向量上依据给出的坐标,返回元素的tensor:

    >>> src = torch.tensor([[4, 3, 5],
                            [6, 7, 8]])
    >>> torch.take(src, torch.tensor([0, 2, 5]))
    tensor([ 4,  5,  8])
    

    pytorch除了提供了.t()这种简单的矩阵转置方式,还提供了另外一个函数:

    torch.transpose(input, dim0, dim1, out=None)
    

    这里通过指定两个维度dim0和dim1,来将其做转换,如果设为0和1则和t的效果等价。不过需要注意的是transpose函数转置前后的到的tensor是共享底层存储空间的,如果对其中一个的元素做更改,另外一个也会发生变化:

    >>> x = torch.randn(3, 1, 2)
    >>> x
    tensor([[[-0.2863,  0.8594]],
    
            [[-0.4789,  0.9160]],
    
            [[ 1.0955, -1.2205]]])
    >>> torch.squeeze(x)
    tensor([[-0.2863,  0.8594],
            [-0.4789,  0.9160],
            [ 1.0955, -1.2205]])
    >>> x = torch.randn(2, 3)
    >>> x
    tensor([[ 0.6525,  0.1151, -0.0437],
            [ 0.2640, -1.2813,  1.3332]])
    >>> y = torch.transpose(x, 0, 1)
    >>> y
    tensor([[ 0.6525,  0.2640],
            [ 0.1151, -1.2813],
            [-0.0437,  1.3332]])
    >>> y[0][0] = 1
    >>> y
    tensor([[ 1.0000,  0.2640],
            [ 0.1151, -1.2813],
            [-0.0437,  1.3332]])
    >>> x
    tensor([[ 1.0000,  0.1151, -0.0437],
            [ 0.2640, -1.2813,  1.3332]])
    

    如果需要删除一个维度,可以用下面的操作:

    torch.unbind(tensor, dim=0)
    

    直接上示例吧:

    >>> x
    tensor([[ 1.0000,  0.1151, -0.0437],
            [ 0.2640, -1.2813,  1.3332]])
    >>> torch.unbind(x, 1)
    (tensor([ 1.0000,  0.2640]), tensor([ 0.1151, -1.2813]), tensor([-0.0437,  1.3332]))
    

    可以看出,当我们删除了维度1之后,原tensor被分为了几个小的只有维度0的子tensor,所以这个函数可以简答的理解为按给定的维度将原tensor展开,上面是按列展开。再比如我们按行展开:

    >>> torch.unbind(x, 0)
    (tensor([ 1.0000,  0.1151, -0.0437]), tensor([ 0.2640, -1.2813,  1.3332]))
    

    终于要把这一部分写完了,还剩最后一个函数:

    torch.where(condition, x, y)
    

    这个函数的功能是依据一个判断语句,来从tensor中挑选语句,官方文档给的例子是:

    >>> x = torch.randn(3, 2)
    >>> y = torch.ones(3, 2)
    >>> x
    tensor([[-0.4620,  0.3139],
            [ 0.3898, -0.7197],
            [ 0.0478, -0.1657]])
    >>> torch.where(x > 0, x, y)
    tensor([[ 1.0000,  0.3139],
            [ 0.3898,  1.0000],
            [ 0.0478,  1.0000]])
    

    那么能不能依据x的值在y和z之中挑选呢?是可以的,甚至其他的条件都可以,但是有一个条件是你所使用的条件和变量是广播的。

    >>> x = torch.randn(3, 2)
    >>> y = torch.ones(3, 2)
    >>> z = torch.zeros(3, 2)
    >>> x
    tensor([[ 0.9749,  0.2215],
            [-0.3449,  2.2324],
            [ 0.8020,  0.7957]])
    >>> y
    tensor([[ 1.,  1.],
            [ 1.,  1.],
            [ 1.,  1.]])
    >>> z
    tensor([[ 0.,  0.],
            [ 0.,  0.],
            [ 0.,  0.]])
    >>> torch.where(x>0,x,y)
    tensor([[ 0.9749,  0.2215],
            [ 1.0000,  2.2324],
            [ 0.8020,  0.7957]])
    

    Random sampling

    写到这里,我这一篇博客才写了四分之一(T_T)
    随机数是深度学习中很关键的基础,为什么?自行百度吧。pytorch中设置随机数生成的种子点,查看种子点的函数分别为:

    torch.manual_seed(seed) #设置
    torch.initial_seed() #查看
    

    示例如下:

    >>> torch.initial_seed()
    16846182053669541300
    >>> torch.manual_seed(1)
    <torch._C.Generator object at 0x7fadc8d9afb0>
    >>> torch.initial_seed()
    1
    

    因为这篇博客里不打算探究pytorch随机数的生成原理,所以以下几个函数就不详细介绍了:get_rng_state();set_rng_state(new_state);torch.default_generator = <torch._C.Generator object>。
    下面来介绍一系列随机tensor的生成方法

    torch.bernoulli(input, out=None)
    

    该函数按照伯努利分布依据输入的tensor来随机的生成0,1二值的tensor。要求输入tensor的元素值在0和1之间。

    >>> a = torch.empty(3, 3).uniform_(0, 1) # generate a uniform random matrix with range [0, 1]
    >>> a
    tensor([[ 0.1737,  0.0950,  0.3609],
            [ 0.7148,  0.0289,  0.2676],
            [ 0.9456,  0.8937,  0.7202]])
    >>> torch.bernoulli(a)
    tensor([[ 1.,  0.,  0.],
            [ 0.,  0.,  0.],
            [ 1.,  1.,  1.]])
    
    >>> a = torch.ones(3, 3) # probability of drawing "1" is 1
    >>> torch.bernoulli(a)
    tensor([[ 1.,  1.,  1.],
            [ 1.,  1.,  1.],
            [ 1.,  1.,  1.]])
    >>> a = torch.zeros(3, 3) # probability of drawing "1" is 0
    >>> torch.bernoulli(a)
    tensor([[ 0.,  0.,  0.],
            [ 0.,  0.,  0.],
            [ 0.,  0.,  0.]])
    
    torch.multinomial(input, num_samples, replacement=False, out=None) 
    

    这个函数比较有意思,他的输入tensor表示了每一个位置的概率,这里并不要求他是大于1的,但是所有元素的和不能是0。num_samples为挑选出的位置的编号,实际上就是一个随机数,第三个参数指的是是否运行重复挑选。官方文档给的例子似乎不太好体现,给一个二值的输入tensor演示一下吧:

    >>> weights = torch.tensor([0, 10], dtype=torch.float)
    >>> torch.multinomial(weights, 4, replacement=True)
    tensor([ 1,  1,  1,  1])
    

    当讲两个位置的概率设为相同时:

    >>> weights = torch.tensor([10, 10], dtype=torch.float)
    >>> torch.multinomial(weights, 4, replacement=True)
    tensor([ 1,  1,  0,  0])
    

    注意如果后面的replacement设为false,那么输出的元素个数必须是不大于输入的size的。

    下面一个方法生成的是服从正太分布的随机数:
    有三种种方式:

    torch.normal(mean, std, out=None) 
    torch.normal(mean=0.0, std, out=None) 
    torch.normal(mean, std=1.0, out=None)
    

    如果输入的mean和std是tensor,那么生成的tensor将按照mean的形状,元素的个数和输入相同,也就是说mean和std可以有不同的形状,但是必须有相同的元素个数:

    >>> torch.normal(mean=torch.arange(1, 11), std=torch.arange(1, 0, -0.1))
    tensor([  1.0425,   3.5672,   2.7969,   4.2925,   4.7229,   6.2134,
              8.0505,   8.1408,   9.0563,  10.0566])
    

    另外也可以固定其中一个,也就是第二种和第三种方式:

    >>> torch.normal(mean=0.5, std=torch.arange(1, 6))
    tensor([-1.2793, -1.0732, -2.0687,  5.1177, -1.2303])
    >>> torch.normal(mean=torch.arange(1, 6))
    tensor([ 1.1552,  2.6148,  2.6535,  5.8318,  4.2361])
    

    下面几个功能类似,都是按照一定得规则生成随机tensor的,这里统一整理一下:

    #生成[0,1)的随机数
    torch.rand(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
    #按照输入的tensor的尺寸生成
    torch.rand_like(input, dtype=None, layout=None, device=None, requires_grad=False) 
    #在一个范围内生成整型的随机
    torch.randint(low=0, high, size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) 
    #不解释
    torch.randint_like(input, low=0, high, dtype=None, layout=torch.strided, device=None, requires_grad=False)
    #返回01正太分布
    torch.randn(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
    #不解释
    torch.randn_like(input, dtype=None, layout=None, device=None, requires_grad=False)
    #返回0到输入n的之间整数随机排列不含n
    torch.randperm(n, out=None, dtype=torch.int64, layout=torch.strided, device=None, requires_grad=False)
    

    另外在torch.Tensor下还定义了一些in-place的函数:

    Serialization

    这里主要介绍如何将得到的tensor保存到本地,或者从本地读取tensor,这也是很关键的步骤。

    torch.save(obj, f, pickle_module=<module 'pickle' from '/private/home/soumith/anaconda3/lib/python3.6/pickle.py'>, pickle_protocol=2)
    

    这一部分在Recommended approach for saving a model
    有更详细的介绍。这里就放几个简单的例子吧:

    >>> # Save to file
    >>> x = torch.tensor([0, 1, 2, 3, 4])
    >>> torch.save(x, 'tensor.pt')
    >>> # Save to io.BytesIO buffer
    >>> buffer = io.BytesIO()
    >>> torch.save(x, buffer)
    

    同样load函数:

    >>> torch.load('tensors.pt')
    # Load all tensors onto the CPU
    >>> torch.load('tensors.pt', map_location='cpu')
    # Load all tensors onto the CPU, using a function
    >>> torch.load('tensors.pt', map_location=lambda storage, loc: storage)
    # Load all tensors onto GPU 1
    >>> torch.load('tensors.pt', map_location=lambda storage, loc: storage.cuda(1))
    # Map tensors from GPU 1 to GPU 0
    >>> torch.load('tensors.pt', map_location={'cuda:1':'cuda:0'})
    # Load tensor from io.BytesIO object
    >>> with open('tensor.pt') as f:
            buffer = io.BytesIO(f.read())
    >>> torch.load(buffer)
    

    这一部分可能后续会专门写一篇博客介绍。这篇博客主要介绍tensor的相关操作函数吧。

    Parallelism

    这里主要是和CPU线程相关的两个函数:

    torch.get_num_threads()
    torch.set_num_threads()
    

    第一个用于的到目前的CPU线程,第二个用于设定使用的线程,但是在GPU训练和测试时基本没有什么用了。

    Locally disabling gradient computation

    前面有提到过,pytorch会默认的给tensor计算梯度,这样在实际使用时,会增加一些不必要的资源开销,可以通过设置torch.no_grad(), torch.enable_grad()和torch.set_grad_enabled()三个值来设定tensor的梯度计算:
    直接上例子吧:

    >>> x = torch.zeros(1, requires_grad=True)
    >>> with torch.no_grad():
    ...     y = x * 2
    >>> y.requires_grad
    False
    
    >>> is_train = False
    >>> with torch.set_grad_enabled(is_train):
    ...     y = x * 2
    >>> y.requires_grad
    False
    
    >>> torch.set_grad_enabled(True)  # this can also be used as a function
    >>> y = x * 2
    >>> y.requires_grad
    True
    
    >>> torch.set_grad_enabled(False)
    >>> y = x * 2
    >>> y.requires_grad
    False
    

    以上基本介绍完了tensor的各种基本的函数。下面步入这篇博客的正题。。。。写了快八千字了才步入正题。。。。

    Math operations

    Pointwise Ops

    这一块将介绍在tensor上可以使用的各种数学计算。首先是最简单的各种运算,输入都是一个tensor,所以就不详细写了,还是直接整理一下:

    求绝对值

    torch.abs(input, out=None)
    >>> torch.abs(torch.tensor([-1, -2, 3]))
    tensor([ 1,  2,  3])
    

    求反三角函数

    torch.acos(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.3348, -0.5889,  0.2005, -0.1584])
    >>> torch.acos(a)
    tensor([ 1.2294,  2.2004,  1.3690,  1.7298])
    
    
    torch.asin(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.5962,  1.4985, -0.4396,  1.4525])
    >>> torch.asin(a)
    tensor([-0.6387,     nan, -0.4552,     nan])
    
    
    torch.atan(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.2341,  0.2539, -0.6256, -0.6448])
    >>> torch.atan(a)
    tensor([ 0.2299,  0.2487, -0.5591, -0.5727])
    
    
    torch.atan2(input1, input2, out=None) #输入为两个tensor,求他们对应的反正切
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.9041,  0.0196, -0.3108, -2.4423])
    >>> torch.atan2(a, torch.randn(4))
    tensor([ 0.9833,  0.0811, -1.9743, -1.4151])
    

    所有元素加上一个定值

    torch.add()
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.0202,  1.0985,  1.3506, -0.6056])
    >>> torch.add(a, 20)
    tensor([ 20.0202,  21.0985,  21.3506,  19.3944])
    

    输入tensor加上一个常数乘以另一个tensor,如果两个维度不同,会扩展:

    >>> a = torch.randn(4)
    >>> a
    tensor([-0.9732, -0.3497,  0.6245,  0.4022])
    >>> b = torch.randn(4, 1)
    >>> b
    tensor([[ 0.3743],
            [-1.7724],
            [-0.5811],
            [-0.8017]])
    >>> torch.add(a, 10, b)
    tensor([[  2.7695,   3.3930,   4.3672,   4.1450],
            [-18.6971, -18.0736, -17.0994, -17.3216],
            [ -6.7845,  -6.1610,  -5.1868,  -5.4090],
            [ -8.9902,  -8.3667,  -7.3925,  -7.6147]])
    

    对tensor1和tensor2做数除,然后乘以一个变量之后加到输入tensor上。

    >>> t = torch.randn(1, 3)
    >>> t1 = torch.randn(3, 1)
    >>> t2 = torch.randn(1, 3)
    >>> torch.addcdiv(t, 0.1, t1, t2)
    tensor([[-0.2312, -3.6496,  0.1312],
            [-1.0428,  3.4292, -0.1030],
            [-0.5369, -0.9829,  0.0430]])
    

    类似的也有乘法:

    torch.addcmul(tensor, value=1, tensor1, tensor2, out=None) 
    

    还有一个减法的,但是好像物理意义不太一样,公式如下:


    lerp
    torch.lerp(start, end, weight, out=None)
    >>> start = torch.arange(1, 5)
    >>> end = torch.empty(4).fill_(10)
    >>> start
    tensor([ 1.,  2.,  3.,  4.])
    >>> end
    tensor([ 10.,  10.,  10.,  10.])
    >>> torch.lerp(start, end, 0.5)
    tensor([ 5.5000,  6.0000,  6.5000,  7.0000])
    

    对tensor中的元素做向上取整?

    torch.ceil(input, out=None) 
    
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.6341, -1.4208, -1.0900,  0.5826])
    >>> torch.ceil(a)
    tensor([-0., -1., -1.,  1.])
    

    向下取整:

    torch.floor(input, out=None) 
    
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.8166,  1.5308, -0.2530, -0.2091])
    >>> torch.floor(a)
    tensor([-1.,  1., -1., -1.])
    

    x大于或小于阈值时将其截断:

    torch.clamp(input, min, max, out=None) 
    
    >>> a = torch.randn(4)
    >>> a
    tensor([-1.7120,  0.1734, -0.0478, -0.0922])
    >>> torch.clamp(a, min=-0.5, max=0.5)
    tensor([-0.5000,  0.1734, -0.0478, -0.0922])
    #当然也可以只设置一边
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.0299, -2.3184,  2.1593, -0.8883])
    >>> torch.clamp(a, min=0.5)
    tensor([ 0.5000,  0.5000,  2.1593,  0.5000])
    
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.0753, -0.4702, -0.4599,  0.1899])
    >>> torch.clamp(a, max=0.5)
    tensor([ 0.0753, -0.4702, -0.4599,  0.1899])
    

    三角函数

    #余弦
    torch.cos(input, out=None)
    >>> a = torch.randn(4)
    >>> a
    tensor([ 1.4309,  1.2706, -0.8562,  0.9796])
    >>> torch.cos(a)
    tensor([ 0.1395,  0.2957,  0.6553,  0.5574])
    
    #双曲余弦
    torch.cosh(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.1632,  1.1835, -0.6979, -0.7325])
    >>> torch.cosh(a)
    tensor([ 1.0133,  1.7860,  1.2536,  1.2805])
    

    元素数除法,可以除数也可以除tensor

    torch.div()
    >>> a = torch.randn(5)
    >>> a
    tensor([ 0.3810,  1.2774, -0.2972, -0.3719,  0.4637])
    >>> torch.div(a, 0.5)
    tensor([ 0.7620,  2.5548, -0.5944, -0.7439,  0.9275])
    
    >>> a = torch.randn(4, 4)
    >>> a
    tensor([[-0.3711, -1.9353, -0.4605, -0.2917],
            [ 0.1815, -1.0111,  0.9805, -1.5923],
            [ 0.1062,  1.4581,  0.7759, -1.2344],
            [-0.1830, -0.0313,  1.1908, -1.4757]])
    >>> b = torch.randn(4)
    >>> b
    tensor([ 0.8032,  0.2930, -0.8113, -0.2308])
    >>> torch.div(a, b)
    tensor([[-0.4620, -6.6051,  0.5676,  1.2637],
            [ 0.2260, -3.4507, -1.2086,  6.8988],
            [ 0.1322,  4.9764, -0.9564,  5.3480],
            [-0.2278, -0.1068, -1.4678,  6.3936]])
    

    计算元素除法的各项余数:

    torch.fmod(input, divisor, out=None) 
    >>> torch.fmod(torch.tensor([-3., -2, -1, 1, 2, 3]), 2)
    tensor([-1., -0., -1.,  1.,  0.,  1.])
    >>> torch.fmod(torch.tensor([1., 2, 3, 4, 5]), 1.5)
    tensor([ 1.0000,  0.5000,  0.0000,  1.0000,  0.5000])
    

    元素乘法:

    torch.mul()
    
    >>> a = torch.randn(3)
    >>> a
    tensor([ 0.2015, -0.4255,  2.6087])
    >>> torch.mul(a, 100)
    tensor([  20.1494,  -42.5491,  260.8663])
    
    >>> a = torch.randn(4, 1)
    >>> a
    tensor([[ 1.1207],
            [-0.3137],
            [ 0.0700],
            [ 0.8378]])
    >>> b = torch.randn(1, 4)
    >>> b
    tensor([[ 0.5146,  0.1216, -0.5244,  2.2382]])
    >>> torch.mul(a, b)
    tensor([[ 0.5767,  0.1363, -0.5877,  2.5083],
            [-0.1614, -0.0382,  0.1645, -0.7021],
            [ 0.0360,  0.0085, -0.0367,  0.1567],
            [ 0.4312,  0.1019, -0.4394,  1.8753]])
    

    计算误差函数:


    误差函数
    torch.erf(tensor, out=None)
    >>> torch.erf(torch.tensor([0, -1., 10.]))
    tensor([ 0.0000, -0.8427,  1.0000])
    

    计算反误差函数:


    反误差函数
    torch.erfinv(tensor, out=None)
    >>> torch.erfinv(torch.tensor([0, 0.5, -1.]))
    tensor([ 0.0000,  0.4769,    -inf])
    

    指数函数:

    torch.exp(tensor, out=None)
    >>> torch.exp(torch.tensor([0, math.log(2)]))
    tensor([ 1.,  2.])
    

    归零化的指数函数(求指数后减一)

    torch.expm1(tensor, out=None)
    >>> torch.expm1(torch.tensor([0, math.log(2)]))
    tensor([ 0.,  1.])
    

    计算元素的小数部分:

    torch.frac(tensor, out=None) 
    >>> torch.frac(torch.tensor([1, 2.5, -3.2]))
    tensor([ 0.0000,  0.5000, -0.2000])
    

    下面是一堆求log的函数:

    # 自然对数
    torch.log(input, out=None)
    #10为底
    torch.log10(input, out=None) 
    #自然对数,输入为1+input
    torch.log1p
    #以2为底
    torch.log2(input, out=None)
    

    取反:

    torch.neg(input, out=None)
    >>> a = torch.randn(5)
    >>> a
    tensor([ 0.0090, -0.2262, -0.0682, -0.2866,  0.3940])
    >>> torch.neg(a)
    tensor([-0.0090,  0.2262,  0.0682,  0.2866, -0.3940])
    

    求指数:

    torch.pow()
    
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.4331,  1.2475,  0.6834, -0.2791])
    >>> torch.pow(a, 2)
    tensor([ 0.1875,  1.5561,  0.4670,  0.0779])
    >>> exp = torch.arange(1, 5)
    
    >>> a = torch.arange(1, 5)
    >>> a
    tensor([ 1.,  2.,  3.,  4.])
    >>> exp
    tensor([ 1.,  2.,  3.,  4.])
    >>> torch.pow(a, exp)
    tensor([   1.,    4.,   27.,  256.])
    
    >>> exp = torch.arange(1, 5)
    >>> base = 2
    >>> torch.pow(base, exp)
    tensor([  2.,   4.,   8.,  16.])
    

    求倒数:

    torch.reciprocal(input, out=None)
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.4595, -2.1219, -1.4314,  0.7298])
    >>> torch.reciprocal(a)
    tensor([-2.1763, -0.4713, -0.6986,  1.3702])
    

    求余数:

    torch.remainder(input, divisor, out=None)
    >>> torch.remainder(torch.tensor([-3., -2, -1, 1, 2, 3]), 2)
    tensor([ 1.,  0.,  1.,  1.,  0.,  1.])
    >>> torch.remainder(torch.tensor([1., 2, 3, 4, 5]), 1.5)
    tensor([ 1.0000,  0.5000,  0.0000,  1.0000,  0.5000])
    

    四舍五入:

    torch.round(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.9920,  0.6077,  0.9734, -1.0362])
    >>> torch.round(a)
    tensor([ 1.,  1.,  1., -1.])
    

    去掉小数部分:

    torch.trunc(input, out=None)
    >>> a = torch.randn(4)
    >>> a
    tensor([ 3.4742,  0.5466, -0.8008, -0.9079])
    >>> torch.trunc(a)
    tensor([ 3.,  0., -0., -0.])
    

    平方根倒数:

    torch.rsqrt(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([-0.0370,  0.2970,  1.5420, -0.9105])
    >>> torch.rsqrt(a)
    tensor([    nan,  1.8351,  0.8053,     nan])
    

    sigmoid函数,这个用的就相当多了:


    sigmoid
    torch.sigmoid(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 0.9213,  1.0887, -0.8858, -1.7683])
    >>> torch.sigmoid(a)
    tensor([ 0.7153,  0.7481,  0.2920,  0.1458])
    

    符号函数,正为1负为-1:

    torch.sign(input, out=None) 
    >>> a = torch.randn(4)
    >>> a
    tensor([ 1.0382, -1.4526, -0.9709,  0.4542])
    >>> torch.sign(a)
    tensor([ 1., -1., -1.,  1.])
    

    另外还有正弦函数sin(),反三角函数sinh(),平方根函数sqrt(),正切函数tan(),反正切函数tanh()等就不再一一给出例子了。

    Reduction Ops

    按指定的维度返回最大元素的坐标。

    torch.argmax(input, dim=None, keepdim=False)
    >>> a = torch.randn(4, 4)
    >>> a
    tensor([[ 1.3398,  0.2663, -0.2686,  0.2450],
            [-0.7401, -0.8805, -0.3402, -1.1936],
            [ 0.4907, -1.3948, -1.0691, -0.3132],
            [-1.6092,  0.5419, -0.2993,  0.3195]])
    
    
    >>> torch.argmax(a, dim=1)
    tensor([ 0,  2,  0,  1])
    

    同样,返回最小的:

    torch.argmin(input, dim=None, keepdim=False)
    

    累乘:

    torch.cumprod(input, dim, out=None) 
    >>> a = torch.randn(10)
    >>> a
    tensor([ 0.6001,  0.2069, -0.1919,  0.9792,  0.6727,  1.0062,  0.4126,
            -0.2129, -0.4206,  0.1968])
    >>> torch.cumprod(a, dim=0)
    tensor([ 0.6001,  0.1241, -0.0238, -0.0233, -0.0157, -0.0158, -0.0065,
             0.0014, -0.0006, -0.0001])
    
    >>> a[5] = 0.0
    >>> torch.cumprod(a, dim=0)
    tensor([ 0.6001,  0.1241, -0.0238, -0.0233, -0.0157, -0.0000, -0.0000,
             0.0000, -0.0000, -0.0000])
    

    累加:

    torch.cumsum(input, dim, out=None) 
    >>> a = torch.randn(10)
    >>> a
    tensor([-0.8286, -0.4890,  0.5155,  0.8443,  0.1865, -0.1752, -2.0595,
             0.1850, -1.1571, -0.4243])
    >>> torch.cumsum(a, dim=0)
    tensor([-0.8286, -1.3175, -0.8020,  0.0423,  0.2289,  0.0537, -2.0058,
            -1.8209, -2.9780, -3.4022])
    

    返回两个tensor之间差的(input - other)的p范数。这个在距离度量里面应该也是用的很普遍的。

    torch.dist(input, other, p=2)
    >>> x = torch.randn(4)
    >>> x
    tensor([-1.5393, -0.8675,  0.5916,  1.6321])
    >>> y = torch.randn(4)
    >>> y
    tensor([ 0.0967, -1.0511,  0.6295,  0.8360])
    >>> torch.dist(x, y, 3.5)
    tensor(1.6727)
    >>> torch.dist(x, y, 3)
    tensor(1.6973)
    >>> torch.dist(x, y, 0)
    tensor(inf)
    >>> torch.dist(x, y, 1)
    tensor(2.6537)
    

    返回一个tensor向量的p范数:

    torch.norm(input, p=2)
    >>> a = torch.randn(1, 3)
    >>> a
    tensor([[-0.5192, -1.0782, -1.0448]])
    >>> torch.norm(a, 3)
    tensor(1.3633)
    torch.norm(input, p, dim, keepdim=False, out=None)
    >>> a = torch.randn(4, 2)
    >>> a
    tensor([[ 2.1983,  0.4141],
            [ 0.8734,  1.9710],
            [-0.7778,  0.7938],
            [-0.1342,  0.7347]])
    >>> torch.norm(a, 2, 1)
    tensor([ 2.2369,  2.1558,  1.1113,  0.7469])
    >>> torch.norm(a, 0, 1, True)
    tensor([[ 2.],
            [ 2.],
            [ 2.],
            [ 2.]])
    

    求均值:

    torch.mean(input)
    >>> a = torch.randn(1, 3)
    >>> a
    tensor([[ 0.2294, -0.5481,  1.3288]])
    >>> torch.mean(a)
    tensor(0.3367)
    torch.mean(input, dim, keepdim=False, out=None)
    >>> a = torch.randn(4, 4)
    >>> a
    tensor([[-0.3841,  0.6320,  0.4254, -0.7384],
            [-0.9644,  1.0131, -0.6549, -1.4279],
            [-0.2951, -1.3350, -0.7694,  0.5600],
            [ 1.0842, -0.9580,  0.3623,  0.2343]])
    >>> torch.mean(a, 1)
    tensor([-0.0163, -0.5085, -0.4599,  0.1807])
    >>> torch.mean(a, 1, True)
    tensor([[-0.0163],
            [-0.5085],
            [-0.4599],
            [ 0.1807]])
    

    还有求中位数median()用法和mean是一样的。还有求众数mode()。
    不过这两个的返回值不仅包含了要求的值,还有原tensor中的坐标:

    >>> a = torch.randn(4, 5)
    >>> a
    tensor([[ 0.2505, -0.3982, -0.9948,  0.3518, -1.3131],
            [ 0.3180, -0.6993,  1.0436,  0.0438,  0.2270],
            [-0.2751,  0.7303,  0.2192,  0.3321,  0.2488],
            [ 1.0778, -1.9510,  0.7048,  0.4742, -0.7125]])
    >>> torch.median(a, 1)
    (tensor([-0.3982,  0.2270,  0.2488,  0.4742]), tensor([ 1,  4,  4,  3]))
    

    返回一个tensor中所有元素的乘积:

    torch.prod(input) 
    >>> a = torch.randn(1, 3)
    >>> a
    tensor([[-0.8020,  0.5428, -1.5854]])
    >>> torch.prod(a)
    tensor(0.6902)
    torch.prod(input, dim, keepdim=False, out=None) 
    >>> a = torch.randn(4, 2)
    >>> a
    tensor([[ 0.5261, -0.3837],
            [ 1.1857, -0.2498],
            [-1.1646,  0.0705],
            [ 1.1131, -1.0629]])
    >>> torch.prod(a, 1)
    tensor([-0.2018, -0.2962, -0.0821, -1.1831])
    

    和这种形式类似的还有标准差std(),求和sum(),方差var()。

    剔除tensor中的重复元素,如果设置return_inverse=True,会得到一个元素在在原tensor中的映射表:

    torch.unique(input, sorted=False, return_inverse=False)
    >>> output = torch.unique(torch.tensor([1, 3, 2, 3], dtype=torch.long))
    >>> output
    tensor([ 2,  3,  1])
    
    >>> output, inverse_indices = torch.unique(
            torch.tensor([1, 3, 2, 3], dtype=torch.long), sorted=True, return_inverse=True)
    >>> output
    tensor([ 1,  2,  3])
    >>> inverse_indices
    tensor([ 0,  2,  1,  2])
    
    >>> output, inverse_indices = torch.unique(
            torch.tensor([[1, 3], [2, 3]], dtype=torch.long), sorted=True, return_inverse=True)
    >>> output
    tensor([ 1,  2,  3])
    >>> inverse_indices
    tensor([[ 0,  2],
            [ 1,  2]])
    

    未完待续。。。

    相关文章

      网友评论

        本文标题:pytorch学习8:Tensor

        本文链接:https://www.haomeiwen.com/subject/qojneftx.html