時々問題に遭遇します:
形状を持つテンソルを割り当てるときのOOM
等式.
形状(1024、100、160)のテンソルを割り当てるときのOOM
ここで、1024は私のバッチサイズで、残りは何なのかわかりません。モデルのバッチサイズまたはニューロンの数を減らすと、正常に実行されます。
モデルとGPUメモリに基づいて最適なバッチサイズを計算する一般的な方法はありますか?プログラムはクラッシュしませんか?
要するに、モデルの観点から可能な限り最大のバッチサイズが必要です。これは、GPUメモリに収まり、プログラムをクラッシュさせません。
以下を使用して、最大バッチサイズを推定できます。
最大バッチサイズ=利用可能なGPUメモリバイト/ 4 /(テンソルのサイズ+トレーニング可能なパラメーター)
Goodfellowらによる最近のディープラーニングの本、 chapter 8 から:
ミニバッチのサイズは通常、次の要因によって決まります。
- バッチが大きいほど、勾配のより正確な推定値が得られますが、線形リターンは少なくなります。
- マルチコアアーキテクチャは通常、非常に小さなバッチで十分に活用されていません。これは、絶対最小バッチサイズを使用する動機となります。これを下回ると、ミニバッチを処理する時間が短縮されません。
- バッチ内のすべての例が並行して処理される場合(通常の場合)、メモリの量はバッチサイズに比例します。多くのハードウェアセットアップでは、これがバッチサイズの制限要因です。
- ある種のハードウェアは、特定のサイズのアレイでより良いランタイムを実現します。特にGPUを使用している場合、2のべき乗のバッチサイズが実行時間を改善するのが一般的です。 2つのバッチサイズの一般的な能力は32から256の範囲で、大規模なモデルでは16が試行されることがあります。
- おそらく、学習プロセスにノイズが加わるため、小さなバッチは正則化効果をもたらします(Wilson and Martinez、2003)。一般化エラーは、多くの場合、バッチサイズ1に最適です。このような小さなバッチサイズでのトレーニングでは、勾配の推定値の変動が大きいため、安定性を維持するために小さな学習率が必要になる場合があります。合計学習時間は、学習率の低下とトレーニングセット全体の観察により多くのステップが必要なため、より多くのステップを実行する必要があるため、非常に高くなる可能性があります。
実際には、これは通常「2のべき乗以上の大きさで、バッチが(GPU)メモリに収まる場合」を意味します。
Stack Exchangeのいくつかの優れた投稿も参照してください。
Keskar et al。による論文は覚えておいてください。 「 ディープラーニングのための大規模バッチトレーニング:一般化ギャップとシャープミニマム 」は、上記のいくつかの投稿で引用され、 いくつかの異論 ディープラーニングコミュニティの他の立派な研究者による。
お役に立てれば...
[〜#〜] update [〜#〜](2017年12月):Yoshua Bengio&teamによる新しい論文があります、 SGD の最小値に影響する3つの要因(2017年11月);学習率とバッチサイズの相互作用に関する新しい理論的および実験的結果を報告するという意味で読む価値があります。
同様のGPUメモリエラーが発生しましたが、次のようにtensorflowセッションを構成することで解決しました。
# See https://www.tensorflow.org/tutorials/using_gpu#allowing_gpu_memory_growth
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
def FindBatchSize(model):
"""#model: model architecture, that is yet to be trained"""
import os, sys, psutil, gc, tensorflow, keras
import numpy as np
from keras import backend as K
BatchFound= 16
try:
total_params= int(model.count_params()); GCPU= "CPU"
#find whether gpu is available
try:
if K.tensorflow_backend._get_available_gpus()== []:
GCPU= "CPU"; #CPU and Cuda9GPU
else:
GCPU= "GPU"
except:
from tensorflow.python.client import device_lib; #Cuda8GPU
def get_available_gpus():
local_device_protos= device_lib.list_local_devices()
return [x.name for x in local_device_protos if x.device_type == 'GPU']
if "gpu" not in str(get_available_gpus()).lower():
GCPU= "CPU"
else:
GCPU= "GPU"
#decide batch size on the basis of GPU availability and model complexity
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params <1000000):
BatchFound= 64
if (os.cpu_count() <16) and (total_params <500000):
BatchFound= 64
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params <2000000) and (total_params >=1000000):
BatchFound= 32
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params >=2000000) and (total_params <10000000):
BatchFound= 16
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params >=10000000):
BatchFound= 8
if (os.cpu_count() <16) and (total_params >5000000):
BatchFound= 8
if total_params >100000000:
BatchFound= 1
except:
pass
try:
#find percentage of memory used
memoryused= psutil.virtual_memory()
memoryused= float(str(memoryused).replace(" ", "").split("percent=")[1].split(",")[0])
if memoryused >75.0:
BatchFound= 8
if memoryused >85.0:
BatchFound= 4
if memoryused >90.0:
BatchFound= 2
if total_params >100000000:
BatchFound= 1
print("Batch Size: "+ str(BatchFound)); gc.collect()
except:
pass
memoryused= []; total_params= []; GCPU= "";
del memoryused, total_params, GCPU; gc.collect()
return BatchFound
#####################################################################################################
#####################################################################################################