前提・実現したいこと
以前、こちらの記事で質問させていただいたのですが補足でご指摘いただいた通りに粒度を大きくしてみたのですが全然高速化できておりません、、、
ですので、何処がボトルネックになっているかご指摘と改善出来るならアドバイス頂けるとありがたいです。
個人的には、並列化した時の通信時間よりforの方が時間がかかっている感じがするのでこのような結果になったのではないかなぁと推測しております。
元のソースコード
Python3
1import concurrent.futures 2import matplotlib.pyplot as plt 3import numpy as np 4import cv2, sys, os 5 6img = cv2.cvtColor(cv2.imread(sys.argv[1]), cv2.COLOR_BGR2RGB) 7useCPU = 1 8 9def main(): 10 """ 11 メイン関数 12 """ 13 try: 14 useCPU = int( input("使用するCPUのコアを入力してください[ 1 ~ {0} ] : ".format(os.cpu_count())) ) 15 except: 16 useCPU = os.cpu_count() 17 if useCPU > os.cpu_count(): 18 useCPU = os.cpu_count() 19 mulchProcess(useCPU=useCPU) 20 plt.imshow(img) 21 plt.show() 22 23def changeToGray( number: int, width: np.ndarray ): 24 """ 25 並列化する処理 ( グレースケールに変換する ) 26 @param number (int) : このプロセスの番号 27 @param width (np.ndarray) : 横1行の配列[ [R, G, B], ・・・・ ,[R, G, B] ] 28 @return number (int) : このプロセスの番号 29 @return width (np.ndarray) : 引数で受け取った配列をグレースケールに変換した配列 30 """ 31 for pixel in width: 32 gray = int(pixel[0]*0.3) + int(pixel[1]*0.59) + int(pixel[2]*0.11) 33 pixel[0] = gray 34 pixel[1] = gray 35 pixel[2] = gray 36 return number, width 37 38def mulchProcess(useCPU: int): 39 """ 40 マルチコアでプロセスを生成して実行させる処理 41 @param useCPU (int) : 使用するCPUのコア数 42 """ 43 with concurrent.futures.ProcessPoolExecutor(max_workers=useCPU) as executer: 44 fs = [ executer.submit(changeToGray, i, width) for width, i in zip( img, range(len(img)) ) ] 45 for future in concurrent.futures.as_completed(fs): 46 line_number = future.result()[0] 47 gray_width = future.result()[1] 48 img[line_number] = gray_width 49 50if __name__ == '__main__': 51 main()
直したソースコード
Python3
1import concurrent.futures 2import matplotlib.pyplot as plt 3import numpy as np 4import cv2, sys, os 5 6img = cv2.cvtColor(cv2.imread(sys.argv[1]), cv2.COLOR_BGR2RGB) 7useCPU = 1 8step = 1 9 10def main(): 11 """ 12 メイン関数 13 """ 14 try: 15 useCPU = int( input("使用するCPUのコアを入力してください[ 1 ~ {0} ] : ".format(os.cpu_count())) ) 16 except: 17 useCPU = os.cpu_count() 18 if useCPU > os.cpu_count(): 19 useCPU = os.cpu_count() 20 step = int( len(img) / useCPU ) 21 mulchProcess(useCPU=useCPU, step= step) 22 plt.imshow(img) 23 plt.show() 24 25def changeToGray( number: int, length: int ): 26 """ 27 並列化する処理 28 @param number (int) : 画像の処理対象範囲の先頭の添字 29 @param length (int) : 対象範囲の長さ 30 @return number (int) : 画像の処理対象範囲の先頭の添字 31 @return part_height (int) : 処理後の画像の配列 32 """ 33 endPioint = number + length if number + length < len(img) else len(img) - 1 34 part_height = img[ number : endPioint-1 ] 35 for width in part_height: 36 for pixel in width: 37 gray = int(pixel[0]*0.3) + int(pixel[1]*0.59) + int(pixel[2]*0.11) 38 pixel[0] = gray 39 pixel[1] = gray 40 pixel[2] = gray 41 return number, part_height 42 43def mulchProcess(useCPU: int, step: int): 44 """ 45 マルチコアでプロセスを生成して実行させる処理 46 @param useCPU (int) : 使用するCPUのコア数 47 @param step (int) : 画像の高さをコア数で割った数 48 """ 49 index_list = [ i for i in range(0, len(img), step) if i < len(img) ] 50 with concurrent.futures.ProcessPoolExecutor(max_workers=useCPU) as executer: 51 fs = [ executer.submit(changeToGray, i, step) for i in index_list ] 52 for future in concurrent.futures.as_completed(fs): 53 line_number = future.result()[0] 54 part_height = future.result()[1] 55 for i, height in zip( range(line_number, line_number+len(part_height)), part_height ): 56 img[i] = height 57 58if __name__ == '__main__': 59 main()
試したこと
横1列ごとのピクセルで処理していたのを「横*(高さ/使用するコア数)」ごとに処理をさせるようにして通信時間を使用するコア数に削減させたつもりです....
補足情報(FW/ツールのバージョンなど)
[実行環境]
MacBook Pro (15-inch, 2016)
プロセッサ : 2.6 GHz Intel Core i7 ( 4コア8スレッド )
メモリ : 16 GB 2133 MHz LPDDR3
Python 3.6.4
[実行時間]
使用画像 : 5000px*5025px (15.1MB)
修正前のコード : 44.79758310317993秒
修正後のコード : 45.401297092437744秒
回答3件
あなたの回答
tips
プレビュー