深度学习和PyTorch框架(一)

PyTorch作为深度学习计算框架引擎自诞生之日起就备受瞩目。 其设计接口简单功能丰富,深藏那些复杂实现,是其受欢迎的主要原因之一,成为深度学习框架广受学术和工业界的热爱构建深度学习应用的工具。本文主要介绍一下Torch的核心自动计算导数原理及应用。

Pytorch 自动梯度计算引擎Autograd

Autograd是使PyTorch灵活和快速构建机器学习项目的原因之一。对一个复杂的计算,它能够快速和简单地计算偏导数(partial derivation-也称梯度)。这个操作是基于回溯学习神经网络(backpropagation-based)学习的关键。

这种自动梯度计算的能力来自于它能在运行时动态跟踪计算,这意味着如果你的模型有决策分支,或是循环次数直到运行时确定,这种计算依旧能被正确的跟踪记录,并且你将能得到正确的梯度用于驱动学习。 这种能力加上你的模型用Python构建,比起那些需要用静态分析严格且僵硬的模型计算梯度的框架更具灵活性。

Autograd的作用

机器学习模型是个函数,有输入和输出。为了讨论,我们将设输入为i维向量\vec{x},元素x_{i}。我们然后能用M表示这个输入的向量值函数:\vec{y}=\vec{M}(\vec{x})(模型M的输出值也表示为一个向量,是因为一般来说一个模型或许会有多个输出)。

因为我们将主要讨论在训练(training)情况下的autograd,我们感兴趣的输出将是模型的损失(Loss)函数输出。 损失函数(loss function)L(\vec{y})=L(\vec{M}(\vec{x}))是模型输出的单值标量函数(single-valued scalar function)。这个函数表示的是模型的预测和特定输入值理想输出的差。

在训练一个模型中,我们想使损失值最小化。在一个完美模型的理想情况下,那意味着调整学习权重参数,也就是说调整这个函数的参数,比如对所有的输入来说损失为零。在现实情况下,这意味着一个迭代进程用于调整学习权重参数直到我们看到一个对广泛的输入可以得到可容忍的损失值。

我们怎么能确定和在那个方向上调整权重参数?我们要最小化损失值,意味着要使对应输入的一阶导数等于0:\frac{\partial L}{\partial x}=0

回忆一下,尽管,损失值不是直接从输入获取到而是一个模型输出的函数(它是输入的函数),\frac{\partial L}{\partial x}=\frac{\partial L(\vec{y})}{\partial x}。根据微积分的链规则(Chain Rule),我们可以得到:\frac{\partial L(\vec{y})}{\partial x}=\frac{\partial L}{\partial y}\frac{\partial y}{\partial x}=\frac{\partial L}{\partial y}\frac{\partial M(x)}{\partial x}

\frac{\partial M(x)}{\partial x}是是事情变的复杂起来的地方。对应模型输入的偏导数输出,如果我们试着用导数链规则(chain rule)扩展这个式子,我们会涉及到很多的局部偏导数的计算,比如模型中众多的每个层的学习参数导数,激活函数的导数,和每次数学变换的导数。每个这样的偏导数的完整表达式是通过计算图的每个可能路径的局部梯度的乘积之和,该计算图以我们试图测量其梯度的变量结束。

我们尤其感兴趣的事学习权重参数的梯度,他们告诉我们改变那个方向的权重可以使损失函数(Loss Function)接近于零。

因为这种局部导数的数量随着神经网络的深度成指数级增长,因此计算他们的复杂度也在增大。 这就是Autograd的价值所在:它能跟踪每次计算。每次在你的PyTorch模型计算的tensor都承载着它的输入Tensor的历史和用于创建它的函数信息。结合作用于Tensor的PyTorch的函数都会有它们自己计算导数的实现,这就极大地加快了为了学习计算局部导数的速度。

Autograd应用的例子

对简单函数参数求导

这个例子是单输入单输出的,比较简单我们求解y=2x^2+bx的导数,首先我们声明变量xb 并且指定x其属性require_grad=True以告诉系统自动计算其导数。y=2x^2+b从分析得知公式的对x求导公式是\frac{dy}{dx}=4x

import torch
import torch.nn as nn

x=torch.tensor(2,dtype=torch.float,requires_grad=True)
b=torch.tensor(1)
y=2*x**2+b
y.backward()
print(y)
print(x.grad)

对应的输出是:

tensor(9., grad_fn=<AddBackward0>)
tensor(8.)

其中,x赋值是标量2,所以公式计算结果y=9,其对应的导数\frac{dy}{dx}=4x=4*2=8,导数的计算是在回溯的时候自动计算出来的。 这个结果和我们通过分析方法求解导数的计算结果一致,注意叶子节点x在我们声明其时指定属性requires_grad=True是告诉程序在回溯计算时自动保留导数。这个例子较为简单,让我们看一个稍微复杂的例子。

多维线性函数梯度计算

这个稍微复杂的梯度计算,输入是向量,参数是多维和输出是标量的梯度计算。和上个例子一样,这个是对参数的梯度计算,主要是输入\mathbf{x}确定情况下,参数\mathbf{w}\mathbf{b}对输出的影响率。完整的公式y=\sum{(\mathbf{Wx+b})}.公式中w,\mathbf{x}\mathbf{b}分别为参数矩阵,输入向量和偏置向量。以下代码是借助于Torch的Autograd机制,获取对\mathbf{w}\mathbf{b}梯度。

标量输出对矩阵参数的偏导(Scalar-by-matrix)

如何计算输出y对参数矩阵\mathbf{W}偏导数,矩阵\mathbf{W}$$为3x4$矩阵,如下所示。

\mathbf{W}=\begin{Bmatrix} w_{00}& w_{01} & w_{02} & w_{03} \\ w_{10}& w_{11} & w_{12} & w_{13}\\ w_{20}& w_{21} & w_{22} & w_{23}\\ \end{Bmatrix}
\mathbf{W}矩阵求偏导,得到梯度矩阵。 其中向量\mathbf{x}=[x_0,x_1,x_2,x_3]^T\mathbf{b}=[b_0,b_1,b_2]^T

\nabla \mathbf{W}=\frac{\partial y}{\partial \mathbf{W}} =\begin{Bmatrix} \frac{\partial y}{\partial w_{00}}& \frac{\partial y}{\partial w_{01}} & \frac{\partial y}{\partial w_{02}} &\frac{\partial y}{\partial w_{03}} \\ \frac{\partial y}{\partial w_{10}}& \frac{\partial y}{\partial w_{11}} & \frac{\partial y}{\partial w_{12}} &\frac{\partial y}{\partial w_{13}} \\ \frac{\partial y}{\partial w_{20}}& \frac{\partial y}{\partial w_{21}} & \frac{\partial y}{\partial w_{22}} &\frac{\partial y}{\partial w_{23}} \\ \end{Bmatrix}=\begin{Bmatrix} x_{0}& x_{1} & x_{2} & x_{3} \\ x_{0}& x_{1} & x_{2} & x_{3} \\ x_{0}& x_{1} & x_{2} & x_{3} \\ \end{Bmatrix}

标量输出对矩阵参数的偏导(Scalar-by-vector)

计算输出y对向量\mathbf{b}的偏导数是比较简单的,如下公式。
\nabla \mathbf{b}=\frac{\partial y}{\partial \mathbf{b}}=[\frac{\partial y}{\partial b_0},\frac{\partial y}{\partial b_1},\frac{\partial y}{\partial b_2}]^T=[1,1,1]^T

import torch
import torch.nn as nn

x=torch.tensor([3.0,2.0,4.0,5.0],dtype=torch.float,requires_grad=False)
W=torch.tensor([[1,2,3,4],[1,2,3,4],[1,2,3,4]],dtype=torch.float,requires_grad=True)
b=torch.tensor([4.0,5.0,8.0],dtype=torch.float,requires_grad=True)  
output=torch.matmul(W,x)+b

y=output.sum()

print(f"the y grad is {output.grad_fn}")
print(y)
output.backward()
print(x.grad)
print(W.grad)
print(b.grad)

对应的输出:

the y grad is <AddBackward0 object at 0x110e30730>
tensor(134., grad_fn=<SumBackward0>)
None
tensor([[3., 2., 4., 5.],
        [3., 2., 4., 5.],
        [3., 2., 4., 5.]])
tensor([1., 1., 1.])

公式y=\sum{(\mathbf{Wx+b})}, 注意到\mathbf{x}的属性required_grad=False的设置,表示不必计算对应x的导数,但其他的两个\mathbf{W}\mathbf{b}需要跟踪计算其导数。注意到\mathbf{x}的导数输出为None,响应了x的属性required_grad=Flase的设置,不计算其导数。而\mathbf{W}\mathbf{b},则在定义变量时指定其属性required_grad=True在上面的程序中,输出结果中可以看到其对应的偏导数矩阵和偏导数向量,响应的了其设置。 可以看到计算分了两个阶段,一个是正向传播(forward)计算,一个是反向传播(backward)计算。正向传播有时也会称推理(reason),可以根据输入值得到输出结论。反向传播则是为计算导数或偏导数并为更新参数做准备。y.backward()函数就是用于回溯传播导数计算。

总结

本文介绍了PyTorch框架中的Autograd机制,和利用代码求解导数和偏导数的方法。这些自动化机制已经深嵌到PyTorch的框架中,极大帮助深度学习应用者设计自己的深度学习应用。在以后的文章里会介绍如何利用Autograd机制和PyTorch其他的一些机制,设计自己的深度学习应用。

参考文献

  1. The Fundamentals of Autograd
  2. Gentle Introduction to torch.autograd
  3. Matrix Calculus
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容