Python代碼中偏函數(shù)的使用詳解
技術(shù)背景
在數(shù)學(xué)中我們都學(xué)過偏導(dǎo)數(shù)∂f(x,y)/∂x,而這里我們提到的偏函數(shù),指的是f(y)(x)。也就是說,在代碼實現(xiàn)的過程中,雖然我們實現(xiàn)的一個函數(shù)可能帶有很多個變量,但是可以用偏函數(shù)的形式把其中一些不需要拆分和變化的變量轉(zhuǎn)變?yōu)楣逃凶兞?。比較典型的兩個例子是計算偏導(dǎo)數(shù)和多進程優(yōu)化。雖然大部分支持自動微分的框架都有相應(yīng)的支持偏導(dǎo)數(shù)的接口,多進程操作中也可以指定額外的args,但是這些自帶的方法在形式上都是比較tricky的,感覺并不如使用偏函數(shù)優(yōu)雅和簡潔。這里我們主要介紹python中可能會用到的偏函數(shù)功能--partial
。
Partial簡單案例
我們先來一個最簡單的乘法函數(shù)f(x,y)=xy。假如說我們想得到該函數(shù)關(guān)于y的偏導(dǎo)數(shù),注意,這里y是第二個輸入的變量,不是第一個位置,一般自動微分框架都默認都第一個位置的變量計算偏導(dǎo)數(shù)。相關(guān)代碼實現(xiàn)如下所示:
from functools import partial def mul(x, y): print (locals()) return x * y x = 2 y = 3 res_0 = mul(x, y) partial_mul = partial(mul, x=x) res_1 = partial_mul(y=3) print ('The result is: {}'.format(res_0)) print ('The result is: {}'.format(res_1))
這段代碼的運行結(jié)果為:
{'x': 2, 'y': 3}
{'x': 2, 'y': 3}
The result is: 6
The result is: 6
我們現(xiàn)在來分析一下上面這個案例中所體現(xiàn)的信息:
- 在使用partial函數(shù)時使用的是關(guān)鍵字參數(shù),即時原本的變量不是一個關(guān)鍵字參數(shù),而是一個位置參數(shù)。
- 雖然得到的偏函數(shù)partial_mul運行的方式跟函數(shù)一致,但其實它是一個partial的對象類型。
- 在生成partial_mul對象時已經(jīng)執(zhí)行過一遍函數(shù),因此函數(shù)中的打印語句被打印了兩次。
- 偏函數(shù)的計算結(jié)果肯定是跟原函數(shù)保持一致的,但是在一些特殊場景下,我們可能會用到這種單變量的偏函數(shù)。
Concurrent多核并行場景
現(xiàn)在我們稍微修改一下上面的案例,我們要用concurrent這個并行工具去分別執(zhí)行上述乘法任務(wù),同時輸入的x也變成了一個多維的數(shù)組。然后為了驗證并行算法,這里每計算一次元素乘法,我們都用time.sleep
方法讓進程休眠2秒鐘時間。由于此時的參數(shù)y還是一個標量,但是每次乘法計算我們都需要輸入這個標量,因此我們直接將其封裝到一個partial偏函數(shù)中,使得函數(shù)變成:f(x,y)=f(y)(x)=P(x),然后對x這個入?yún)⑦M行并行化操作:
import numpy as np import concurrent.futures from functools import partial import time # 定義休眠函數(shù) def mul(x, y): time.sleep(2) return x * y # 定義入?yún)? x = np.array([1, 2, 3], np.float32) y = 3. # 有阻塞計算 time_0 = time.time() res_0 = [] for _x in x: res_0.append(mul(_x, y)) res_0 = np.array(res_0, np.float32) time_1 = time.time() # 并行計算 partial_mul = partial(mul, y=y) time_2 = time.time() with concurrent.futures.ProcessPoolExecutor(max_workers=x.shape[0]) as executor: res = executor.map(partial_mul, x) res_1 = np.array(list(res), np.float32) time_3 = time.time() print ('The result is: {}, and for loop time cost is: {}s'.format(res_0, time_1 - time_0)) print ('The result is: {}, and concurrent time cost is : {}s'.format(res_1, time_3 - time_2))
如果有感興趣的童鞋也可以去嘗試一下,在這種場景下的并行運算,如果參量y不是一個可迭代式的變量,是無法用zip壓縮傳到map函數(shù)中去的。上述代碼的運行結(jié)果如下:
The result is: [3. 6. 9.], and for loop time cost is: 6.005392789840698s
The result is: [3. 6. 9.], and concurrent time cost is : 2.0451698303222656s
這個計算時長其實就約等于休眠時長,因為這里我們開啟了3個進程來進行休眠,因此并行時長是2s。
Jax自動微分場景
這里我們用Jax的自動微分框架做一個示例,沒有安裝Jax和Jaxlib的想運行需要自行安裝相關(guān)軟件。雖然在Jax的grad函數(shù)中,支持argnums這樣的參數(shù)配置,但從代碼層面角度來說,總是顯得可讀性并不好。正常情況下我們算偏導(dǎo)數(shù)∂f(x,y)/∂x其實更合理的表述應(yīng)該是∂P(x)/∂x。而如果按照Jax這種寫法,更像是從[∂f(x,y)/∂x,∂f(x,y)/∂x]兩個元素中取了第一個元素。當(dāng)然,這只是表述上的問題,也是我個人的理解,其實并不影響程序的正確性。這里使用partial偏函數(shù)的相關(guān)案例如下所示:
from functools import partial from jax import grad from jax import numpy as jnp # Jax要求grad函數(shù)輸出結(jié)果為標量,所以要加一項求和 def mul(x, y): f = x * y return f.sum() # 定義輸入變量 x = jnp.array([1, 2, 3], jnp.float32) y = 3. # 定義偏函數(shù)和對應(yīng)偏導(dǎo)數(shù) partial_mul = partial(mul, y=y) grad_mul = grad(partial_mul) print (grad_mul(x))
執(zhí)行結(jié)果如下:
[3. 3. 3.]
總結(jié)概要
本文介紹了在Python中使用偏函數(shù)partial的方法,并且介紹了兩個使用partial函數(shù)的案例,分別是concurrent并行場景和基于jax的自動微分場景。在這些相關(guān)的場景下,我們用partial函數(shù)更多時候可以使得代碼的可讀性更好,在性能上其實并沒有什么提升。如果不想使用partial函數(shù),類似的功能也可以使用參考鏈接中所介紹的方法,實現(xiàn)一個裝飾器,也可以做到一樣的功能。
到此這篇關(guān)于Python代碼中偏函數(shù)的使用詳解的文章就介紹到這了,更多相關(guān)Python偏函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python字符串函數(shù)strip()原理及用法詳解
這篇文章主要介紹了Python字符串函數(shù)strip()原理及用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07python 字典item與iteritems的區(qū)別詳解
這篇文章主要介紹了python 字典item與iteritems的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04python中for循環(huán)輸出列表索引與對應(yīng)的值方法
今天小編就為大家分享一篇python中for循環(huán)輸出列表索引與對應(yīng)的值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11如何實現(xiàn)Django Rest framework版本控制
這篇文章主要介紹了如何實現(xiàn)Django Rest framework版本控制,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07