【Pytorch神经网络基础理论篇】 06 自动求导+导数与微分
?
0.導(dǎo)數(shù)和微分
0.1逼近法
在2500年前,古希臘人把一個多邊形分成三角形,并把它們的面積相加,才找到計算多邊形面積的方法。 為了求出曲線形狀(比如圓)的面積,古希臘人在這樣的形狀上刻內(nèi)接多邊形,內(nèi)接多邊形的等長邊越多,就越接近圓。這個過程也被稱為逼近法。
在深度學(xué)習(xí)中,我們“訓(xùn)練”模型,不斷更新它們,使它們在看到越來越多的數(shù)據(jù)時變得越來越好。通常情況下,變得更好意味著最小化一個損失函數(shù)(loss function),即一個衡量“我們的模型有多糟糕”這個問題的分數(shù)。這個問題比看上去要微妙得多。
最終,我們真正關(guān)心的是生成一個能夠在我們從未見過的數(shù)據(jù)上表現(xiàn)良好的模型。但我們只能將模型與我們實際能看到的數(shù)據(jù)相擬合。
因此,我們可以將擬合模型的任務(wù)分解為兩個關(guān)鍵問題:
(1)優(yōu)化(optimization):用模型擬合觀測數(shù)據(jù)的過程;
(2)泛化(generalization):數(shù)學(xué)原理和實踐者的智慧,能夠指導(dǎo)我們生成出有效性超出用于訓(xùn)練的數(shù)據(jù)集本身的模型。
0.2 導(dǎo)數(shù)和微分
在深度學(xué)習(xí)中,我們通常選擇對于模型參數(shù)可微的損失函數(shù)。這意味著,對于每個參數(shù), 如果我們把這個參數(shù)增加或減少一個無窮小的量,我們可以知道損失會以多快的速度增加或減少。
?0.2.1 簡單模擬求導(dǎo)過程
%matplotlib inline import numpy as np from IPython import display from d2l import torch as d2ldef f(x):return 3 * x ** 2 - 4 * x def numerical_lim(f, x, h):return (f(x + h) - f(x)) / hh = 0.1 for i in range(5):print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}')h *= 0.1 h=0.10000, numerical limit=2.30000 h=0.01000, numerical limit=2.03000 h=0.00100, numerical limit=2.00300 h=0.00010, numerical limit=2.00030 h=0.00001, numerical limit=2.000031.自動求導(dǎo)
?
?
?
?
?
?
?
?
?
?
?
?
?2.自動求導(dǎo)實現(xiàn)
2.1ppt截圖
?
?
?
?
??
?
2.2 代碼實現(xiàn)
import torch print('1.自動梯度計算') x = torch.arange(4.0, requires_grad=True) # 1.將梯度附加到想要對其計算偏導(dǎo)數(shù)的變量 print('x:', x) print('x.grad:', x.grad) 1.自動梯度計算 x: tensor([0., 1., 2., 3.], requires_grad=True) x.grad: None y = 2 * torch.dot(x, x) # 2.記錄目標值的計算 對應(yīng)位置相乘再相加 print('y:', y) y: tensor(28., grad_fn=<MulBackward0>) y.backward() # 3.y=2*x*x 執(zhí)行它的反向傳播函數(shù) print('x.grad:', x.grad) # 4.訪問得到的梯度 print('x.grad == 4*x:', x.grad == 4 * x) x.grad: tensor([ 0., 4., 8., 12.]) x.grad == 4*x: tensor([True, True, True, True]) ## 計算另一個函數(shù) x.grad.zero_() #梯度清零 print('x:', x) y = x.sum() print('y:', y) y.backward() print('x.grad:', x.grad) x: tensor([0., 1., 2., 3.], requires_grad=True) y: tensor(6., grad_fn=<SumBackward0>) x.grad: tensor([1., 1., 1., 1.]) # 非標量變量的反向傳播 x.grad.zero_() print('x:', x) y = x * x y.sum().backward() print('x.grad:', x.grad) x: tensor([0., 1., 2., 3.], requires_grad=True) x.grad: tensor([0., 2., 4., 6.]) def f(a):b = a * 2print(b.norm())print("開始循環(huán):")while b.norm() < 1000: # 求L2范數(shù):元素平方和的平方根b = b * 2print(b)print("開始判斷")if b.sum() > 0:c = belse:c = 100 * breturn c print('2.Python控制流的梯度計算') a = torch.tensor(2.0) # 初始化變量 print(a) a.requires_grad_(True) # 1.將梯度賦給想要對其求偏導(dǎo)數(shù)的變量 print('a:', a) d = f(a) # 2.記錄目標函數(shù) print('d:', d) d.backward() # 3.執(zhí)行目標函數(shù)的反向傳播函數(shù) print('a.grad:', a.grad) # 4.獲取梯度 2.Python控制流的梯度計算 tensor(2.) a: tensor(2., requires_grad=True) tensor(4., grad_fn=<CopyBackwards>) 開始循環(huán): tensor(8., grad_fn=<MulBackward0>) tensor(16., grad_fn=<MulBackward0>) tensor(32., grad_fn=<MulBackward0>) tensor(64., grad_fn=<MulBackward0>) tensor(128., grad_fn=<MulBackward0>) tensor(256., grad_fn=<MulBackward0>) tensor(512., grad_fn=<MulBackward0>) tensor(1024., grad_fn=<MulBackward0>) 開始判斷 d: tensor(1024., grad_fn=<MulBackward0>) a.grad: tensor(512.)QA
1.顯示構(gòu)造:先將整個計算寫出來,再去寫入?yún)?shù)值。
2.在深度網(wǎng)絡(luò)求梯度的時候,需要正向算一遍(將y的函數(shù)值算出來),反向算一遍。
3.pytorch默認累計梯度的原因:累計梯度的情況主要是在批量的情況下,Pytorch對于內(nèi)存的管理不夠好,批量計算的內(nèi)存大小較大,因此將其分開計算,故需要默認累計梯度。
4.為什么深度學(xué)習(xí)中一般都去標量求導(dǎo),而不是對矩陣和向量,如果我的loss是包含向量或矩陣的情況下,在求導(dǎo)之前是否需要將其變成標量的形式?
答:loss通常是一個標量
5.多個loss分別反向的情況下,需要累計梯度
6.為什么獲取grad前需要backward?
因為backward占用內(nèi)存較大
7.pytorch上可以實現(xiàn)矢量求導(dǎo)嗎?
可以,高階求導(dǎo),但是通常需要優(yōu)化算法。
在PyTorch中data.norm()是含義_Escape the bug的博客-CSDN博客https://blog.csdn.net/jnbfknasf113/article/details/110141537https://blog.csdn.net/jnbfknasf113/article/details/110141537
?
總結(jié)
以上是生活随笔為你收集整理的【Pytorch神经网络基础理论篇】 06 自动求导+导数与微分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Pytorch神经网络实战案例】22
- 下一篇: 【Pytorch神经网络理论篇】 02