tensor 自動求導(dǎo)

自動求導(dǎo)(autograd)

直接用張量定義的運算時無法求導(dǎo)的,自動求導(dǎo)功能由 autograde 模塊提供贿讹。

這小結(jié)主要包括:

  • 計算圖(computation graph)

  • autograde.Variable

  • backward( )

先來舉一個簡單的例子:實現(xiàn)
f(x) = x^2 - x
并計算其在 x = 3 處的導(dǎo)數(shù)够掠。因為

f'(x) = 2 x - 1,

所以\begin{align}f(3)=6, \quad f'(3)=5\end{align}

import torch
from torch.autograd import Variable
# 定義變量x
x = Variable(torch.Tensor([3]), requires_grad = True)
# 定義函數(shù)
f = x*x - x     # 向前構(gòu)建計算圖
# 求導(dǎo)數(shù)
f.backward()    # 向后傳播求導(dǎo)數(shù)
print(x)
print('f(3)=', f.data[0])
print('f\'(3)=', x.grad.data[0])
tensor([3.], requires_grad=True)
f(3)= tensor(6.)
f'(3)= tensor(5.)

上面的例子演示了一個典型的自動求導(dǎo)的過程疯潭。

首先定義了 Variable 生產(chǎn)變量,x = Variable(value,requires_grad = True)

接著向前傳播計算函數(shù)(同時構(gòu)建計算圖): y = f(x)

反向傳播計算導(dǎo)數(shù): y.backward(), 導(dǎo)數(shù) dy/dx 自動儲存在 x.grad

下面我們來看一下每一步在做什么哭廉。

Variable

Variable 類封裝了 Tensor 類相叁,其支持幾乎所有 Tensor 支持的運算增淹。和 Tensor 不同基于 Variable 的運算是會同時構(gòu)建計算圖。這個計算圖能幫助我們自動求導(dǎo)埠通。Variable 主要包含三個部分:

autograde.Variable:

  • data

  • grade

  • grad_fn

  1. Variable.data: 儲存 Variable 的值端辱,有以下兩個可選參數(shù):

    • require_grad (boolean): 是否需要對該變量進(jìn)行求導(dǎo)
    • volatile (boolean): 為 True 時意味著構(gòu)建在該 variable 之上的圖都不會求導(dǎo),且 volatile 的優(yōu)先級高于 require_grade
value = torch.Tensor([1,2])
x = Variable(value, requires_grad = True)
print(x.data is value) # 檢查x.data 與 value 是否共享內(nèi)存
False
  1. Variable.grade_fn: 存儲該 Variable 是通過什么樣的基本運算得到荣病,它將被用于 backward 的時候求導(dǎo)渗柿。譬如 y = x+x,那么 grad_fn 記錄的就是 y 由 x 和 x 做加法得到颊亮。根據(jù)鏈?zhǔn)椒▌t陨溅,有了 dy ,那么 grad_fn 就會告訴我們?nèi)绾吻蟪?dx 雹有。
y = x + x
z = x**3
print(y.grad_fn)
print(z.grad_fn)
<AddBackward0 object at 0x000001B529EE0CF8>
<PowBackward0 object at 0x000001B529EE06D8>

葉子節(jié)點(leaf node):由用戶自己創(chuàng)建霸奕,不依賴于其他變量的節(jié)點质帅。葉子節(jié)點的 grad_fn 為 None临梗。

# check whether is leaf node
x.is_leaf,y.is_leaf
(True, False)
# 查看該變量的反向傳播函數(shù)
x.grad_fn,y.grad_fn
(None, <AddBackward0 at 0x1b529f04048>)
# next_functions 保存 grad_fn 的輸入,y 中兩個節(jié)點均為葉子節(jié)點票彪,需要求導(dǎo),梯度是累加的摇零。
y.grad_fn.next_functions
((<AccumulateGrad at 0x1b529f040f0>, 0),
 (<AccumulateGrad at 0x1b529f040f0>, 0))
  1. Variable.grad: 存儲導(dǎo)數(shù)。注意:
    • Variable.grad 本身還是個 Variable
    • 一個變量 x 可能會屬于多個計算圖噪服,每次調(diào)用backward(), 導(dǎo)數(shù)是累加的仇味。所以如果不想導(dǎo)數(shù)累加,運行backward()之前需要用x.grad.data.zero_()對導(dǎo)數(shù)清零嬉愧。
    • 在計算 x 的導(dǎo)數(shù)時揽惹,導(dǎo)數(shù)值會在向前的過程中形成 buffer ,在計算完成后會自動清空闪金。若是需要多次反向傳播哎垦,需要使用backward(retain_graph = True)來保留這些 buffer 漏设。
x = Variable(torch.Tensor([1]),requires_grad = True)
y = x + x       # 計算圖1
z = x**3       # 計算圖2

# 第一次求導(dǎo)
y.backward()
print(x.grad.data)   # dy/dx = 2

z.backward()
print(x.grad.data)  # dy/dx + dz/dx = 2+3 = 5
tensor([2.])
tensor([5.])
x = Variable(torch.Tensor([1]),requires_grad = True)
y = x + x       # 計算圖1
z = x**3       # 計算圖2

# 第一次求導(dǎo)
y.backward()
print(x.grad.data)   # dy/dx = 2

x.grad.data.zero_()
z.backward()
print(x.grad.data)  # dy/dx + dz/dx = 2+3 = 5
tensor([2.])
tensor([3.])

高階導(dǎo)數(shù)

在很多實際應(yīng)用中我們需要求高階導(dǎo)數(shù)。在實際大規(guī)模問題中犬性,直接二階導(dǎo)數(shù),是 Hessian 矩陣鹤耍,而這個矩陣往往是非常巨大的惰蜜,計算起來代價是不能接受的格侯。因此 PyTorch 提供的高階導(dǎo)數(shù)功能并不是直接求二階導(dǎo)數(shù),而是提供對梯度的函數(shù)求導(dǎo)撑教,也就是說我們可以做如下運算:
\nabla_x G(\nabla f(x))亿卤。
下面我們舉例子說明:

f(x_1,x_2,x_3) = \sum_{i=1}^3 x_i^2\\

x = Variable(torch.Tensor([1,2,3]),requires_grad = True)
y = x*x
f = y.sum()  # y 是一個向量
df = torch.autograd.grad(f, x, create_graph = True) # create_graph = True 會對反向傳播構(gòu)建計算圖排吴,用于計算二階導(dǎo)數(shù)
print(df[0])
tensor([2., 4., 6.], grad_fn=<AddBackward0>)

這里我們要掌握函數(shù)torch.autograd.grad(y,x,creat_graph = False), 該函數(shù)直接返回導(dǎo)數(shù) dy/dx. 不同于backward(), 它并不會把導(dǎo)數(shù)累加到 x.grad 上面肛冶。另外creat_graph 參數(shù)表示反向傳播的時候是否構(gòu)建新計算圖珊肃,如果需要計算二階導(dǎo)數(shù),其值必須為True延蟹;否則沒法對導(dǎo)數(shù)繼續(xù)求導(dǎo)阱飘。下面讓我們完成導(dǎo)數(shù)的導(dǎo)數(shù):

G(x_1,x_2,x_3) = \sum_{i=1}^3 \left(\frac{\partial f}{\partial x_i}\right)^2 = \sum_{i=1}^3 4x_i^2\\ \frac{\partial G}{\partial x_i} = 8 x_i \quad \forall i=1,2,3

G = df[0].pow(2).sum()
dG = torch.autograd.grad(G,x)
print(dG[0])
tensor([ 8., 16., 24.])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末高帖,一起剝皮案震驚了整個濱河市散址,隨后出現(xiàn)的幾起案子预麸,更是在濱河造成了極大的恐慌吏祸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诱渤,居然都是意外死亡递胧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門祝闻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遗菠,“玉大人,你說我怎么就攤上這事辙纬。” “怎么了蓖谢?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵譬涡,是天一觀的道長。 經(jīng)常有香客問我盯腌,道長陨瘩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮蒿囤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己恒傻,他們只是感情好建邓,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沸手,像睡著了一般注簿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诡渴,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音惑灵,去河邊找鬼眼耀。 笑死,一個胖子當(dāng)著我的面吹牛畔塔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播把敢,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼谅辣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桑阶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤割择,失蹤者是張志新(化名)和其女友劉穎萎河,沒想到半個月后蕉饼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玛歌,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡支子,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叹侄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡圈膏,死狀恐怖篙骡,靈堂內(nèi)的尸體忽然破棺而出糯俗,到底是詐尸還是另有隱情,我是刑警寧澤睦擂,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布顿仇,位于F島的核電站,受9級特大地震影響臼闻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜述呐,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一乓搬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧进肯,春花似錦、人聲如沸江掩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至差油,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蓄喇,已是汗流浹背交掏。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留钱骂,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓见秽,卻偏偏與公主長得像讨盒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子返顺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容