Узкое место производительности TensorFlow на IteratorGetNext

Возясь с TensorFlow, я заметил, что относительно простая задача (пакетирование некоторых данных нашего 3D-акселерометра и получение суммы каждой эпохи) имеет относительно низкую производительность. Вот суть того, что у меня было, когда я получил (невероятно изящный!) -operations-with-tensorflow/37774470#37774470">Временная шкала добавлена ​​функциональность:

import numpy as np
import tensorflow as tf
from tensorflow.python.client import timeline

# Some dummy functions to compute "features" from the data

def compute_features( data ):
    feature_functions = [
        lambda x: test_sum( x, axis = 0 ),
        lambda x: test_sum( x, axis = 1 ),
        lambda x: test_sum( x, axis = 2 ),
    ]
    return tf.convert_to_tensor( [ f( data ) for f in feature_functions ] )

def test_sum( data, axis = 0 ):
    t, v = data
    return tf.reduce_sum( v[:, axis] )


# Setup for using Timeline
sess = tf.Session()
run_options = tf.RunOptions( trace_level = tf.RunOptions.FULL_TRACE )
run_metadata = tf.RunMetadata()

# Some magic numbers for our dataset
test_sampling_rate = 5000.0
segment_size = int( 60 * test_sampling_rate )

# Load the dataset
with np.load( 'data.npz' ) as data:
    t_raw = data['t']
    v_raw = data['v']

# Build the iterator
full_dataset = tf.data.Dataset.from_tensor_slices( (t_raw, v_raw) ).batch( segment_size )
dataset_iterator = full_dataset.make_initializable_iterator()
next_datum = dataset_iterator.get_next()

sess.run( dataset_iterator.initializer )
i = 0
while True:
    try:
        print( sess.run( compute_features( next_datum ), options = run_options,
                                                         run_metadata = run_metadata ) )
        # Write Timeline data to a file for analysis later
        tl = timeline.Timeline( run_metadata.step_stats )
        ctf = tl.generate_chrome_trace_format()
        with open( 'timeline_{0}.json'.format( i ), 'w' ) as f:
            f.write( ctf )
        i += 1
    except tf.errors.OutOfRangeError:
        break

Подняв это в Chrome, я заметил, что в каждой итерации IteratorGetNext поглощал большую часть времени:

Снимок экрана Chrome, на котором показана временная шкала для одной итерации

Как видите, «основная» часть вычислений сосредоточена в крошечных точках с правой стороны, в то время как подавляющее большинство времени этого цикла застревает в IteratorGetNext.

Мне интересно, не упустил ли я что-нибудь очевидное в том, как я построил свой график, который привел бы к столь вопиющему падению производительности на этом этапе. Я немного озадачен тем, почему эта установка работает так плохо.


person Maxwell Collard    schedule 09.02.2018    source источник


Ответы (1)


Если IteratorGetNext отображается как крупное событие на временной шкале, то ваша модель ограничена при обработке входных данных. В этом случае конвейер довольно прост, но узким местом является копирование 300 000 элементов в пакет. Вы можете убрать эту копию с критического пути, добавив преобразование Dataset.prefetch(1) в определение набора данных:

full_dataset = (tf.data.Dataset.from_tensor_slices((t_raw, v_raw))
                .batch(segment_size)
                .prefetch(1))

Дополнительные рекомендации по повышению производительности см. в новом Руководстве по производительности входного конвейера в tensorflow. орг.

PS. Вызов compute_features(next_datum) в цикле со временем приведет к росту вашего графика и замедлению цикла. Переписать его следующим образом будет более эффективно:

next_computed_features = compute_features(next_datum)
while True:
    try:
        print(sess.run(next_computed_features, options=run_options,
                       run_metadata=run_metadata))
        # ...
    except tf.errors.OutOfRangeError:
        break
person mrry    schedule 09.02.2018