亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

搜索 pytorch學習8:Tensor

標簽:
Python

虽然我在前面写到没有必要去阅读整个官方文档,但是在开发过程中发现,如果对整个文档特别是关于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.float32torch.float32>>> torch.set_default_dtype(torch.float64)>>> torch.tensor([1.2, 3]).dtype           # a new floating point tensortorch.float64

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


webp

tensor数据类型


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

>>> torch.get_default_dtype()  # initial default for floating point is torch.float32torch.float32>>> torch.set_default_dtype(torch.float64)>>> torch.get_default_dtype()  # default is now changed to torch.float64torch.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.FloatTensortorch.float32

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

torch.set_default_tensor_type(t)

例子如下:

>>> torch.tensor([1.2, 3]).dtype    # initial default for floating point is torch.float32torch.float32>>> torch.set_default_tensor_type(torch.DoubleTensor)
>>> torch.tensor([1.2, 3]).dtype    # a new floating point tensortorch.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 datatensor([ 0,  1])>>> torch.tensor([[0.11111, 0.222222, 0.3333333]],
                 dtype=torch.float64,
                 device=torch.device('cuda:0'))  # creates a torch.cuda.DoubleTensortensor([[ 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)

直接上示例吧:

>>> xtensor([[ 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的之间整数随机排列不含ntorch.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_gradFalse>>> is_train = False>>> with torch.set_grad_enabled(is_train):...     y = x * 2>>> y.requires_gradFalse>>> torch.set_grad_enabled(True)  # this can also be used as a function>>> y = x * 2>>> y.requires_gradTrue>>> torch.set_grad_enabled(False)>>> y = x * 2>>> y.requires_gradFalse

以上基本介绍完了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)

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


webp

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])



作者:shaozi_ss
链接:https://www.jianshu.com/p/cf7adeff2a05


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消