PyTorch自动微分(Autograd)

简介

PyTorch 中所有神经网络的核心是 autograd 自动求导包. 我们先来简单介绍一下, 然后我们会去训练我们的第一个神经网络.

autograd 自动求导包针对张量上的所有操作都提供了自动微分操作. 这是一个逐个运行的框架, 这意味着您的反向传播是由您的代码如何运行来定义的, 每个单一的迭代都可以不一样.

让我们用一些更简单的术语与例子来了解这些套路.

Variable(变量)

autograd.Variable 是包的核心类. 它包装了张量, 并且支持几乎所有的操作. 一旦你完成了你的计算, 你就可以调用 .backward() 方法, 然后所有的梯度计算会自动进行.

你还可以通过 .data 属性来访问原始的张量, 而关于该 variable(变量)的梯度会被累计到 .grad 上去(grad有梯度的意思).

在这里插入图片描述

还有一个针对自动求导实现来说非常重要的类 - Functionfunction有函数的意思).

VariableFunction 是相互联系的, 并且它们构建了一个非循环的图, 编码了一个完整的计算历史信息. 每一个 variable(变量)都有一个 .grad_fn 属性, 它引用了一个已经创建了 VariableFunction (除了用户创建的 Variable 之外 - 它们的 grad_fnNone ).

如果你想计算导数, 你可以在 Variable 上调用 .backward()backward有反向的意思)方法. 如果 Variable 是标量的形式(例如, 它包含一个元素数据), 你不必指定任何参数给 backward(), 但是, 如果它有更多的元素. 你需要去指定一个 grad_output 参数, 该参数是一个匹配 shape(形状)的张量.

import torch
from torch.autograd import Variable

创建 variable(变量):

x = torch.ones(2, 2, requires_grad=True)
print(x)
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

variable(变量)的操作:

y = x + 2
print(y)
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)

y 由操作创建,所以它有 grad_fn 属性.

print(y.grad_fn)
<AddBackward0 object at 0x00000250615600A0>

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_(...)in-place改变一个已有Tensor的requires_grad标志,默认为False

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
b = (a * a).sum()
print(a.requires_grad)
print(b.grad_fn)
print(b.requires_grad)
False
None
False
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
True
<SumBackward0 object at 0x00000250615609D0>

梯度

我们现在开始了解反向传播, out.backward()out.backward(torch.Tensor([1.0])) 这样的方式一样

out.backward()

但因 d ( o u t ) d x \frac{d(out)}{dx} dxd(out) 的梯度:

print(x.grad)
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

应该是会得到一个元素全为 4.5 的矩阵。让我们推导出out Variable“ o o o”。我们有 o = 1 4 ∑ i z i o = \frac{1}{4}\sum_iz_i o=41izi , z i = 3 ( x i + 2 ) 2 z_i=3(x_i+2)^2 zi=3(xi+2)2 和 $z_i\mid_{x_i=1}=27 。 因 此 , 。因此, \frac{∂o}{∂x_i}\mid_{x_i=1}= \frac{∂o}{∂z_i}\frac{∂z_i}{∂x_i} = \frac{1}{4}(6x_i+12)= \frac{3}{2}(x_i+2) =\frac{9}{2}=4.5 $

你可以使用自动求导来做很多有趣的事情:

x = torch.randn(3, requires_grad=True)
print(x)

y = x * 2
while y.data.norm() < 1000: #也可以直接写y.norm(), norm()计算y的p-范数,默认p=2
    y = y * 2

print(y)
tensor([ 1.1708, -0.1020, -0.4631], requires_grad=True)
tensor([1198.9468, -104.4859, -474.1878], grad_fn=<MulBackward0>)
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)
tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])

再来一个例子:

x = torch.tensor([[1,2,4],[3,1,2]], dtype=torch.float, requires_grad=True)
print(x)

y = x + 2
z = y * y
print(z)

z.backward(torch.ones_like(x))
print(x.grad) #计算得到的就是z相对于x的导数
tensor([[1., 2., 4.],
        [3., 1., 2.]], requires_grad=True)
tensor([[ 9., 16., 36.],
        [25.,  9., 16.]], grad_fn=<MulBackward0>)
tensor([[ 6.,  8., 12.],
        [10.,  6.,  8.]])

也可以通过将代码块封装进with torch.no_grad(),来暂停.requires_grad=True的Tensors的历史跟踪。

print(x.requires_grad)
print((x ** 2).requires_grad)

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

print((x ** 2).requires_grad)
True
True
False
True

参考:
1.https://blog.csdn.net/anhec/article/details/96422609
2.https://pytorch.apachecn.org/docs/0.3/blitz_autograd_tutorial.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值