目录

  • 自动微分
  • 张量调整形状
  • 广播机制
  • 索引与切片
  • 降维与升维


自动微分

Pytorch支持自动微分,即自动计算梯度,无需人工参与,既可以自动计算一个函数关于一个变量在某一取值下的导数。通过该功能,就可以使用基于梯度的方法对参数(变量)进行优化(也叫学习或训练)。使用Pytorch计算梯度非常容易,仅需要执行tensor.backward()函数,就可以通过反向传播算法自动完成。

需要注意,为了计算一个函数关于某一个变量的导数,Pytorch要求显示设置该变量(张量)是可求导的,否则默认不能对该变量求导。具体设置方法为:在张量生成时,设置requires_grad=True

因此,计算pytorch手动计算梯度 pytorch自定义梯度计算_广播机制中,当pytorch手动计算梯度 pytorch自定义梯度计算_深度学习_02时,求pytorch手动计算梯度 pytorch自定义梯度计算_深度学习_03pytorch手动计算梯度 pytorch自定义梯度计算_深度学习_04的值:

import torch

x=torch.tensor([2.],requires_grad=True)
y=torch.tensor([3.],requires_grad=True)

z=(x+y)*(y-2)
print(z)
# tensor([5.], grad_fn=<MulBackward0>)

z.backward()
print(x.grad,y.grad)
# tensor([1.]) tensor([6.])

我们手动验证:pytorch手动计算梯度 pytorch自定义梯度计算_python_05pytorch手动计算梯度 pytorch自定义梯度计算_深度学习_02时,梯度确实为pytorch手动计算梯度 pytorch自定义梯度计算_python_07pytorch手动计算梯度 pytorch自定义梯度计算_pytorch_08

张量调整形状

参与运算的张量需要满足一定的形状,比如两个矩阵相乘,前一个矩阵的第二维应该和后一个矩阵的第一维相同。Pytorch一共有4种调整张量形状的函数,分别为view,reshape,transpose,permute

view函数的参数用于设置新的张量形状,因此,需要保证张量总的元素个数不变:

x=torch.tensor([1,2,3,4,5,6])
print(x.shape) # torch.Size([6])
y=x.view(-1,3)
print(y.size()) # torch.Size([2, 3])

进行view操作的张量要求是连续的(Contiguous),可以调用is_conuous函数判断一个张量是否为连续的。如果张量非连续,则需要先调用contiguous函数将其变为连续的,才能使用view。为了克服这个缺点,Pytorch提供了reshape,可以对非连续张量调整形状,reshape与view的功能一致。

transpose(转置)函数用于交换张量中的两个维度,参数分别为相应的维序号:

x=torch.tensor([[1,2,3],[4,5,6]])
print(x)
"""
torch.Size([2, 3])
tensor([[1, 2, 3],
        [4, 5, 6]])
"""
y=x.transpose(0,1) # 交换第1维和第2维
print(y)
"""
torch.Size([3, 2])
tensor([[1, 4],
        [2, 5],
        [3, 6]])
"""

transpose只能同时交换两个维度,若要交换更多维度,需要多次调用该函数,为了便捷,Pytorch提供了permute函数,其需要提供全部维度信息作为参数(即使有些维度无须交换也要提供):

x=torch.tensor([[[1,2,3],[4,5,6]]])
print(x,x.shape)
"""
tensor([[[1, 2, 3],
         [4, 5, 6]]]) torch.Size([1, 2, 3])
"""
y=x.permute(2,0,1)
print(y,y.shape)
"""
tensor([[[1, 4]],
        [[2, 5]],
        [[3, 6]]]) torch.Size([3, 1, 2])
"""

广播机制

在上面的张量运算中,都是假设两个参与运算的张量形状相同。在有些情况下,即使两个张量的形状不同,也可以通过广播机制执行按元素计算。具体的执行规则为:

  • 首先,对其中一个或同时对两个张量的元素进行复制,使得两个张量形状相同;
  • 然后,在扩展之后的张量上再执行按元素运算。

通常是沿着长度为1的维度进行扩展,示例如下:

x=torch.arange(1,4).view(3,1)
y=torch.arange(4,6).view(1,2)
print(x)
"""
tensor([[1],
        [2],
        [3]])
"""
print(y)
"""
tensor([[4, 5]])
"""

生成两个张量,形状分别为(3,1)和(1,2),显然,它们不能直接执行按元素运算。因此,在执行按元素运算之前,需要将它们扩展(广播)为形状(3,2)的张量,具体扩展方法为将x的第1列复制到第2列,将y的第1行复制到第2行,第3行。

比如,执行加法:

print(x+y)
"""
tensor([[5, 6],
        [6, 7],
        [7, 8]])
"""

索引与切片

与Python列表类似,Pytorch中也可以对张量进行索引和切片操作,规则也与Python基本一致,即索引值是从0开始的,切片[m:n]的范围是从m开始到n前一个元素结束(左闭右开)。与Python不同,Pytorch可以对张量的任意一个维度进行索引或切片:

x=torch.arange(12).view(3,4)
print(x)
"""
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
"""
print(x[1,3]) # 取第2行第4列的元素
"""
tensor(7)
"""
print(x[1]) # 取第2行全部元素
"""
tensor([4, 5, 6, 7])
"""
print(x[1:3]) # 取第2,3两行的元素
"""
tensor([[ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
"""
print(x[:,2]) # 取第3列全部元素
"""
tensor([ 2,  6, 10])
"""
print(x[:,2:4]) # 取第3,4两列的元素
"""
tensor([[ 2,  3],
        [ 6,  7],
        [10, 11]])
"""
x[:,2:4]=100 # 第3,4两列元素全部赋值100
print(x)
"""
tensor([[  0,   1, 100, 100],
        [  4,   5, 100, 100],
        [  8,   9, 100, 100]])
"""

降维与升维

升维通过调用torch.unsqueeze(input,dim,out=None)函数,对输入张量的dim位置插入维度1,并返回一个新的张量。与索引相同,dim的值可以为负数。

降维恰好相反,使用torch.squeeze(input,dim,out=None)函数:

  • 在不指定dim时,张量中形状为1的所有维都将被去除。比如输入形状为pytorch手动计算梯度 pytorch自定义梯度计算_pytorch_09的张量,输出形状变成pytorch手动计算梯度 pytorch自定义梯度计算_python_10
  • 当给定dim时,降维操作只在给定维度上,比如输入形状为pytorch手动计算梯度 pytorch自定义梯度计算_广播机制_11,如果设置squeeze(input,dim=0),张量形状将保持不变,只有设置squeeze(input,dim=1),形状才会变成pytorch手动计算梯度 pytorch自定义梯度计算_pytorch手动计算梯度_12