2016-11-03 11 views
3

私は2つのgpu(TitanX(パスカル)とGTX 1080)を持っています。私は シングルスレッドグラフ計算を実行しようとしています。グラフは、2つの別々の行列乗算チェーンです(それぞれ対応するgpuに割り当てられています)。ここで TensorFlow 2gpuより遅く単一のgpu

は、私が使用しているコードです:

輸入tensorflowをNP 輸入ランダム インポート時 輸入ロギングなど 輸入numpyのTFとしてそれは20.4秒を要し

from tensorflow.python.ops import init_ops 
from tensorflow.python.client import timeline 


def test(): 
    n = 5000 

    with tf.Graph().as_default(): 
     A1 = tf.placeholder(tf.float32, shape=[n, n], name='A') 
     A2 = tf.placeholder(tf.float32, shape=[n, n], name='A') 
     with tf.device('/gpu:0'): 
      B1 = A1 
      for l in xrange(10): 
       B1 = tf.matmul(B1, A1) 

     with tf.device('/gpu:1'): 
      B2 = A2 
      for l in xrange(10): 
       B2 = tf.matmul(B2, A2) 
      C = tf.matmul(B1, B2) 

     run_metadata = tf.RunMetadata() 
     with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess: 
      start = time.time() 
      logging.info('started') 
      A1_ = np.random.rand(n, n) 
      A2_ = np.random.rand(n, n) 
      sess.run([C], 
        feed_dict={A1: A1_, A2: A2_}, 
        options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE), 
        run_metadata=run_metadata) 
      logging.info('writing trace') 
      trace = timeline.Timeline(step_stats=run_metadata.step_stats) 
      trace_file = open('timeline.ctf.json', 'w') 
      trace_file.write(trace.generate_chrome_trace_format()) 
      logging.info('trace written') 
      end = time.time() 
      logging.info('computed') 
      logging.info(end - start) 


if __name__ == "__main__": 
    logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') 
    test() 
  • 終わり。
  • すべての操作をgpu0(TitanX)に設定すると14秒かかります。
  • すべての操作をgpu1(GTX 1080)に設定すると、終了までに19.8秒かかります。

テンソルフローがgpusの両方を検出し、すべてのデバイスを正しく設定していることがわかります。 なぜ2つのGPUを1つではなくスピードアップしないのですか? gpusが異なるモデル(AFAIKのcudaはそれを可能にする)であるという問題かもしれませんか?

ありがとうございました。

EDIT 私はそうtensorflowは、いくつかの最適化を行うように思われるので、両方の鎖のために異なる初期行列を使用するようにコードを更新しました。ここで

は、タイムラインプロファイルJSONファイルのリンクです:https://api.myjson.com/bins/23csi

Screenshot

このタイムラインは、答えよりも多くの問題を提起:

  1. PID 7(gpu0)は、実行の2行を持っているのはなぜ?
  2. pid 3と5の長いMatMulsとは何ですか?
  3. すべてのオペアンプは小さいが多い5.
  4. gpu0のexecept pidの上で実行されているようだ( "_recv_A_0/_3"、名前 "MATMUL"、OP "MATMUL" INPUT1、 "_recv_A_0/_3" INPUT 0) MatMulの操作(スクリーンショットから見ることはできません)は、pid 3とpid 5の長いMatMuls操作の直後です。これは何ですか?
+0

あなたはまた、あなたが 'sess.run(C.opを行うことができ、ボトルネックhttps://github.com/tensorflow/tensorflow/issues/1824#issuecomment-225754659 –

+0

だものを見るためにタイムラインを見ることができます)は 'sess.run(C)'の代わりに '' sess.Run(C) ''の代わりにTensorFlow-> Pythonをあなたのタイミングから転送します –

+0

セッションのコンストラクタで "TypeError:__init __()に予期しないキーワード引数 'run_metadata' 9月16日のソースで、pipから再インストールしようとしましたが(同じエラーが発生しました) – MikleB

答えて

2

GPUでカーネルを初めて起動すると、PTXASのコンパイルによって発生する可能性があります。この遅れは秒単位であり、GPUを2つ以上使用すると累積します。したがって、時間が "初期カーネルの初期起動"によって支配されるため、実行が遅くなる場合があります。純粋な計算時間をベンチマークする1つの方法は、各GPU上で各cuda演算を少なくとも1回実行することによって「事前加温」することです。私は2枚のTitanXカードでベンチマークを実行することで同じ遅さを観察しましたが、この遅延はカーネルを「予熱した」ときに消えました。ここで

は、事前に温暖化の前にあります: enter image description here

はここで事前に温めた後だ:以下 enter image description here あなたのコードは事前温暖化を行うために、また、任意のTensorFlow <削除するように変更される - > Pythonの転送を。

import tensorflow as tf 

from tensorflow.python.ops import init_ops 
from tensorflow.python.client import timeline 
import logging, time 
import numpy as np 

def test(): 
    n = 5000 

    with tf.device('/gpu:0'): 
     A1 = tf.Variable(tf.ones_initializer(shape=[n, n]), name='A1') 
     B1 = A1 
     for l in xrange(10): 
      B1 = tf.matmul(A1, B1, name="chain1") 

    with tf.device('/gpu:1'): 
     A2 = tf.Variable(tf.ones_initializer(shape=[n, n]), name='A2') 
     B2 = A2 
     for l in xrange(10): 
      B2 = tf.matmul(A2, B2, name="chain2") 
     C = tf.matmul(B1, B2) 

    run_metadata = tf.RunMetadata() 
    start = time.time() 
    logging.info('started') 
    sess = tf.InteractiveSession(config=tf.ConfigProto(allow_soft_placement=False, log_device_placement=True)) 
    sess.run(tf.initialize_all_variables()) 
    # do warm-run 
    sess.run([C.op], 
      options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE), 
      run_metadata=run_metadata) 
    run_metadata = tf.RunMetadata() 
    sess.run([C.op], 
      options=tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE), 
      run_metadata=run_metadata) 
    logging.info('writing trace') 
    trace = timeline.Timeline(step_stats=run_metadata.step_stats) 
    trace_file = open('timeline.ctf.json', 'w') 
    trace_file.write(trace.generate_chrome_trace_format(show_memory=True)) 
    logging.info('trace written') 
    end = time.time() 
    logging.info('computed') 
    logging.info(end - start) 


if __name__ == "__main__": 
    logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') 
    test() 
+0

btw、タイムラインの誤った "gpu:0/stream:22"は実際にはgpu:1にあり、log_device_placementから見ると –

+0

わかりました。しかし、これらのタイムラインの痕跡はまだ私には不思議に見えます。なぜ私はすべての操作をgpu0に割り当てると、結果は常にすべて計算されます(私は5000から20000までの異なるマトリックスサイズを試して、100までの異なるチェーンの長さを試しました)?これらの2つの鎖は、単一のgpu上であっても2つの並列ストリームで計算できると思われる。 – MikleB

+0

これは間違いなく、テンソルフローはパラレルストリームのopsをスケジュールするのではなく、各opがGPUのすべてのストリームを使用できる –

0

Cを計算するときにGPU間でデータを転送する必要があるためですか? Cをcpuに入れてみることはできますか?

with tf.device('/cpu:0'): 
    C = tf.matmul(B1, B2) 
+0

と表示されています。また、最後のものの前に各gpuのために500のマトリックスのmltsがあるので、それは重要ではないと思う。 – MikleB

関連する問題