Python Numba CPU下加速

      網(wǎng)友投稿 992 2025-03-31

      Python代碼加速

      主要考慮代碼優(yōu)化加速,而非代碼邏輯優(yōu)化。

      Python代碼直接運(yùn)行GPU是不行的,需要一定的改變,Numba是一個(gè)接口,不過本文主要針對CPU下的Python代碼加速。

      Python解釋器工作原理

      Python文件執(zhí)行過程

      .py文件通過解釋器轉(zhuǎn)化為虛擬機(jī)可以執(zhí)行的字節(jié)碼(.pyc);

      字節(jié)碼在虛擬機(jī)上執(zhí)行,得到結(jié)果;

      字節(jié)碼是一種只能運(yùn)行在虛擬機(jī)上的文件,默認(rèn)后綴.pyc,Python生成.pyc之后一般放在內(nèi)存中繼續(xù)使用,并不是每次都將.pyc文件保存到磁盤上。

      虛擬機(jī)是基于硬件和操作系統(tǒng)的。

      .pyc字節(jié)碼通過Python虛擬機(jī)與硬件交互,就是說虛擬機(jī)的存在導(dǎo)致程序與硬件之間增加了中間層。效率自然被拖后。

      JIT(Just-In-Time)

      JIT技術(shù)中,JIT編譯器將Python源代碼.py直接編譯成機(jī)器可以執(zhí)行的機(jī)器語言(機(jī)器碼),就可以直接在CPU等硬件上運(yùn)行。

      這樣,JIT就跳過了原來的虛擬機(jī),執(zhí)行速度幾乎與用C語言編程速度無差別。

      Numba庫

      Numba是Anaconda公司開發(fā)的針對Python的開源JIT編譯器,用于提供Python版CPU和GPU編程,速度比原生Python快數(shù)十倍。一、安裝Numba

      pip install numba

      # 或者

      conda install numba

      二、使用方法:裝飾器

      from numba import jit

      import numpy as np

      SIZE = 2000

      x = np.random.random((SIZE, SIZE))

      """

      給定n*n矩陣,對矩陣每個(gè)元素計(jì)算tanh值,然后求和。

      因?yàn)橐h(huán)矩陣中的每個(gè)元素,計(jì)算復(fù)雜度為 n*n。

      """

      @jit # numba的使用方法

      def jit_tan_sum(a): ? # 函數(shù)在被調(diào)用時(shí)編譯成機(jī)器語言

      tan_sum = 0

      for i in range(SIZE): ? # Numba 支持循環(huán)

      for j in range(SIZE):

      tan_sum += np.tanh(a[i, j]) ? # Numba 支持絕大多數(shù)NumPy函數(shù)

      return tan_sum

      print(jit_tan_sum(x))

      如代碼所示,只是在函數(shù)上加一個(gè)裝飾器@jit,就可以將運(yùn)行速度提升20多倍。

      @jit裝飾器的本質(zhì),是將函數(shù)編譯為機(jī)器碼,省掉虛擬機(jī)環(huán)節(jié),提升速度。

      三、Numba的使用場景總結(jié)

      numba目前只支持Python原生函數(shù)和部分Numpy函數(shù),其他場景下無效。

      from numba import jit

      import pandas as pd

      x = {'a': [1, 2, 3], 'b': [20, 30, 40]}

      @jit

      def use_pandas(a): # Function will not benefit from Numba jit

      df = pd.DataFrame.from_dict(a) # Numba doesn't know about pd.DataFrame

      df += 1 ? ? ? ? ? ? ? ? ? ? ? ?# Numba doesn't understand what this is

      return df.cov() ? ? ? ? ? ? ? ?# or this!

      print(use_pandas(x))

      上述代碼中使用了Pandas,而Pandas并不是原生代碼,而是更高層次的封裝,Numba不能理解pandas內(nèi)部在做什么,所以無法對其加速。

      而一些常用的機(jī)器學(xué)習(xí)框架,比如scikit-learn, tensorflow, pyrorch等,已經(jīng)做了大量的優(yōu)化,不適合再使用Numba做加速。

      可以簡單總結(jié)為,Numba不支持:

      pandas

      scikit-learn, tensorflow, pyrorch

      Python Numba CPU下加速

      try…except 異常處理

      with 語句

      yield from

      四、Numba具體使用過程

      Numba有兩種模式:

      @jit:object模式:上圖左側(cè)

      Numba的@jit裝飾器會嘗試優(yōu)化代碼,如果發(fā)現(xiàn)不支持(比如pandas等),那么Numba會繼續(xù)使用Python原來的方法去執(zhí)行該函數(shù)。

      @jit(nopython=True)或者@njit:nopython模式:上圖右側(cè)

      強(qiáng)制加速,不會進(jìn)入上圖左側(cè)流程,只進(jìn)行右側(cè)流程,如果編譯不成功,就拋出異常。

      實(shí)際使用中,一把推薦將代碼中計(jì)算密集的部分作為單獨(dú)的函數(shù)提出來,并使用nopython方法優(yōu)化,這樣可以保證能用到Numba加速;其余部分還是使用Python原生代碼。

      五、編譯開銷

      編譯源代碼需要一定的時(shí)間:

      C/C++等編譯型語言是提前把整個(gè)程序先編譯好,再執(zhí)行可執(zhí)行文件;

      Numba庫是懶編譯(Lazy Compilation)技術(shù);

      其中,懶編譯技術(shù)(Lazy Compilation)即

      在運(yùn)行過程中第一次發(fā)現(xiàn)源代碼中有@jit,才將該代碼塊編譯;

      同一個(gè)Numba函數(shù)多次調(diào)用,只需要編譯一次;

      總 時(shí) 間 = 編 譯 時(shí) 間 + 運(yùn) 行 時(shí) 間 總時(shí)間=編譯時(shí)間+運(yùn)行時(shí)間

      總時(shí)間=編譯時(shí)間+運(yùn)行時(shí)間

      from numba import jit

      import numpy as np

      import time

      SIZE = 2000

      x = np.random.random((SIZE, SIZE))

      """

      給定n*n矩陣,對矩陣每個(gè)元素計(jì)算tanh值,然后求和。

      因?yàn)橐h(huán)矩陣中的每個(gè)元素,計(jì)算復(fù)雜度為 n*n。

      """

      @jit

      def jit_tan_sum(a): ? # 函數(shù)在被調(diào)用時(shí)編譯成機(jī)器語言

      tan_sum = 0

      for i in range(SIZE): ? # Numba 支持循環(huán)

      for j in range(SIZE):

      tan_sum += np.tanh(a[i, j]) ? # Numba 支持絕大多數(shù)NumPy函數(shù)

      return tan_sum

      # 總時(shí)間 = 編譯時(shí)間 + 運(yùn)行時(shí)間

      start = time.time()

      jit_tan_sum(x)

      end = time.time()

      print("Elapsed (with compilation) = %s" % (end - start))

      # Numba將加速的代碼緩存下來

      # 總時(shí)間 = 運(yùn)行時(shí)間

      start = time.time()

      jit_tan_sum(x)

      end = time.time()

      print("Elapsed (after compilation) = %s" % (end - start))

      上述代碼中,兩次調(diào)用了Numba優(yōu)化函數(shù),第一次執(zhí)行時(shí)需要編譯,第二次就直接使用緩存的已經(jīng)編譯好的代碼,運(yùn)行時(shí)間大大縮短。

      六、確定輸入輸出類型Eager Compilation:節(jié)省編譯速度

      原生Python速度慢的另一個(gè)因素是變量類型不確定,Python解釋器需要進(jìn)行大量的類型推斷。

      Numba也要推斷輸入輸出的類型:

      from numba import jit, int32

      @jit("int32(int32, int32)", nopython=True)

      def f2(x, y):

      # A somewhat trivial example

      return x + y

      @jit(int32(int32, int32))告知Numba你的函數(shù)在使用什么樣的輸入和輸出:

      括號內(nèi)是輸入;

      括號左側(cè)是輸出;

      這樣不會加快執(zhí)行速度,但是會加快編譯速度,可以更快將函數(shù)編譯到機(jī)器碼上。

      Numba原理

      Numba使用了LLVM和NVVM技術(shù),此技術(shù)將Python等解釋型語言直接翻譯成CPU、GPU可執(zhí)行的機(jī)器碼。

      Python 虛擬化

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:如何從Excel中的列表創(chuàng)建工作表名稱?
      下一篇:wps添加頁眉怎么取消(wps文檔怎樣取消頁眉)
      相關(guān)文章
      亚洲区小说区图片区| 亚洲精品国产高清不卡在线| 国产成人精品日本亚洲专区61 | 亚洲中文字幕无码亚洲成A人片| 亚洲第一永久在线观看| 亚洲自偷精品视频自拍| 久久亚洲精品无码VA大香大香| 五月天网站亚洲小说| 亚洲国产综合精品中文第一区| 久久精品亚洲中文字幕无码网站| 久久亚洲国产中v天仙www| 国产亚洲精品观看91在线| 亚洲动漫精品无码av天堂| 亚洲欧洲美洲无码精品VA| 国产精品亚洲成在人线| 亚洲成AV人片在线播放无码| 亚洲av无码成h人动漫无遮挡| 亚洲国产精品第一区二区| 中文字幕亚洲综合久久2| 亚洲精品在线播放| 亚洲国产日韩在线成人蜜芽 | 亚洲精品亚洲人成在线观看下载| 亚洲精品在线视频| 在线观看亚洲av每日更新| 亚洲精品亚洲人成人网| 亚洲AV日韩AV鸥美在线观看| 亚洲人成网站在线播放影院在线| 亚洲短视频在线观看| 亚洲一区二区免费视频| 亚洲性色AV日韩在线观看| 亚洲AV永久无码精品一福利 | 亚洲国产精品一区二区三区久久| 奇米影视亚洲春色| 亚洲av无码成人黄网站在线观看 | 爱情岛亚洲论坛在线观看 | 无码专区一va亚洲v专区在线| 亚洲午夜福利精品无码| 亚洲精品美女久久777777| 亚洲天天做日日做天天欢毛片| 亚洲另类自拍丝袜第1页| 亚洲午夜成人精品无码色欲|