zoukankan      html  css  js  c++  java
  • PyTorch学习笔记4--PyTorch自动微分

    PyTorch所有神经网络的核心是autograd自动微分。该 autograd 软件包为 Tensors 上的所有操作提供自动微分。

    计算图 = Tensor + Function

    PyTorch也是以计算图为核心进行微分的。这与TensorFlow中是一致的。在计算图中,圆圈/矩形等表示Tensor,而线条表示计算操作(TensorFlow里是Ops,PyTorch里是Function,本质相同)。在PyTorch里,TensorFunction互相连接并生成一个非循环图,它表示和存储了完整的计算历史。 每个张量都有一个.grad_fn属性,这个属性引用了一个创建该Tensor的Function(除非这个张量是用户手动创建的,即,这个张量的 grad_fn 是 None)。

    1. 要追踪所有对于某张量的操作,设置其.requires_gradTrue即可。
    2. 要计算对某张量的梯度,得到某Tensor后对其调用 .backward(),这个张量的所有梯度将会自动积累到 .grad 属性。
    3. 要阻止张量跟踪历史记录,可以调用.detach()方法将其与计算历史记录分离,并禁止跟踪它将来的计算记录。

    为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算。

    import torch
    #--------------------------------------------
    x = torch.ones(2, 2, requires_grad=True)
    print(x)
    # 新建全1矩阵,跟踪计算记录
    # 打印结果为
    tensor([[1., 1.],
            [1., 1.]], requires_grad=True)
    #--------------------------------------------
    y = x + 2
    print(y)
    print(y.grad_fn)
    # 对张量x进行了操作,得到y,脑袋里思考这里形成了一个什么样的计算图
    # 打印结果为(grad_fn被自动生成了,显示了构建此Tensor的Function是加法)
    tensor([[3., 3.],
            [3., 3.]], grad_fn=<AddBackward>)
    <AddBackward object at 0x00000232535FD860>
    #--------------------------------------------
    z = y * y * 3
    out = z.mean()
    print(z, out)
    # 打印结果为
    tensor([[27., 27.],
            [27., 27.]], grad_fn=<MulBackward>) tensor(27., grad_fn=<MeanBackward1>)
    #--------------------------------------------
    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)
    # .requires_grad_( ... ) 可以改变现有张量的 requires_grad属性
    # 运行结果为
    False
    True
    <SumBackward0 object at 0x000002325360B438>
    

    以上程序示范了如何使用requires_grad跟踪Tensor的生成过程,也就是计算图(模型)的生成过程:其中张量x是2x2的全1矩阵,张量y是2x2的全3矩阵,张量z是2x2的全27矩阵,张量out是标量,z的平均值。

    因为(out=frac{1}{4} sum_{i}z_{i}),而(z_{i} = 3(x_{i} + 2)^{2}),因此(frac{partial out}{partial x_{i}} = frac{3}{2}(x_{i}+2)),所以(frac{partial out}{partial x_{i}}=4.5)

    # ...
    # 当计算图构建完成,可以开始计算梯度了,下面一行代码自动完成梯度的计算:
    out.backward() # out是标量,因此不需要为backward()函数指定参数,相当于out.backward(torch.tensor(1))
    print(x.grad) # backward自动计算该Tensor的梯度,x.grad即为到x这里的梯度,指定了自变量为x而非y和z。
    # 计算结果为
    tensor([[4.5000, 4.5000],
            [4.5000, 4.5000]])
    

    以上代码讲了y为标量情况下的求导方法。以下代码介绍y为矢量情况下的求导方法。

    x = torch.randn(3, requires_grad=True) #创建一个x, size为(1,3),初始化为正态随机数。
    y = x * 2 
    while y.data.norm() < 1000: #求得 y^(2^(n))>=1000的最小值
        y = y * 2
    print(y)
    # 打印结果为
    tensor([-920.6895, -115.7301, -867.6995], grad_fn=<MulBackward>)
    
    gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
    y.backward(gradients) #当y为矢量,需要对backward()函数指定参数,该参数指定了求导后的乘因子
    print(x.grad)
    # 打印结果为
    tensor([ 51.2000, 512.0000,   0.0512])
    # 如果gradients因子均为1,则结果应为tensor([ 512.0000, 512.0000,   512.0000])
    

    如果.requires_grad=True但是你又不希望进行autograd的计算, 那么可以将变量包裹在 with torch.no_grad()中:

    print(x.requires_grad)
    print((x ** 2).requires_grad)
    with torch.no_grad():
    	print((x ** 2).requires_grad)
    # 打印结果为
    True
    True
    False
    
  • 相关阅读:
    项目中 2个或者多个EF模型 表名称相同会导致生成的实体类 覆盖的解决方法
    Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法;关于如何查看 EntityValidationErrors 详细信息的解决方法
    深夜杳杳
    我在学习
    IIS下新建虚拟目录
    Win10资源管理器异常
    Docker笔记三:Docker数据卷和DockerFile
    Docker笔记二:Docker拷贝,提交,进入容器和阿里云加速
    ElasticSearch7.x系列三:Logstash的使用
    ElasticSearch7.x系列二:Kibana的使用和C#的Nest客户端
  • 原文地址:https://www.cnblogs.com/charleechan/p/12255191.html
Copyright © 2011-2022 走看看