日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

[Python技巧]如何加快循环操作和Numpy数组运算速度

發(fā)布時間:2023/12/10 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Python技巧]如何加快循环操作和Numpy数组运算速度 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019 年第 53 篇文章,總第 77 篇文章

本文大約 4200?字,閱讀大約需要 11?分鐘

前言

Python 雖然寫起來代碼量要遠少于如 C++,Java,但運行速度又不如它們,因此也有了各種提升 Python 速度的方法技巧,這次要介紹的是用 Numba 庫進行加速比較耗時的循環(huán)操作以及 Numpy 操作。

在?24式加速你的Python中介紹對循環(huán)的加速方法中,一個辦法就是采用?Numba?加速,剛好最近看到一篇文章介紹了利用?Numba?加速 Python ,文章主要介紹了兩個例子,也是?Numba?的兩大作用,分別是加速循環(huán),以及對?Numpy?的計算加速。

原文:https://towardsdatascience.com/heres-how-you-can-get-some-free-speed-on-your-python-code-with-numba-89fdc8249ef3


相比其他語言,Python 確實在運行速度上是比較慢的。

一種常用解決方法,就是用如 C++ 改寫代碼,然后用 Python 進行封裝,這樣既可以實現(xiàn) C++ 的運行速度又可以保持在主要應(yīng)用中采用 Python 的方便。

這種辦法的唯一難點就是改寫為 C++ 部分的代碼需要耗費不少時間,特別是如果你對 C++ 并不熟悉的情況。

Numba?可以實現(xiàn)提升速度但又不需要改寫部分代碼為其他編程語言。

Numba 簡介

Numba?是一個可以將 Python 代碼轉(zhuǎn)換為優(yōu)化過的機器代碼的編譯庫。通過這種轉(zhuǎn)換,對于數(shù)值算法的運行速度可以提升到接近?C?語言代碼的速度。

采用?Numba?并不需要添加非常復(fù)雜的代碼,只需要在想優(yōu)化的函數(shù)前 添加一行代碼,剩余的交給?Numba?即可。

Numba?可以通過?pip?安裝:

$?pip?install?numba

Numba?對于有許多數(shù)值運算的,Numpy?操作或者大量循環(huán)操作的情況,都可以大大提升運行速度。

加速 Python 循環(huán)

Numba?的最基礎(chǔ)應(yīng)用就是加速 Python 中的循環(huán)操作。

首先,如果你想使用循環(huán)操作,你先考慮是否可以采用?Numpy?中的函數(shù)替代,有些情況,可能沒有可以替代的函數(shù)。這時候就可以考慮采用?Numba?了。

第一個例子是通過插入排序算法來進行說明。我們會實現(xiàn)一個函數(shù),輸入一個無序的列表,然后返回排序好的列表。

我們先生成一個包含 100,000 個隨機整數(shù)的列表,然后執(zhí)行 50 次插入排序算法,然后計算平均速度。

代碼如下所示:

import?time import?randomnum_loops?=?50 len_of_list?=?100000def?insertion_sort(arr):for?i?in?range(len(arr)):cursor?=?arr[i]pos?=?iwhile?pos?>?0?and?arr[pos-1]?>?cursor:#?從后往前對比,從小到大排序arr[pos]?=?arr[pos-1]pos?=?pos-1#?找到當前元素的位置arr[pos]?=?cursorreturn?arr start?=?time.time() list_of_numbers?=?list() for?i?in?range(len_of_list):num?=?random.randint(0,?len_of_list)list_of_numbers.append(num)for?i?in?range(num_loops):result?=?insertion_sort(list_of_numbers)end?=?time.time()run_time?=?end-start print('Average?time={}'.format(run_time/num_loops))

輸出結(jié)果:

Average?time=22.84399790763855

從代碼可以知道插入排序算法的時間復(fù)雜度是?,因為這里包含了兩個循環(huán),for?循環(huán)里面帶有?while?循環(huán),這是最差的情況。然后輸入數(shù)量是 10 萬個整數(shù),再加上重復(fù) 50 次,這是非常耗時的操作了。

原作者采用的是電腦配置是 i7-8700k,所以其平均耗時是?3.0104s。但這里我的電腦配置就差多了,i5-4210M 的筆記本電腦,并且已經(jīng)使用了接近 4 年,所以我跑的結(jié)果是,平均耗時為?22.84s。

那么,如何采用?Numba?加速循環(huán)操作呢,代碼如下所示:

import?time import?random from?numba?import?jitnum_loops?=?50 len_of_list?=?100000@jit(nopython=True) def?insertion_sort(arr):for?i?in?range(len(arr)):cursor?=?arr[i]pos?=?iwhile?pos?>?0?and?arr[pos-1]?>?cursor:#?從后往前對比,從小到大排序arr[pos]?=?arr[pos-1]pos?=?pos-1#?找到當前元素的位置arr[pos]?=?cursorreturn?arr start?=?time.time() list_of_numbers?=?list() for?i?in?range(len_of_list):num?=?random.randint(0,?len_of_list)list_of_numbers.append(num)for?i?in?range(num_loops):result?=?insertion_sort(list_of_numbers)end?=?time.time()run_time?=?end-start print('Average?time={}'.format(run_time/num_loops))

輸出結(jié)果:

Average?time=0.09438572406768798

可以看到,其實只增加了兩行代碼,第一行就是導(dǎo)入?jit?裝飾器

from?numba?import?jit

接著在函數(shù)前面增加一行代碼,采用裝飾器

@jit(nopython=True) def?insertion_sort(arr):

使用?jit?裝飾器表明我們希望將該函數(shù)轉(zhuǎn)換為機器代碼,然后參數(shù)?nopython?指定我們希望?Numba?采用純機器代碼,或者有必要的情況加入部分?Python?代碼,這個參數(shù)必須設(shè)置為?True?來得到更好的性能,除非出現(xiàn)錯誤。

原作者得到的平均耗時是?0,1424s?,而我的電腦上則是提升到僅需?0.094s?,速度都得到非常大的提升。

加速 Numpy 操作

Numba?的另一個常用地方,就是加速?Numpy?的運算。

這次將初始化 3 個非常大的?Numpy?數(shù)組,相當于一個圖片的尺寸大小,然后采用?numpy.square()?函數(shù)對它們的和求平方。

代碼如下所示:

import?time import?numpy?as?npnum_loops?=?50 img1?=?np.ones((1000,?1000),?np.int64)?*?5 img2?=?np.ones((1000,?1000),?np.int64)?*?10 img3?=?np.ones((1000,?1000),?np.int64)?*?15def?add_arrays(img1,?img2,?img3):return?np.square(img1+img2+img3)start1?=?time.time() for?i?in?range(num_loops):result?=?add_arrays(img1,?img2,?img3) end1?=?time.time() run_time1?=?end1?-?start1 print('Average?time?for?normal?numpy?operation={}'.format(run_time1/num_loops))

輸出結(jié)果:

Average?time?for?normal?numpy?operation=0.040156774520874024

當我們對?Numpy?數(shù)組進行基本的數(shù)組計算,比如加法、乘法和平方,Numpy?都會自動在內(nèi)部向量化,這也是它可以比原生?Python?代碼有更好性能的原因。

上述代碼在原作者的電腦運行的速度是?0.002288s?,而我的電腦需要?0.04s?左右。

但即便是?Numpy?代碼也不會和優(yōu)化過的機器代碼速度一樣快,因此這里依然可以采用?Numba?進行加速,代碼如下所示:

#?numba?加速 from?numba?import?vectorize,?int64@vectorize([int64(int64,int64,int64)],?target='parallel') def?add_arrays_numba(img1,?img2,?img3):return?np.square(img1+img2+img3)start2?=?time.time() for?i?in?range(num_loops):result?=?add_arrays_numba(img1,?img2,?img3) end2?=?time.time() run_time2?=?end2?-?start2 print('Average?time?using?numba?accelerating={}'.format(run_time2/num_loops))

輸出結(jié)果:

Average?time?using?numba?accelerating=0.007735490798950195

這里采用的是?vectorize?裝飾器,它有兩個數(shù)參數(shù),第一個參數(shù)是指定需要進行操作的?numpy?數(shù)組的數(shù)據(jù)類型,這是必須添加的,因為?numba?需要將代碼轉(zhuǎn)換為最佳版本的機器代碼,以便提升速度;

第二個參數(shù)是?target?,它有以下三個可選數(shù)值,表示如何運行函數(shù):

  • cpu:運行在單線程的 CPU 上

  • parallel:運行在多核、多線程的 CPU

  • cuda:運行在 GPU 上

parallel?選項在大部分情況是快過?cpu?,而?cuda?一般用于有非常大數(shù)組的情況。

上述代碼在原作者的電腦運行時間是?0.001196s?,提升了 2 倍左右,而我的電腦是?0.0077s,提升了 5 倍左右速度。

小結(jié)

numba?在以下情況下可以更好發(fā)揮它提升速度的作用:

  • Python?代碼運行速度慢于?C代碼的地方,典型的就是循環(huán)操作

  • 在同個地方重復(fù)使用同個操作的情況,比如對許多元素進行同個操作,即?numpy數(shù)組的操作

而在其他情況下,Numba?并不會帶來如此明顯的速度提升,當然,一般情況下嘗試采用?numba?提升速度也是一個不錯的嘗試。

最后,練習(xí)代碼:

https://github.com/ccc013/Python_Notes/blob/master/Python_tips/numba_example.ipynb


關(guān)于 Python?加速的操作,你還知道其他的技巧或者方法嗎,可以留言分享一下!

歡迎關(guān)注我的微信公眾號--算法猿的成長,或者掃描下方的二維碼,大家一起交流,學(xué)習(xí)和進步!

如果覺得不錯,在看、轉(zhuǎn)發(fā)就是對小編的一個支持!

往期精彩推薦

機器學(xué)習(xí)系列

Github項目 & 資源教程推薦

總結(jié)

以上是生活随笔為你收集整理的[Python技巧]如何加快循环操作和Numpy数组运算速度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。