虽然我在前面写到没有必要去阅读整个官方文档,但是在开发过程中发现,如果对整个文档特别是关于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的函数:
-
torch.Tensor.bernoulli_()
- in-place version oftorch.bernoulli()
,伯努利分布 -
torch.Tensor.cauchy_()
- numbers drawn from the Cauchy distribution,柯西分布 -
torch.Tensor.exponential_()
- numbers drawn from the exponential distribution,指数分布 -
torch.Tensor.geometric_()
- elements drawn from the geometric distribution,几何分布 -
torch.Tensor.log_normal_()
- samples from the log-normal distribution,对数正太分布 -
torch.Tensor.normal_()
- in-place version oftorch.normal()
,正太分布 -
torch.Tensor.random_()
- numbers sampled from the discrete uniform distribution,均匀分布 -
torch.Tensor.uniform_()
- numbers sampled from the continuous uniform distribution,连续均匀分布
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]])
未完待续。。。
网友评论