PyTorch学习日志_20201030_ Autograd 包

日期:2020.10.30
主题:PyTorch入门
内容:

  • 根据PyTorch官方教程文档,学习PyTorch中所有神经网络的核心——Autograd 包的基础操作(主要与张量相关)。

  • 根据自己的理解和试验,为代码添加少量注解。

具体代码如下 ↓

from __future__ import print_function
import torch

"""
{Autograd:自动求导}
 PyTorch中,所有神经网络的核心是 autograd 包,其为张量上的所有操作提供了自动求导机制。
    它是一个在运行时定义(define-by-run)的框架。
        这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。
"""

"""
【张量】
1.Tensor 是 autograd 包的核心类,其有 .grad 属性。
    若它的属性 .requires_grad 为 True,那么它将会追踪对于该张量的所有操作。
        当完成计算后可以通过调用 .backward(),来自动计算所有的梯度,自动累加到.grad属性.
    若要阻止跟踪历史,可以调用 .detach() 方法
        该方法将张量与计算历史分离,并阻止它未来的计算记录被跟踪。
2.Function 是 autograd 包的另一个重要的类
    Tensor 和 Function 互相连接生成了一个无圈图(acyclic graph),它编码了完整的计算历史。
    每个张量都有一个 .grad_fn 属性
        该属性引用了创建 Tensor 自身的Function(默认为None)
    若需要计算导数,可以在 Tensor 上调用 .backward()。
        如果 Tensor 是一个标量(即它包含一个元素的数据),则不需要为 backward() 指定任何参数;
        但是如果它有更多的元素,则需要指定一个 gradient 参数,该参数是形状匹配的张量。
"""

# 创建一个张量并设置requires_grad=True用来追踪其计算历史
x = torch.ones(2, 2, requires_grad=True)
print(x)
print("x.grad_fn = ", x.grad_fn) # x不是通过运算方法来创建,故其grad_fn = none

# 对这个张量做一次加法运算
y = x + 2
print('\n', y)
print("y.grad_fn = \n", y.grad_fn) # y由加法创建,所以它的grad_fn = AddBackward0

# 同理,对张量做一次Hadamard积
z = x * y
print('\n', z)
print("z.grad_fn = \n", z.grad_fn) #y由Hadamard积产生,所以它的grad_fn = MulBackward0

# 同理,对张量做一次矩阵乘法
z = x @ y
print('\n', z)
print("z.grad_fn = \n", z.grad_fn) #y由Hadamard积产生,所以它的grad_fn = MmBackward
print('-'*40, '\n')


# 对张量求均值
z = torch.tensor([[1., 0., 2.],
                  [0., 1., 0.],
                  [1., 0., 2.]])
print(z)
out = z.mean() # 对 m*n 个数求均值,返回一个实数 0.7778
print("\nz.mean() = ", out)
out = z.mean(0) # 压缩行,对各列求均值,返回 1* n 矩阵
print("\nz.mean(0) =\n", out)
out = z.mean(1) # 压缩列,对各行求均值,返回 m *1 矩阵
print("\nz.mean(1) =\n", out)
print('-'*40, '\n')


# .requires_grad_(...) 原地改变了现有张量的 requires_grad 标志(默认为 False)。
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print("a.requires_grad = ", a.requires_grad) # False

a.requires_grad_(True) # 开始追踪a的计算历史
print("a.requires_grad = ", a.requires_grad) # True

b = (a * a).sum() # b继承a的 requires_grad 属性,其计算历史被追踪
print("b.grad_fn = \n", b.grad_fn) # SumBackward0
print('-'*40, '\n')
 

"""
【梯度】
 通常来说,torch.autograd 是计算雅可比向量积的一个“引擎”。
"""
y = x + 2
z = y * y * 3
out = z.mean() 
print(out, '\n') # tensor(27., grad_fn=<MeanBackward0>) 

# 调用 .backward(),进行反向传播(自动计算所有的梯度,并累加到 .grad 属性)。
out.backward() # out.backward() == out.backward(torch.tensor(1.))(因为 out 是标量)
print(x.grad) # 输出导数 d(out)/dx
# 先将整个过程“平铺陈述”,详细到“祖先”,再进行梯度计算
# 数学上,若有向量值函数y = f(x),则y相对于x的梯度是一个雅可比矩阵
print('-'*40, '\n')


# 雅可比向量积的例子
x = torch.ones(3, requires_grad=True)
y = x * 2
t = 0
print(x, '\n')
while y.data.norm() < 10: # y.data.norm()指的是y的范数
    y = y * 2
    t += 1
print(y, t, '\n')
# 在这种情况下,y 不再是标量。

# torch.autograd 不能直接计算完整的雅可比矩阵,
# 但若只想要雅可比向量积,只需将这个向量作为参数传给 backward
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float) # v可视为每个out分量对an求导时的权重
y.backward(v) # 相当于对张量做一次Hadamard积
print(x.grad)
print('-'*40, '\n')


# 可以将代码块包装在 with torch.no_grad(): 中,来阻止跟踪。
x.requires_grad = False     # 先将x的跟踪关闭
print("(x ** 2).requires_grad = ", (x ** 2).requires_grad) # False

with torch.no_grad():
    x.requires_grad = True # 在封装代码中尝试打开x的跟踪
    print("(x ** 2).requires_grad = ", (x ** 2).requires_grad) # False
    
print("(x ** 2).requires_grad = ", (x ** 2).requires_grad, '\n') # True
# 可见在包装中的代码依然有效,包装只是暂时“搁置”了对x的跟踪请求(“按下不表”)




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值