網站首頁 編程語言 正文
1 自動微分
我們在《數值分析》課程中已經學過許多經典的數值微分方法。許多經典的數值微分算法非常快,因為它們只需要計算差商。然而,他們的主要缺點在于他們是數值的,這意味著有限的算術精度和不精確的函數求值,而這些都從根本上限制了求解結果的質量。因此。充滿噪聲的、復雜多變的函數很難得到精準的數值微分。
自動微分技術(稱為“automatic differentiation, autodiff”)是介于符號微分和數值微分的一種技術,它是在計算效率和計算精度之間的一種折衷。自動微分不受任何離散化算法誤差的約束,它充分利用了微分的鏈式法則和其他關于導數的性質來準確地計算它們。
2 前向自動微分
我們先來計算簡單的前向自動微分。假設我們有兩個變量u和v,使用浮點數存儲。我們將變量u′=du/dt和v′=dv/dt和這些變量一起存儲,這里tt是獨立的變量。在一些程序設計語言(如Python)中,我們可以選擇定義一種新的數據類型來存儲[u,u′]和[v,v′]這類數對。我們可以在這些數對上定義一種代數運算,這些代數運算編碼了一些經典的操作:
在進行前向自動微分之前,我們需要先將計算f(t)所產生的操作序列表示為計算圖。接著,采用自底向上的遞推算法的思想,從做為遞推起點的數對t≡[t0,1](因為dt/dt=1)開始,我們能夠按照我們上述編碼規則同時對函數f(t)和它的導數f′(t)進行求值。我們在編程語言中可以選擇令數對重載運算符,這樣額外的求導數運算就可以對用戶透明地執行了。
例1?比如,對于函數f(x)=exp?(x2?x)/x,想要依次計算dyi/dx(這里yi為所有計算中間項)。則我們先從x開始將表達式分解為計算圖:
然后前向遞推地按照我們之前所述的編碼規則來進行求導
注意鏈式法則(chain rule)告訴我們:
(f(g(x)))′=f′(g(x))?g′(x)
所以我們對
yk=g(yi)
有
y′k=g′(yi)?yi′
事實上,我們也能夠處理有多個輸入的函數g:
k=g(yi,?,yj)
多元微分鏈式法則如下:
比如,對于
我們有
下面展示了一個對二元函數模擬前向自動微分的過程。
例2?設(x1,x2)=x1?exp?(x2)?x1,模擬前向微分過程。
接下來我們看如何用Python代碼來實現單變量函數的前向自動微分過程。為了簡便起見,我們下面只編碼了幾個常用的求導規則。
import math
class Var:
def __init__(self, val, deriv=1.0):
self.val = val
self.deriv = deriv
def __add__(self, other):
if isinstance(other, Var):
val = self.val + other.val
deriv = self.deriv + other.deriv
else:
val = self.val + other
deriv = self.deriv
return Var(val, deriv)
def __radd__(self, other):
return self + other
def __sub__(self, other):
if isinstance(other, Var):
val = self.val - other.val
deriv = self.deriv - other.deriv
else:
val = self.val - other
deriv = self.deriv
return Var(val, deriv)
def __rsub__(self, other):
val = other - self.val
deriv = - self.deriv
return Var(val, deriv)
def __mul__(self, other):
if isinstance(other, Var):
val = self.val * other.val
deriv = self.val * other.deriv + self.deriv * other.val
else:
val = self.val * other
deriv = self.deriv * other
return Var(val, deriv)
def __rmul__(self, other):
return self * other
def __truediv__(self, other):
if isinstance(other, Var):
val = self.val / other.val
deriv = (self.deriv * other.val - self.val * other.deriv)/other.val**2
else:
val = self.val / other
deriv = self.deriv / other
return Var(val, deriv)
def __rtruediv__(self, other):
val = other / self.val
deriv = other * 1/self.val**2
return Var(val, deriv)
def __repr__(self):
return "value: {}\t gradient: {}".format(self.val, self.deriv)
def exp(f: Var):
return Var(math.exp(f.val), math.exp(f.val) * f.deriv)
例如,我們若嘗試計算函數f(x)=exp?(x2?x)/x在x=2.0處的導數f′(2.0)如下:
fx = lambda x: exp(x*x - x)/x
df = fx(Var(2.0))
print(df)
打印輸出:
value: 3.694528049465325 ? ? ? ? deriv: 9.236320123663312
可見,前向過程完成計算得到f(2.0)≈3.69, f′(2.0)≈9.24。
3 反向自動微分
我們前面介紹的前向自動微分方法在計算y=f(t)的時候并行地計算f′(t)。接下來我們介紹一種“反向”自動微分方法,相比上一種的方法它僅需要更少的函數求值,不過需要以更多的內存消耗和更復雜的實現做為代價。
同樣,這個技術需要先將計算f(t)所產生的操作序列表示為計算圖。不過,與之前的從dt/dt=1開始,然后往dy/dt方向計算不同,反向自動求導算法從dy/dy=1開始并且按與之前同樣的規則往反方向計算,一步步地將分母替換為dt。反向自動微分可以避免不必要的計算,特別是當y是一個多元函數的時候。例如,對f(t1,t2)=f1(t1)+f2(t2),反向自動微分并不需要計算f1關于t2的微分或f2關于t1的微分。
例3?設f(x1,x2)=x1?exp(x2)?x1,模擬反向自動微分過程。
可見若采用反向自動微分,我們需要存儲計算過程中的所有東西,故內存的使用量會和時間成正比。不過,在現有的深度學習框架中,對反向自動微分的實現進行了進一步優化,我們會在深度學習專題文章中再進行詳述。
4 總結
自動微分被廣泛認為是一種未被充分重視的數值技術, 它可以以盡量小的執行代價來產生函數的精確導數。它在軟件需要計算導數或Hessian來運行優化算法時顯得格外有價值,從而避免每次目標函數改變時都去重新手動計算導數。當然,做為其便捷性的代價,自動微分也會帶來計算的效率問題,因為在實際工作中自動微分方法并不會去化簡表達式,而是直接應用最顯式的編碼規則。
原文鏈接:https://www.cnblogs.com/orion-orion/p/17010353.html
相關推薦
- 2023-02-04 Android自定義view實現雪花特效實例代碼_Android
- 2022-04-18 uniapp 獲取元素距離頂部的距離,實現頁面滾動元素消失后懸浮在底部的效果
- 2022-11-13 Elasticsearch6.2服務器升配后的bug(避坑指南)_服務器其它
- 2022-04-14 CMake編譯中的庫文件和頭文件鏈接你了解嗎_C 語言
- 2022-09-20 linux?shell字符串截取的詳細總結(實用!)_linux shell
- 2022-11-29 C#交換兩個變量值的幾種方法總結_C#教程
- 2022-01-10 cookie localstorage sessionstorage的區別
- 2022-12-31 Android入門之bindService的用法詳解_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支