学習時間を少しでも短くしたい
トレーニングの時間は少しでも短くしたいですよね。
画像処理をしていて、画像の読み込みにかかる時間ってどれくらいなの?
というのを常々疑問に思っていたのですが、ちゃんと調べることはずっとしていませんでした。
load_img,imreadの画像の読み込み時間の違い
ほんとうはよくあるサンプルプログラムみたいに全部メモリに読み込んでおいてそれを処理できればいいんですがmnistじゃあるまいし実際に使う画像を全部乗っけられるようなメモリはなかなか取れません。
tensorflow , kerasを使ってる人だと load_imgを使ってる人もいるんじゃないかと思います。自分もはじめの頃に勉強した本がこれだったのでほぼずっとload_imgを使ってきていました。でもopencvにもimreadというのがあります。どっちがどれくらい速いの?
(@2023.1.22 PILの計測を追加しました)
実験
画像を1000枚読み込んで、ちょっとだけ加工(リサイズ、白黒化)する処理をして計測しました。
自分の場合白黒化する必要があったのでそれも計測に入れました。
計測に使った環境はgoogle colabのcpuです。
元画像はだいたいですが、長辺が1024の画像です。
import os
YDIRS = [ "./images" ] #適宜画像ファイルのあるディレクトリを指定
filePaths = []
for imgDir in YDIRS:
fileList = os.listdir( imgDir )
fileList.sort()
for fileName in fileList:
filePath = os.path.join( imgDir,fileName )
filePaths.append( filePath )
imgNum = len( filePaths )
print( "imgNum="+str(imgNum))
こんな感じでファイルのパスを集めて
#load_imgで読むのにかかる時間
import time
from tensorflow.keras.utils import load_img
tfromEpo = time.perf_counter()
for i in range(1000):
filePath = filePaths[i]
img = load_img( filePath,target_size=(512,512))
if i % 100 == 0:
print( f"\r{i+1}/{imgNum}",end="" )
ttoEpo = time.perf_counter()
tdEpo = ttoEpo - tfromEpo
print( f" -- elapsed {tdEpo:.04f} sec." )
こんな感じで計測します。
目的サイズは512x512としました。
処理内容
load_img後のグレースケール化は自前の処理で、
imreadのほうは
ary = cv2.imread(filePath, cv2.IMREAD_GRAYSCALE)
aryX = cv2.resize(ary,(512,512),interpolation=cv2.INTER_LINEAR)
こんな感じです。
imreadはリサイズの補間オプションがあるのでそれの違いも調べました。
1000枚の画像を前処理で512x512に白黒でリサイズ化しておいたものをpngのテンポラリファイルとして保存しておいて読むこむのも計測しました。
要するにload_imgでもimreadでもPILでも最終的に512x512の白黒画像を1000枚、メモリに展開するのに掛かる時間を計測しました。
計測結果
load_img/imread/PIL | 処理 | 時間(秒) |
---|---|---|
load_img | 読み込みのみ | 14.7785 |
load_img | グレースケール化 | 16.1188 |
imread | INTER_NEAREST | 6.6793 |
imread | INTER_LINEAR | 7.0711 |
imread | INTER_CUBIC | 7.5854 |
imread | INTER_AREA | 9.1466 |
imread | INTER_LANCZOS4 | 10.9502 |
imread | 前処理したファイル(png)の読み込み | 3.3909 |
PIL | openのみ | 0.0808 |
PIL | open + img_to_array + cv2.resize(INTER_LINEAR) | 17.9979 |
PIL | open + conver('L')でグレー化+img_to_array+cv2.resize(INTER_LINEAR) | 16.6866 |
結論
思っていた以上にload_imgが遅いことがわかりました。
補間については、AREA LANCZOS4はそれなりに重い処理のようです。
前処理しておいたものを読み込む仕組みに変えると倍以上に速くなっているところをみるとimreadを使った場合でもresizeは決して軽い処理ではないと言えそうです。
PILはopenだけだと激速ですが、ちょっとなにか処理すると途端に速度が低下しload_img以下になりました。なれてないもので使い方に間違いがあるのかもしれませんが、openだけだとほんとにファイルを開くだけなのだと思われます。
自分の場合は画像は70000枚くらいでしたので、大雑把にload_imgでグレースケール化してると15x70/60=17.5で1エポックごとに17分以上も画像の読み込み→白黒化に使っていたことになります。
もしこれを前処理したものをimreadする形式に変えたとすると3x70/60=3.5で1エポックごとに14分も高速化できることになります。
14分x100epoch=1400
1400/60=23.3333...
100epoch処理したとするとまる1日近くの違いになることになります。
全く馬鹿になりませんね。
@2023.1.22 PIL追加。計測の精度向上