Python
numpy
python3
pillow

【Python】画像読み込み時の記述方法による実行速度の比較

初めに

前回の記事(Neural Network Console を用いた超解像処理の実装)が初投稿にもかかわらず、23いいねと予想以上のいいねをいただきました。(2017/11/19 現在)本当にありがとうございました。
そして今回は、前回のNeural Network ConsoleのGUI操作ではなく、Pythonで文字による実装を行いました。その時に、画像の読み込みについて一つ検証を行いましたので、メモを残しておきます。

配列の生成方法

複数の配列をまとめた配列の生成方法には主に2種類あります。1つはそれぞれの配列を生成しつつ連結をしていくもの、もう1つは[]の中にfor分で繰り返し処理をしていくものです。いくつかの記事を眺めていると、どうやらこの2つは内部で行われている処理は違うようで、実行速度やメモリに差があるようです。そのため、今回のこの記事では機械学習における大量の画像の読み込みを行う際に、この2つの記述法によってどのくらいの違いがあるのかを検証していきます。
なお、この記事内では1つ1つ連結していく表記を「連結表記」、[]内にfor分を用いる表記を「内部表記」と呼ぶことにします。

記述方法サンプル

アウトプット

[0 1 2 3 4 5 6 7 8 9]
  • 連結表記
append.py
import numpy as np

lst = []
for i in range(10):
    x = np.array(i)
    lst.append(x)

print(np.array(lst))
  • 内部表記
in.py
print(np.array([i for i in range(10)]))

ソースコード

test.py
import time
import random
import numpy as np
from PIL import Image


# 内部表記
def in_create(lst):
    return np.array([np.array(Image.open("{}{}.png".format(path,lst[i]))) for i in range(len(lst))])

# 連結表記
def append_create(lst):
    res = []
    for i in range(len(lst)):
        img = Image.open("{}{}.png".format(path,lst[i]))
        arr = np.array(img)
        res.append(arr)
    return np.array(res)


# 変数設定
path = "data\dataset\\train\\input0\\"
l = [i for i in range(30000)]
num = 100

# 内部表記の測定\
start = time.time()
for i in range(num):
    x = in_create(l)
elapsed_time = (time.time() - start) / num
print ("内部表記:{}[sec]".format(elapsed_time))

# 連結表記の測定
start = time.time()
for i in range(num):
    x = append_create(l)
elapsed_time = (time.time() - start) / num
print ("連結表記:{}[sec]".format(elapsed_time))

今回は機械学習のために用意した128x128のカラー画像30000枚を一気に読み込んで配列にするまでにかかる時間を計測しました。また、それぞれ100回処理を繰り返し平均の時間を表示するようにしました。

結果

>python test.py
内部表記:17.044339520931246[sec]
連結表記:17.479241828918457[sec]

ということで、内部表記を行った方が処理速度がわずかに早いことがわかりました。

まとめ

この計測の後にも、2,3回計測をしなおしましたが、どの場合においても内部表記の方がわずかに時間が速かったです。
また、実行中に託すマネージャーを除いていると、内部表記は使用しているメモリは最大1.5GiBでしたが、連結表記は1.5GiBまで使用メモリが上昇した後に最後の瞬間だけ2GiBまで上昇する現象が起きました。今回の計測に当たり、使用メモリも厳密に測りたかったのですが、なぜか導入がうまくできなかったため、「使用メモリに関しても内部表記の方が良い」とは言い切れませんが、連結表記よりも受けるメリットは大きそうです。
ただし、コードの可読性が若干下がるというデメリットはありますが、、、。