2016-05-19 5 views
3

TensorFlowの操作と変数を効率的にデバイスに割り当てる方法が困惑しています。少なくとも私の基本的な畳み込みニューラルネットワークの実装では、可能な限り多くの操作をGPUに配置することが望ましいことは明らかです。しかし、私は現在へのアクセス権を持っているGPUは、フォームGPU実装の一環として、特定のTensorFlow計算をCPU上で実行するにはどうすればよいですか?

Ran out of memory trying to allocate 2.60GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.

Ran out of memory trying to allocate 83.74MiB. See logs for memory state. 
Resource exhausted: OOM when allocating tensor with shape[28000,1,28,28] 
のような特定の操作のために時折クラッシュし、多くの警告に記憶し、その結果を制限しています

これは、CPUに変数を配置することで回避できますが、私の実装では、これによりトレーニングのエポックが10回esは計算するのに長い。

明らかに、理想的な方針は、エラーを生成するコードの特定のチャンクを特定し、それらをCPU上に配置しようとすることです。しかし、これらの計算は効率を達成するためにGPUを配置する必要がある他のものから分離できないため、これをどうやって行うのかはわかりません。例えば

、単に

xは私のモデルへの入力の tf.placeholderで、 yは私のネットワークの出力アクティベーションされ、上記のエラーが生成さ
evals = sess.run(tf.argmax(y, 1), feed_dict={x: use_x_all}) 

ようなものでテストセットに予測を生成しますuse_x_allは大きな配列です(ここでは28000の例)。この計算を単独でCPUに実行しようとすると、恐らくyを生成するネットワーク評価がGPU上にあるために失敗します。このため

私は(ように見える)

明確にスケールしない
use_x_all, _ = data_loader.stack_data(use_data, as_cols=False) 
use_x_split = np.split(use_x_all, splits) 
for use_x in use_x_split: 
    # ... (full example below) 
    evals_part = sess.run(tf.argmax(y, 1), feed_dict={x: use_x}) 
    # accumulate evals 

のようなアプローチに頼る必要があります。

良い方法がありますか?具体的には

  • 上記のような計算をCPUに置き、GPU上で実行される同じグラフ(例:トレーニング)の計算はまだありますか?

、あるいは

  • より容易にそのような計算のメモリ要求を低減するために、このような状況でも適用することができる(バッチ処理など)イディオムがありますか?

実は、私は後者がTensorFlow APIの一部ではないことを驚いています。上記のようなコードを必要とせずに、デバイスに収まらないautomatically break up calculationsはできませんか?私のコードから


全例:

f = open('{0:s}/{1:s}_{2:3.0f}.csv'.format(FLAGS.pred_dir, FLAGS.session_name, 
                 10000*float(sess.run(accuracy, feed_dict=valid_feed))), 'w') 
f.write('ImageId,Label\n') 
use_x_all, _ = data_loader.stack_data(use_data, as_cols=False) 
      use_x_split = np.split(use_x_all, splits) 
last = 0 
buff = '' 
for use_x in use_x_split: 
    evals = sess.run(tf.argmax(y, 1), feed_dict={x: use_x}) 
    f.write('\n'.join('{0},{1}'.format(r[0]+ last, r[1]) for r in enumerate(evals, start=1))) 
    last += int(len(use_x_all)/splits) 
    if last < len(use_x_all): 
     f.write('\n') 
f.close() 
+0

TensorFlow [機能要求](https://github.com/tensorflow/tensorflow/issues/2431)とも呼ばれます。 – orome

答えて

-1

は、CPU上で上記のような計算を配置し、まだ同じグラフのこれらの計算を持つ方法(例えばトレーニング)の実行がありますGPUで?

明示的およびネストされたデバイス配置を使用できます。ロギングを使用して、操作の配置場所を確認します。

config = tf.ConfigProto() 
config.log_device_placement = True 
s = tf.InteractiveSession(config=config) 

with tf.device("/gpu:0"): 
    m = tf.matmul(tf.constant([[1,2,3,4]]), tf.constant([[1],[1],[1],[1]])) 
    with tf.device("/cpu:0"): 
     m = m + 1 

s.run(m) 
+0

いいえ、質問に記載されているように、問題はグラフがGPU上にあり、CPU上のグラフの出力でその 'argmax'を実行しようとすると失敗します(それはGPUにとどまります)。 – orome

+0

はあなたが求めているものが明確ではありません。投稿したコードは完全ではありません。問題を再現できるように実行できるコードを投稿してください。コードをチェックし、テンソルフローで訓練可能な操作を切断できないことを忘れないでください。 – fabrizioM

2

短い答え: あなたは、計算を分割することができますが、正しい方法について少し考える必要があります。 また、小規模なバッチはここで考えるのが妥当なイディオムです。

長い答え:

異機種混在配置が可能ですが、私はそれはあなたが聞かせてより少しより複雑だと思います。以下の(抽象簡略化)の設定を考えてみましょう:

setup

ここでの問題は、このネットワークを評価するために必要なすべてのテンソルは、私たちのGPUには収まらないだろうということです。残念ながら、メモリ割り当ての問題は通常は集約的な問題であるため、「エラーを生成するコードの特定のチャンクを特定する」ほど簡単ではありません。 I.E。エラーは、合計が大きすぎるというだけの症状であり、その特定の割り当てが大きすぎることを示すものではありません。あなたは、ラクダの背中を壊したストローを見ているだけです。

あなたが指摘するように、私たちはより良いスループットをGPU上での計算を実行したいのですが、無計画に配分することは、我々が得たであろう任意のパフォーマンスの向上を捨て、PCIインターフェースを介して大量のデータを移動します。

partitions

左側のパーティション化スキームでは、インターフェイスよりもずっと少ないデータしか移動しません。

あなたは別のバランスを達成するために、計算、グラフを分割することができ、他の無数の方法数があることを除いて...

Other partitions

及びこれらのそれぞれは、パフォーマンスの面で異なる動作をしようとしています。これはTFがあなたのグラフを自動分割しない理由です。それは実際には一般的なケースでは直接的な問題ではありません。

戻るあなたの問題に固有でパーティションの計算のため

ヒント。あなたのアプローチ(より小さなバッチ)は、実行可能なアプローチの1つです。効果的には、のサイズをすべて縮小すると、割り当て要求が発生します。それを分割することは他の人に示唆されているように実行可能なアプローチかもしれませんが、あなたはそれを知的に行うべきです。デバイス間のメモリ移動を最小限に抑え、同じデバイス上にグラフの計算上密な部分(畳み込み層の塊のような)を配置しようとします。

グラフの異なる部分のテンソルの大きさを(手動またはテンソルを使って)計算するのに役立つ方法があります。これは、ネットワークのどの部分が互いに対して相対的であるかを感じさせるはずです。これは、それを分割する方法についての合理的なガイドを提供します。

最後に、推論(訓練なし)のみを行っている場合は、一度にいくつかのネットワークだけを評価することもできます。これは、小さなバッチを使用する二重のアプローチのようなものです。多数の小さなバッチを持つ大規模なネットワークの代わりに、いくつかの大きなバッチを持つ少数の小さなネットワークを使用することができます。

関連する問題