最詳細的Python OpenCV速度提升全彙總!

Python OpenCV速度提升全彙總

前言

周更周更,希望能做到有質量的周更。最近好忙啊,在弄圖像算法專利Kaggle的比賽,還有工作上的事情。閒話打住,說說自己喫飯的傢伙,OpenCV和python。這篇主要彙總OpenCV python項目中對速度的提升的方法。個人經驗,如有問題歡迎評論或者私聊

整體思路

要縮短代碼運行的時間,那麼我們首先要知道改哪裏。我們需要分析代碼運行時間。找出在哪裏修改,而修改整體思路分爲兩步,減少路程增加速度減少路程就是減少代碼裏不必要的操作,用簡單的方法實現你的算法,每個項目的代碼都不一樣,這個只能靠自己。另一個是增加速度,增加代碼運行速度,這個方法比較共通。我會在下面一一列出,希望沒有遺漏,從而解決您的問題。

具體步驟

分析代碼運行時間(必要)

分析代碼運行時間,這樣你才能找出在哪裏修改你的代碼。
1.最簡單的

import time
t1=time.time()
test_work=[x**2 for x in range(1,1000000,3)]
t2=time.time()
print(t2-t1)
#0.11789417266845703

2.jupyter環境(IPython)
IPython的功能比較強大
它的“魔法”命令(‘magic’ commands)可以輕鬆實現分析代碼運行時間這個功能
先貼一個三個鏈接
IPython官方文檔內置魔術命令的介紹
IPython(jupyter環境)中的”魔法“命令 %time,%timeit,%%time,%%timeit
IPython中的時序和性能分析
強烈建議大家進去看看,第一個和第三個。只想瞭解%time和%timeit的可以看第二個。

簡要的說一下。
時間分析裏的
%time:查看腳本運行需要多長時間
%timeit:查看腳本平均運行多個運行所花費的時間
%prun:查看腳本中每個函數運行了多長時間
%lprun:查看函數中每行花費了多長時間

內存分析裏的:
%mprun:查看腳本逐行使用多少內存
%memit:查看腳本總體使用多少內存

python加速

這個就有的說了,一搜各種方法都出來了。這裏對我啓發比較大的是這篇文章。24式加速你的Python(小結)
這裏先總結,並說下自己的感受供各位參考,其中的部分內容之後可以再寫(shui)一篇博客了。

關於查找的建議

1.用set而非list進行查找
(準確的說是查找在set中的速度更快,list中的查找會隨着list本身的增大而變慢,數據量大時,更改後效果顯著)
2.用dict而非兩個list進行匹配查找(數據量大時,更改後效果顯著)

關於循環的建議

1.優先使用for循環而不是while循環(只快一點
2.在循環體中避免重複計算(減少不必要的操作

關於函數的建議

1.用循環機制代替遞歸函數(更改後效果顯著)
2.用緩存機制加速遞歸函數(更改後效果顯著)
3.用numba加速Python函數(萬金油的加速效果顯著)
numba是一個用於編譯Python數組和數值計算函數的編譯器,這個編譯器能夠大幅提高直接使用Python編寫的函數的運算速度。
numba使用LLVM編譯器架構將純Python代碼生成優化過的機器碼,通過一些添加簡單的註解,將面向數組和使用大量數學的python代碼優化到與c,c++和Fortran類似的性能,而無需改變Python的解釋器。
直接貼官方文檔
Numba documentation
最關鍵的是使用簡單,不過如果函數只打算用一兩次,那還是沒必要去用的。

關於使用標準庫函數進行加速的建議

1.使用collections.Counter加速計數(數據量大時,更改後效果優秀)
2.使用collections.ChainMap加速字典合併(數據量大時,更改後效果顯著)

關於使用高階函數進行加速的建議

1.使用map代替推導式進行加速(數據量大時,更改後效果顯著)
2.使用filter代替推導式進行加速(數據量大時,更改後效果顯著)

關於使用numpy向量化進行加速的建議

1.使用np.array代替list(數據量大時,更改後效果顯著)

2.使用np.ufunc代替math.func(數據量大時,更改後效果顯著)

3.使用np.where代替if(數據量大時,更改後效果顯著)

關於加速Pandas的建議

1.使用csv文件讀寫代替excel文件讀寫(數據量大時,更改後效果顯著)
2.使用pandas多進程工具pandarallel(多進程工具)

關於使用dask加速的建議

Dask是一款用於分析計算的靈活並行計算庫。
Dask由兩部分組成:
針對計算優化的動態任務調度。這與Airflow,Luigi,Celery或Make類似,但針對交互式計算工作負載進行了優化。
“大數據”集合, 像並行數組,數據框和列表一樣,它們將通用接口(如NumPy,Pandas或Python迭代器)擴展到大於內存或分佈式環境。 這些並行集合運行在動態任務調度器之上。
貼兩個鏈接
Dask教程
Dask官方文檔
1.使用dask加速dataframe
2.使用dask.delayed進行加速

關於應用多線程多進程加速

1.應用多線程加速IO密集型任務
2.應用多進程加速CPU密集型任務

OpenCV加速

OpenCV文檔的建議

這裏的建議直接引用一下官方的文檔,下面是翻譯。
出自這裏OpenCV的性能測量和改進技術

這裏要注意的主要事情是,首先嚐試以一種簡單的方式實現該算法。工作正常後,對其進行概要分析,找到瓶頸並對其進行優化。
1.儘量避免在Python中使用循環,尤其是雙/三重循環等。它們本來就很慢。
2.由於Numpy和OpenCV已針對向量運算進行了優化,因此將算法/代碼向量化到最大程度。
3.利用緩存一致性。
4.除非需要,否則切勿製作數組的副本。嘗試改用視圖。陣列複製是一項昂貴的操作。
即使完成所有這些操作後,如果您的代碼仍然很慢,或者不可避免地需要使用大循環,請使用Cython等其他庫來使其更快。

Numpy文檔的建議

而在Numpy中在它的文檔的2.4.4建議也類似。
出自這裏Numpy優化代碼
1.向量化循環
查找避免使用numpy數組進行for循環的技巧。爲此,掩碼和索引數組可能很有用。
2.廣播(Broadcasting)
在合併數組之前,請使用廣播(Broadcasting)對數組進行儘可能小的操作。
3.就地操作(In place operations)
In place operations
a *= 0比a = 0 * a 快
4.易於存儲(Be easy on the memory):使用視圖(views),而不是副本(copies)。
5.當心緩存效果:進行分組時,內存訪問成本更低:連續訪問大型陣列比隨機訪問要快得多。除其他外,這意味着較小的步幅更快。
6.使用編譯後的代碼
一旦確定所有高級優化都已被採用,最後的選擇就是將熱點(hot spots:花費大部分時間的幾行代碼或函數)轉移到已編譯的代碼中。對於已編譯的代碼,首選的選擇是使用 Cython:在已編譯的代碼中轉換現有的Python代碼很容易,並且很好地利用 numpy支持會 在numpy數組上產生有效的代碼,例如通過展開循環。

最後提一下的是OpenCV裏默認的優化。
許多OpenCV功能已使用SSE2,AVX等進行了優化。它還包含未優化的代碼。因此,如果我們的系統支持這些功能,則應該利用它們(幾乎所有現代處理器都支持它們)。默認在編譯時啓用。因此,如果已啓用,OpenCV將運行優化的代碼,否則將運行未優化的代碼。您可以使用cv2.useOptimized()來檢查是否啓用/禁用它,並使用cv2.setUseOptimized()來啓用/禁用它。

cv2.useOptimized()
#Out[33]: True
#默認是開啓的
cv2.setUseOptimized(False)
cv2.useOptimized()
#Out[35]: False
#使用cv2.setUseOptimized(False)就可以禁用優化了

還有OpenCV裏的很多函數,個人推薦使用前看下文檔,參數的選擇也是挺關鍵的優化步驟。

結束語

寫完了,這篇總結自己也學習了很多,儘量做到詳細。Python的速度確實是它的劣勢,不過人生苦短,我選它。如果有不清楚的地方,歡迎留言或者私聊哦,筆者看到後一定會回覆的。如果這篇文章對你有幫助,麻煩點個贊。謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章