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