Ch01-02.自动求导(Pytorch入门)

自动求导机制

PyTorch 中所有神经网络的核心是 autograd 包。 我们先简单介绍一下这个包,然后训练第一个简单的神经网络。
autograd包为张量上的所有操作提供了自动求导。 它是一个在运行时定义的框架,这意味着反向传播是根据你的代码来确定如何运行,并且每次迭代可以是不同的。

张量(Tensor)

torch.Tensor是这个包的核心类,如果设置.requires_grad为True, 那么就会追踪所有对于该张量的操作。当完成计算后通过调用.backward(),自动计算所有梯度,这个张量的所有梯度都会自动累计到.grad属性。
要阻止张量跟踪历史记录,可以调用.detach()方法将其与计算历史记录分离,并禁止跟踪它将来的计算记录。

推断时 为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算。
在自动梯度计算中还有另外一个重要的类Function.
Tensor和Function互相连接并生成一个非循环图,它表示和存储了完整的计算历史,每个张量都由.grad_fn属性,这个属性引用了一个创建了Tensor的Function(除非这个Tensor是由用户手动创建,即,该张量的.grad_fn是None)
如果需要计算导数,你可以再Tensor上调用.backward()。如果Tensor是一个标量(即它包含一个元素数据)则不需要为backward()指定任何参数,但是如果有更多元素,你需要指定一个gradient参数来匹配张量形状。

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>)
x.requires_grad_(True)
# 可以用于改变requires_grad属性

梯度

反向传播因为out是一个纯量(scalar), out.backward()等于out.backward(torch.tensor(1))

out.backward()
# 打印 d(out)/dx 梯度
print(x.grad)

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

总结流程:

  1. 当我们执行z.backward()的时候,这个操作将调用z里面的grad_fn属性,执行求导的操作
  2. 这个操作将遍历grad_fn的next_functions, 然后分别取出里面的Function(AccumulateGrad), 执行求导操作,这个部分是一个递归的过程直到最后类型为叶子节点。
  3. 计算出结果以后,将结果保存在他们对应的variable这个变量所引用的对象(x和y)的grad这个属性里面
  4. 求导结束。所有叶节点的grad变量都得到相应的更新
    最终当我们执行完c.backward()之后,a和b里面的grad值就得到了更新。

扩展Autograd

如果需要自定义autograd扩展新的功能,需要扩展Function类,因为Function使用autograd来计算结果和梯度,并对操作历史进行编码。在Function类中最主要的方法是forward()和backward()他们分别代表前向传播和后向传播。
一个自定义的Function需要以下三个方法:
init(optional):如果该操作需要额外的参数,则需要定义该function的构造函数,不需要可以省略
forward(): 执行前向传播的计算代码
backward():执行后向传播的计算代码

# 引入Function便于扩展
from torch.autograd.function import Function
# 定义一个乘以常数的操作(输入参数是张量)
# 方法必须是静态方法,所以要加上@staticmethod 
class MulConstant(Function):
    @staticmethod 
    def forward(ctx, tensor, constant):
        # ctx 用来保存信息这里类似self,并且ctx的属性可以在backward中调用
        ctx.constant=constant
        return tensor *constant
    @staticmethod
    def backward(ctx, grad_output):
        # 返回的参数要与输入的参数一样.
        # 第一个输入为3x3的张量,第二个为一个常数
        # 常数的梯度必须是 None.
        return grad_output, None 
# 测试定义的Function
a=torch.rand(3,3,requires_grad=True)
b=MulConstant.apply(a,5)
print("a:"+str(a))
print("b:"+str(b)) # b为a的元素乘以5
#a:tensor([[0.0118, 0.1434, 0.8669],
#        [0.1817, 0.8904, 0.5852],
#        [0.7364, 0.5234, 0.9677]], #requires_grad=True)
#b:tensor([[0.0588, 0.7169, 4.3347],
#        [0.9084, 4.4520, 2.9259],
#        [3.6820, 2.6171, 4.8386]], grad_fn=<MulConstantBackward>)

# 反向传播,返回值不是标量,所以backward要参数
b.backward(torch.ones_like(a))
a.grad
#tensor([[1., 1., 1.],
#        [1., 1., 1.],
#        [1., 1., 1.]])
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342