Broadcast机制

如果满足以下规则,则两个张量是“可广播的”:
1、每个张量具有至少一个维度。
2、从尾部开始迭代张量时,对应维度的长度要么相等,要么其中一个维度的长度为1,或者不存在。
如果张量x和y可以符合广播的条件,那么:结果张量可以按照下面的方式计算:
1、如果x和y的维度不相同,用1来扩张维度少的那个,使两个张量维度一致。
2、对于每个维度,结果维度是x,y对应维度的最大值。
值得注意的是,通过broadcast扩张的张量在扩张时并不会进行复制,这节省了内存空间

a = torch.rand(5,1,4,1)
b = torch.rand(3,1,1)
print((a+b).shape)
c = torch.rand(1)
d = torch.rand(3,1,7)
print((c+d).shape)

输出

torch.Size([5, 3, 4, 1])
torch.Size([3, 1, 7])

拼接与拆分

cat

在指定的维数进行合并,要求其余维度的长度相同

a = torch.rand(4,3,28,28)
b = torch.rand(5,3,28,28)
print(torch.cat([a,b],0).shape)

输出

torch.Size([9, 3, 28, 28])

stack

在指定的维数进行合并,新生成的张量在指定位置增加一个长度为2的维度,其余维度后移,要求两个张量的shape相同

a = torch.rand(4,3,28,28)
b = torch.rand(4,3,28,28)
print(torch.stack([a,b],1).shape)
print(torch.stack([a,b],3).shape)

输出

torch.Size([4, 2, 3, 28, 28])
torch.Size([4, 3, 28, 2, 28])

split

有两种用法
1.按分配的好的长度在指定的维度上进行分割,可以有多个张量,长度的参数个数要和张量个数相应,且长度之和要和维度的长度相同

c, d, e, f = b.split([2,3,1,2],0)
print(c.shape)
print(d.shape)
print(e.shape)
print(f.shape)

输出

torch.Size([2, 3, 28, 28])
torch.Size([3, 3, 28, 28])
torch.Size([1, 3, 28, 28])
torch.Size([2, 3, 28, 28])

2.按统一的长度在指定的维度上进行均分,可以有多个张量,张量个数和均分的长度相乘的值要和指定维度的长度相同

a = torch.rand(4,3,28,28)
b = torch.rand(8,3,27,28)
c, d = a.split(2,0)
e, f, g = b.split(9,2)
print(c.shape)
print(d.shape)
print(e.shape)
print(f.shape)
print(g.shape)

输出

torch.Size([2, 3, 28, 28])
torch.Size([2, 3, 28, 28])
torch.Size([8, 3, 9, 28])
torch.Size([8, 3, 9, 28])
torch.Size([8, 3, 9, 28])

chunk

在指定的维度上按照张量的个数进行均分,当指定维度的长度不是指定个数的倍数时,会找比这个长度大的最小倍数然后再进行分配

a = torch.rand(4,3,28,29)
b = torch.rand(8,3,27,28)
c, d = a.chunk(2,2)
e, f, g = b.chunk(3,3)
print(c.shape)
print(d.shape)
print(e.shape)
print(f.shape)
print(g.shape)

输出

torch.Size([4, 3, 14, 29])
torch.Size([4, 3, 14, 29])
torch.Size([8, 3, 27, 10])
torch.Size([8, 3, 27, 10])
torch.Size([8, 3, 27, 8])

Tensor运算

基础的数乘

张量之间可以直接使用加减乘除符号(+,-,*,/)进行运算,值得注意的是,这种运算是数乘,且张量之间如果满足Broadcast机制,也可以进行基础运算。也可以使用torch.add(),torch.sub(),torch.mul(),torch.div()来进行运算,结果是一样的。

f = torch.full([2,2],2)
g = torch.full([2,2],3)
h = torch.full([2],8)
print(f+g)
print(f-g)
print(f*g)
print(h/f)

输出

tensor([[5, 5],
        [5, 5]])
tensor([[-1, -1],
        [-1, -1]])
tensor([[6, 6],
        [6, 6]])
tensor([[4., 4.],
        [4., 4.]])

matmul

这种乘法是矩阵相乘,torch.mm()仅限二维,torch.matmul()可以适用于多维,所以不管是哪种维度,都推荐使用matmul(),可以直接使用运算符号@代替matmul。不同维度的张量相乘时,Broadcast机制同样也适用,且多维的张量进行matmul运算时,只会在最后的两个维度进行。

a = torch.rand(4,3,28,64)
b = torch.rand(1,64,32)
print(torch.matmul(a,b).shape)
print((a @ b).shape)

输出

torch.Size([4, 3, 28, 32])
torch.Size([4, 3, 28, 32])

tensor的平方、开方运算

tensor的平方、开放运算也是类似与数乘,和矩阵相乘不同。Tensor.pow(x)和Tensor**x等价,都是Tensor的x次方运算。
Tensor.sqrt()是开方运算,Tensor.rsqrt()是先开方再取倒数。

f = torch.full([2,2],2)
g = torch.full([2,2],9)
print(f.pow(3))
print(f**3)
print(g.sqrt())
print(g.rsqrt())

输出

tensor([[8, 8],
        [8, 8]])
tensor([[8, 8],
        [8, 8]])
tensor([[3., 3.],
        [3., 3.]])
tensor([[0.3333, 0.3333],
        [0.3333, 0.3333]])

Exp Log

Exp运算也是与矩阵数乘类似,与矩阵乘法不同,torch.exp()是张量乘以无理数e,torch.log()是张量进行log运算,默认是以e为底

a = torch.exp(torch.ones(2,2,2))
print(a)
print(torch.log(a))

输出

tensor([[[2.7183, 2.7183],
         [2.7183, 2.7183]],

        [[2.7183, 2.7183],
         [2.7183, 2.7183]]])
tensor([[[1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.]]])

近似值

.floor()是向下取整,.ceil()是向上取整,.round()是四舍五入,.trunc()是整数部分,.frac()是小数部分

a = torch.tensor(3.14)
print(a.floor(),a.ceil(),a.trunc(),a.frac())
b = torch.tensor(3.499)
print(b.round())
c = torch.tensor(3.5)
print(c.round())

输出

tensor(3.) tensor(4.) tensor(3.) tensor(0.1400)
tensor(3.)
tensor(4.)

Clamp

clamp(min)是让张量内小于min的值为min,clamp(min,max)是让张量内的值小于min的为min,大于max的为max。

grad = torch.rand(2,3) * 15
print(grad)
print(grad.clamp(10))
print(grad.clamp(5,12))

输出

tensor([[14.6030,  9.7245,  7.8587],
        [ 6.0906,  4.5278,  4.5055]])
tensor([[14.6030, 10.0000, 10.0000],
        [10.0000, 10.0000, 10.0000]])
tensor([[12.0000,  9.7245,  7.8587],
        [ 6.0906,  5.0000,  5.0000]])

Tensor统计

求范数

pytorch中的torch.norm主要用于计算矩阵和向量的p范数,具体的用法如下所示:
torch.norm(input, p=‘fro’, dim=None, keepdim=False, out=None, dtype=None)

  • input (Tensor):
    输入的张量,数据类型必须是浮点型或复杂输入。对于复杂输入,使用每个元素的绝对值计算范数。如果输入很复杂,并且未指定dtype或out,则结果的数据类型将是相应的浮点类型
  • p (int, float, inf, -inf, ‘fro’,‘nuc’, optional):
    表示指定的范数,其中默认类型’fro’为Frobenius范数,'nuc’表示矩阵的核范数
  • dim (int, tuple of python:ints, list of python:ints, optional):
    指定要计算范数的输入维度。如果dim为None,则将在输入的所有维度上计算范数。
  • keepdim (bool, optional): 输出的张量是否保持不变,默认值是False,如果dim = None和out =
    None,则该参数会被省略掉
  • out (Tensor, optional): 输出的张量,如果dim = None和out = None,则该参数会被省略掉
  • dtype (torch.dtype, optional):
    返回的张量的所需数据类型。如果指定,则在执行操作时将输入张量转换为dtype。默认值是None

求统计值

min()求最小值, max()求最大值, mean()求平均值, sum求总和, prod()求累乘
argmin()求最小值的索引, argmax()求最大值的索引

    a = torch.arange(8).view(2,4).float()
    print(a)
    print(a.min(),a.max(),a.mean(),a.prod(),a.sum())
    print(a.argmax(),a.argmin())

输出

tensor([[0., 1., 2., 3.],
        [4., 5., 6., 7.]])
tensor(0.) tensor(7.) tensor(3.5000) tensor(0.) tensor(28.)
tensor(7) tensor(0)

对于min()和max()以及argmin()和argmax()还可以通过dim和keepdim这两个参数控制输出

a = torch.arange(15).view(3,5).float()
    print(a)
    print(a.max(0,True))
    print(a.argmax(0,True))
    print(a.max(1,True))
    print(a.argmin(1,True))

输出

tensor([[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.]])
torch.return_types.max(
values=tensor([[10., 11., 12., 13., 14.]]),
indices=tensor([[2, 2, 2, 2, 2]]))
tensor([[2, 2, 2, 2, 2]])
torch.return_types.max(
values=tensor([[ 4.],
        [ 9.],
        [14.]]),
indices=tensor([[4],
        [4],
        [4]]))
tensor([[0],
        [0],
        [0]])

求多个最值

通过topk()可以求最大的几个值或者最小的几个值,通过kthvalue可以求第几大的值

比较

张量可以通过>, >=, <, <=, !=, ==这几个运算符进行比较,返回的是布尔值0或1
torch.eq()比较的是两个张量,返回的是张量形状的布尔值
torch.equal()直接返回的是两个张量是否完全相等


Tensor高阶操作

Where

利用两个张量通过torch.where(condition, x, y)生成新的张量,根据condition的布尔张量决定取哪个张量的值生成新的张量
如果是1则选取x的值,如果是0则选取y的值

condition = torch.tensor([[0.6897,0.7271],
                        [0.8884,0.4163]])
a = torch.tensor([[0.,0.],
                [0.,0.]])
b = torch.tensor([[1.,1.],
                [1.,1.]])
print(torch.where(condition > 0.5,a,b))

输出

tensor([[0., 0.],
        [0., 1.]])

gather

gather其实是对input的一种映射,index必须是LongTensor类型

b = torch.tensor([[1,2,3],[4,5,6]])
print(b)
index_1 = torch.LongTensor([[0,1],[2,0]])
index_2 = torch.LongTensor([[0,1,1],[0,0,0]])
print(torch.gather(b, dim=1, index=index_1))
print(torch.gather(b, dim=0, index=index_2))

输出

tensor([[1, 2, 3],
        [4, 5, 6]])
tensor([[1, 2],
        [6, 4]])
tensor([[1, 5, 6],
        [1, 2, 3]])

-------------完-------------