在 Python 中,我們可以找到原生的并行化運算指令,本文可以教你僅使用 3 行代碼,大大加快資料預處理的速度,
在默認情況下,Python 程式是單個行程,使用單 CPU 核心執行,而大多數硬體都至少搭載了雙核處理器,這意味著如果沒有進行優化,在資料預處理的時候會出現「一核有難九核圍觀」的情況——超過 50% 的算力都會被浪費,
幸運的是,Python 庫中內建了一些隱藏的特性,可以讓我們充分利用所有 CPU 核心的能力,通過使用 Python 的 concurrent.futures 模塊,我們只需要 3 行代碼就可以讓一個普通的程式轉換成適用于多核處理器并行處理的程式,
標準方法
讓我們舉一個簡單的例子,在單個檔案夾中有一個圖片資料集,其中有數萬張圖片,在這里,我們決定使用 1000 張,我們希望在所有圖片被傳遞到深度神經網路之前將其調整為 600×600 像素解析度的形式,以下是你經常會在 GitHub 上看到的標準 Python 代碼:
上面的程式遵循你在處理資料腳本時經常看到的簡單模式:
1. 首先從需要處理內容的檔案(或其他資料)串列開始,
2. 使用 for 回圈逐個處理每個資料,然后在每個回圈迭代上運行預處理,
讓我們在一個包含 1000 個 jpeg 檔案的檔案夾上測驗這個程式,看看運行它需要多久:
在我的酷睿 i7-8700k 6 核 CPU 上,運行時間為 7.9864 秒!在這樣的高端 CPU 上,這種速度看起來是難以讓人接受的,看看我們能做點什么,
更快的方法
為了便于理解并行化的提升,假設我們需要執行相同的任務,比如將 1000 個釘子釘入木頭,假如釘入一個需要一秒,一個人就需要 1000 秒來完成任務,四個人組隊就只需要 250 秒,
在我們這個包含 1000 個影像的例子中,可以讓 Python 做類似的作業:
- 將 jpeg 檔案串列分成 4 個小組;
- 運行 Python 解釋器中的 4 個獨立實體;
- 讓 Python 的每個實體處理 4 個資料小組中的一個;
- 結合四個處理程序得到的結果得出最終結果串列,
這一方法的重點在于,Python 幫我們處理了所有棘手的作業,我們只需告訴它我們想要運行哪個函式,要用多少 Python 實體,剩下的就交給它了!只需改變三行代碼,實體:
import glob
import os
import cv2
import concurrent.futures
def load_and_resize(image_filename):
### Read in the image data
img = cv2.imread(image_filename)
### Resize the image
img = cv2.resize(img, (600, 600))
### Create a pool of processes. By default, one is created for each CPU in your machine.
with concurrent.futures.ProcessPoolExecutor() as executor:
### Get a list of files to process
image_files = glob.glob("*.jpg")
### Process the list of files, but split the work across the process pool to use all CPUs
### Loop through all jpg files in the current folder
### Resize each one to size 600x600
executor.map(load_and_resize, image_files)
從以上代碼中摘出一行:
你的 CPU 核越多,啟動的 Python 行程越多,我的 CPU 有 6 個核,實際處理代碼如下:
「executor.map()」將你想要運行的函式和串列作為輸入,串列中的每個元素都是我們函式的單個輸入,由于我們有 6 個核,我們將同時處理該串列中的 6 個專案!
如果再次用以下代碼運行我們的程式:
我們可以將運行時間降到 1.14265 秒,速度提升了近 6 倍!
注意:在生成更多 Python 行程及在它們之間整理資料時會有一些開銷,所以速度提升并不總是這么明顯,但是總的來說,速度提升還是非常可觀的,
它總是那么快嗎?
如果你有一個資料串列要處理,而且在每個資料點上執行相似的運算,那么使用 Python 并行池是一個很好的選擇,但有時這不是最佳解決方案,并行池處理的資料不會在任何可預測的順序中進行處理,如果你對處理后的結果有特殊順序要求,那么這個方法可能不適合你,
你處理的資料也必須是 Python 可以「炮制」的型別,所幸這些指定類別都很常見,以下來自 Python 官方檔案:
- None, True, 及 False
- 整數、浮點數、復數
- 字串、位元組、位元組陣列
- 只包含可挑選物件的元組、串列、集合和字典
- 在模塊頂層定義的函式(使用 def ,而不是 lambda )
- 在模塊頂層定義的內置函式
- 在模塊頂層定義的類
- 這種類的實體,其 dict 或呼叫getstate() 的結果是可選擇的
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/264071.html
標籤:Python
