zoukankan      html  css  js  c++  java
  • [PyTorch入门之60分钟入门闪击战]之自动推倒

    AUTOGRAD: AUTOMATIC DIFFERENTIATION(自动分化)

    来源于这里

    autograd包是PyTorch中所有神经网络的核心。首先我们先简单地了解下它,然后我们将训练我们的第一个神经网络。

    autograd包为Tensors上的所有操作提供自动分化。它是一个逐步执行的框架,这意味着你的反向传播(backprop)函数是由你的代码运行方式定义的,而且每个迭代器可以是不同的。接下来通过一些例子用更简单的术语来了解autograd

    Tensor

    torch.tensorautograd包的核心。如果你将它的属性.requires_grad设置为True,那么它将开始追踪其上的所有操作。当完成你的计算之后,你可以调用.backward()是所有的梯度自动计算完成。这个张量的梯度会被累积到.grad属性中。

    要停止张量追踪记录,你可以使用.detach()将它熊计算记录中分离出来,并防止将来的计算被追踪。

    为了阻止追踪记录(和使用内存),你可以使用with torch.no_grad()打包代码块。这在评估模型的时候非常有用,因为当模型的requires_grad=True时,可能具有可训练的参数,但我们并不需要这些梯度。

    另外还有一个对自动推倒非常重要的类 --- Function

    TensorFunction相互关联、构建出一个无环图,它编码了一个完整的计算历史记录。每个tensor都有一个.grad_fn属性,该属性引用自一个创建张量(用户创建的张量除外,它们的.grad_fn是空)的函数。

    如果你想计算导数,你可以调用张量上的backward()。如果张量是一个标量(比如它只有一个数据元素),那么你不需要给backward()传递任何特殊的参数;但是如果它拥有多个元素,你需要指定一个特殊的梯度参数,它是一个与形状匹配的张量。

    创建一个张量,并设置requires_grad=True来追踪计算。

    import torch
    x = torch.ones(2,2,requires_grad=True)
    print(x)
    

    输出

    tensor([[1., 1.],
            [1., 1.]], requires_grad=True)
    

    进行一次张量操作:

    y = x + 2
    print(y)
    

    输出:

    tensor([[3., 3.],
            [3., 3.]], grad_fn=<AddBackward0>)
    

    y是作为一个操作的结果被创建的,所以它有grad_fn属性:

    print(y.grad_fn)
    

    输出:

    <AddBackward0 object at 0x121669470>
    

    y进行更多操作:

    z = y * y * 3
    out = z.mean()
    print(z,out)
    
    tensor([[27., 27.],
            [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
    

    。requires_grad_(...)可以改变已存在张量的requires_grad属性。如果为给定,该输入标识默认为False

    a = torch.randn(2,2)
    a = ((a * 3) / (a - 1))
    print(a.requires_grad)
    a.requires_grad_(True)
    print(a.requires_grad)
    b = (a * a).sum()
    print(b.grad_fn)
    

    输出:

    False
    True
    <SumBackward0 object at 0x121726588>
    

    Gradients(梯度)

    现在进行反向传播。因为out只包含一个标量,out.backward()等价于out.backward(torch.tensor(1.))

    out.backward()
    

    打印梯度 d(out)/dx:

    print(x.grad)
    

    输出:

    tensor([[4.5000, 4.5000],
            [4.5000, 4.5000]])
    

    如上,得到了一个4.5填充的2x2的矩阵。我们将out张量命名为(omicron)。我们知道(omicron = frac{1}{4}sum_iz_i,z_i = 3(x_i+2)^2),而且(z_i|_{x_i=1} = 27),那么,(frac{sigma_omicron}{sigma_{x_i}} = frac{3}{2}(x_i + 2)),因此(frac{sigma_omicron}{sigma_{x_i}}|_{x_i=1} = frac{9}{2} = 4.5)

    在数学上,如果你有一个向量值函数(vec{y} = f(vec{x})),那么遵循(vec{x})(vec{y})的梯度是一个Jacobian矩阵:

    [ J = egin{pmatrix} frac{sigma_{y_1}}{sigma_{x_1}} quad cdots quad frac{sigma_{y_1}}{sigma_{x_n}} \ vdots quad ddots quad vdots \ frac{sigma_{y_m}}{sigma_{x_1}} quad cdots quad frac{sigma_{y_m}}{sigma_{x_n}} end{pmatrix}]

    通常来讲,torch.autograd是一个计算vector-Jacobian结果的引擎。也就是说,给定任意的(v = (v_1 quad v_2 quad cdots quad v_m)^T),计算(v^T cdot J)的结果。如果(v)恰好是标量函数(l = g(vec{y}))的梯度,那么(v = (frac{sigma_l}{sigma_{y_1}} quad cdots quad frac{sigma_l}{sigma_{y_n}})),然后根据链接规则,vector-Jacobain的结果就是遵循(vec{x})(l)的梯度:

    [J^T cdot v = egin{pmatrix} frac{sigma_{y_1}}{sigma_{x_1}} quad cdots quad frac{sigma_{y_m}}{sigma_{x_1}} \ vdots quad ddots quad vdots \ frac{sigma_{y_1}}{sigma_{x_n}} quad cdots quad frac{sigma_{y_m}}{sigma_{x_n}} end{pmatrix} egin{pmatrix} frac{sigma_l}{sigma_{y_1}} \ vdots \ frac{sigma_l}{sigma_{y_m}} end{pmatrix} = egin{pmatrix} frac{sigma_l}{sigma_{x_1}} \ vdots \ frac{sigma_l}{sigma_{x_n}} end{pmatrix}]

    注意 (v^T cdot J)给出了一个可以看做是从(J^T cdot v)获取的列向量的行向量。

    vector-Jacobain结果的特性使得在一个非标量输出的模型中反馈外部梯度非常方便。

    现在我们来看一个vector-Jacobain结果的例子:

    x = torch.rands(3,requires_grad=True)
    y = x * 2
    
    while y.data.norm() < 1000:
        y = y * 2
    
    print(y)
    

    输出:

    tensor([805.7939, -90.6879, 624.5883], grad_fn=<MulBackward0>)
    

    现在这种情况下,y不再是一个标量。torch.autograd不能直接计算完整的Jacobain矩阵,但如果我们只想要vector-Jacobain结果,那么只需将向量作为参数传递给backward即可。

    v = torch.tensor([0.1,1.0,0.0001],dtype=torch.float)
    y.backward(v)
    
    print(x.grad)
    

    输出:

    tensor([2.5600e+01, 2.5600e+02, 2.5600e-02])
    

    你也可以通过使用with torch.no_grad()打包代码块的方式在.requires_grad=True的张量上停止追踪历史记录的自动推倒。

    print(x.requires_grad)
    print((x ** 2).requires_grad)
    
    with torch.no_grad():
        print((x ** 2).requires_grad)  
    

    输出:

    True
    True
    False
    

    进阶阅读

    更详细的autogradFunction文档在这里

  • 相关阅读:
    java泛型的一些知识点:Java泛型--泛型应用--泛型接口、泛型方法、泛型数组、泛型嵌套
    Java遍历Map的四种方式
    Less20、21、22【报错注入+Cookie字段注入+Base64编码】
    Less18、19【报错注入+User-Agent、Referer字段注入】
    Less17【报错注入+Update注入/时间注入】
    Less-16【盲注+时间注入】
    Less-15【盲注+时间注入】
    Less-14【报错注入】
    Less-12、13【报错注入】
    Less-11【报错注入】
  • 原文地址:https://www.cnblogs.com/lianshuiwuyi/p/11097053.html
Copyright © 2011-2022 走看看