Kerasでメモリ使用量を減らしたかったらmax_queue_sizeを調整しよう
Kerasで大きめの画像を使ったモデルを訓練していると、メモリが足りなくなるということがよくあります。途中処理の変数のデータ型(np.uint8)を変えるのだけではなく、max_queue_sizeの調整をする必要があることがあります。それを見ていきます。
目次
メモリサイズの目安
ニューラルネットワークに食わせる変数は基本的にfloat32になるので、4バイト変数になります。つまり、「縦解像度×横解像度×チャンネル数(カラーなら3)×バッチサイズ×4バイト」必要になります。y横軸に縦横の解像度、縦軸にバッチサイズを取って計算すると次のような表になります。単位はGBです。
バッチ/解像度 | 32 | 64 | 128 | 256 | 512 | 1024 |
---|---|---|---|---|---|---|
32 | 0.000366211 | 0.001464844 | 0.005859375 | 0.0234375 | 0.09375 | 0.375 |
64 | 0.000732422 | 0.002929688 | 0.01171875 | 0.046875 | 0.1875 | 0.75 |
128 | 0.001464844 | 0.005859375 | 0.0234375 | 0.09375 | 0.375 | 1.5 |
256 | 0.002929688 | 0.01171875 | 0.046875 | 0.1875 | 0.75 | 3 |
512 | 0.005859375 | 0.0234375 | 0.09375 | 0.375 | 1.5 | 6 |
1024 | 0.01171875 | 0.046875 | 0.1875 | 0.75 | 3 | 12 |
2048 | 0.0234375 | 0.09375 | 0.375 | 1.5 | 6 | 24 |
4096 | 0.046875 | 0.1875 | 0.75 | 3 | 12 | 48 |
8192 | 0.09375 | 0.375 | 1.5 | 6 | 24 | 96 |
16384 | 0.1875 | 0.75 | 3 | 12 | 48 | 192 |
32768 | 0.375 | 1.5 | 6 | 24 | 96 | 384 |
65536 | 0.75 | 3 | 12 | 48 | 192 | 768 |
32×32ぐらいではほぼ問題になることはありませんが、256×256ぐらいから結構問題になってくるのではないでしょうか。
ただ、これは最小限の値で、実際にはこれにラベルデータや、主にバッチの演算や代入をする場合は瞬間的にこれの2倍ぐらいは見ておいたほうがいいのではないかと思います。ここに出るくる値が2GBでも、実際は10GBぐらい消費していたなんてことがあります。
1つの大きな原因はmax_queue_size
すべてがすべて解決できるわけではないですが、実際のメモリ使用量を減らす方策として、model.fit_generator, predict_generatorにおける「max_queue_size」を減らすというのがあります。これを調整している人はあまり見たことない気がします。
公式ドキュメントを見ると、model.fit_generatorの中に
max_queue_size: 整数.ジェネレータのキューのための最大サイズ. 指定しなければmax_queue_sizeはデフォルトで10になります.
特に指定しないと、デフォルトで10もキュー(キャッシュ)しているんですね。この単位はバッチなので、10バッチ分キャッシュしていると考えて良いと思います。GPUの性能があまり良くなくて、データの読み込みよりもネットワークの演算のほうがボトルネックになりやすいケースではこれは有効です。しかし、最近のGPUや特にTPUのように、ネットワークの演算は高性能だけど、データの読み込みが追いつかなくてジェネレーターがボトルネックになるケースでは、このキャッシュがほとんど意味をなさなくなります。
まずmax_queue_size分キャッシュしているのを確認します。
from keras.layers import Dense, Input
from keras.models import Model
import numpy as np
from keras.utils import to_categorical
input = Input((60,))
x = Dense(10, activation="softmax")(input)
model = Model(input, x)
model.compile("adam", "categorical_crossentropy", ["acc"])
def base_generator():
# batch_size=128
while True:
X = np.random.randn(128,60)
y = to_categorical(np.random.randint(0, 10,128), num_classes=10)
yield X, y
y_cache = []
def cache_generator():
global y_cache
y_cache = np.zeros(10).reshape(1,-1)
print("reset cache")
for X, y in base_generator():
y_cache = np.concatenate([y_cache, y], axis=0)
yield X, y
y_pred = model.predict_generator(cache_generator(), steps=10, max_queue_size=10)
print("Generatorが実際に転送した値")
print(y_pred.shape)
print("内部キャッシュ")
cache = np.asarray(y_cache[1:])
print(cache.shape)
このように、base_generator()をラップするようなcache_generator()を作り、ここでYの値をキャッシュしながらpredict_generatorさせています。ここでのキャッシュしたYの値は、実際にニューラルネットワーク側に転送されなくても、キュー用に内部的に読み込んだデータ数になるので、predictで返したサンプル数よりも多くなります。実際、デフォルトの(max_queue_size=10)で実行すると、
Generatorが実際に転送した値
(1280, 10)
内部キャッシュ
(2688, 10)
このように実際に転送したサンプルの2倍以上キューしていることになります。ちなみにこのmax_queue_sizeを2にすると、
Generatorが実際に転送した値
(1280, 10)
内部キャッシュ
(1536, 10)
キャッシュのマージンが少なくなります。
データの読み込みがボトルネックになっているケースでは、10バッチもキャッシュする必要はありません。仮にメモリが溢れて、その対策としてバッチサイズを下げ、ネットワークの計算が遅くなる/安定性が悪くなるのだったら、max_queue_sizeを下げたほうが効果があると思います。あくまで読み込みがボトルネックになるケースではですが。
逆に読み込みがボトルネックにならないようなケースでは、このデフォルトの設定はかなり有効になります。計算デバイスの性能良くなって、どこに重きをおくかが変わってきたのでしょうね。
まとめ
「メモリサイズをケチりたかったら、バッチサイズを下げるだけじゃなくて、max_queue_sizeを下げたほうが効果的かもしれないよ」ということでした。
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
「本当の実装力を身につける」ための221本ノック――
機械学習(ML)で避けて通れない数値計算ライブラリ・NumPyを、自在に活用できるようになろう。「できる」ための体系的な理解を目指します。基礎から丁寧に解説し、ディープラーニング(DL)の難しいモデルで遭遇する、NumPyの黒魔術もカバー。初心者から経験者・上級者まで楽しめる一冊です。問題を解き終わったとき、MLやDLなどの発展分野にスムーズに入っていけるでしょう。
本書の大きな特徴として、Pythonの本でありがちな「NumPyとML・DLの結合を外した」点があります。NumPyを理解するのに、MLまで理解するのは負担が大きいです。本書ではあえてこれらの内容を書いていません。行列やテンソルの理解に役立つ「従来の画像処理」をNumPyベースで深く解説・実装していきます。
しかし、問題の多くは、DLの実装で頻出の関数・処理を重点的に取り上げています。経験者なら思わず「あー」となるでしょう。関数丸暗記では自分で実装できません。「覚える関数は最小限、できる内容は無限大」の世界をぜひ体験してみてください。画像編集ソフトの処理をNumPyベースで実装する楽しさがわかるでしょう。※紙の本は電子版の特典つき
- まとめURL:https://github.com/koshian2/numpy_book
- みんなの感想:https://togetter.com/li/1641475
- A4 全176ページモノクロ / 2020年12月発行
「誰もが夢見るモザイク除去」を起点として、機械学習・ディープラーニングの基本をはじめ、GAN(敵対的生成ネットワーク)の基本や発展型、ICCV, CVPR, ECCVといった国際学会の最新論文をカバーしていく本です。
ディープラーニングの研究は発展が目覚ましく、特にGANの発展型は市販の本でほとんどカバーされていない内容です。英語の原著論文を著者がコードに落とし込み、実装を踏まえながら丁寧に解説していきます。
また、本コードは全てTensorFlow2.0(Keras)に対応し、Googleの開発した新しい機械学習向け計算デバイス・TPU(Tensor Processing Unit)をフル活用しています。Google Colaboratoryを用いた環境構築不要の演習問題もあるため、読者自ら手を動かしながら理解を深めていくことができます。
AI、機械学習、ディープラーニングの最新事情、奥深いGANの世界を知りたい方にとってぜひ手にとっていただきたい一冊となっています。持ち運びに便利な電子書籍のDLコードが付属しています。
「おもしろ同人誌バザールオンライン」で紹介されました!(14:03~) https://youtu.be/gaXkTj7T79Y?t=843
まとめURL:https://github.com/koshian2/MosaicDeeplearningBook
A4 全195ページ、カラー12ページ / 2020年3月発行
累計100万PV超の人気ブログが待望の電子化! このブログが電子書籍になって読みやすくなりました!
・1章完結のオムニバス形式
・機械学習の基本からマニアックなネタまで
・どこから読んでもOK
・何巻から読んでもOK
・短いものは2ページ、長いものは20ページ超のものも…
・通勤・通学の短い時間でもすぐ読める!
・読むのに便利な「しおり」機能つき
・全巻はA5サイズでたっぷりの「200ページオーバー」
・1冊にたっぷり30本収録。1本あたり18.3円の圧倒的コストパフォーマンス!
・文庫本感覚でお楽しみください
北海道の駅巡りコーナー
ローカル線や秘境駅、マニアックな駅に興味のある方におすすめ! 2021年に大半区間が廃線になる、北海道の日高本線の全区間・全29駅(苫小牧~様似)を記録した本です。マイカーを使わずに、公共交通機関(バス)と徒歩のみで全駅訪問を行いました。日高本線が延伸する計画のあった、襟裳岬まで様似から足を伸ばしています。代行バスと路線バスの織り成す極限の時刻表ゲームと、絶海の太平洋と馬に囲まれた日高路、日高の隠れたグルメを是非たっぷり堪能してください。A4・フルカラー・192ページのたっぷりのボリュームで、あなたも旅行気分を漫喫できること待ったなし!
見どころ:日高本線被災区間(大狩部、慶能舞川橋梁、清畠~豊郷) / 牧場に囲まれた絵笛駅 / 窓口のあっただるま駅・荻伏駅 / 汐見の戦争遺跡のトーチカ / 新冠温泉、三石温泉 / 襟裳岬
A4 全192ページフルカラー / 2020年11月発行