Ответ на ваш основной вопрос: «Как правильно оценивать часть диаграммы tenorflow?»:
Tensorflow включает в себя абстрактный класс, который предоставляет помощники для тестов тензорного потока: Benchmark .
Таким образом, объект Benchmark
может быть создан и использован для выполнения теста на части графа тензорного потока. В приведенном ниже коде создается эталонный объект, а затем вызывается метод run_op_benchmark
. run_op_benchmark
передается сеанс, Тензор conv_block
(в данном случае), feed_dict
, число итераций записи, желаемое минимальное количество итераций, логический флаг, чтобы тест производительности не влиял также на вычисление использования памяти и удобное имя. Метод возвращает словарь, содержащий результаты теста:
benchmark = tf.test.Benchmark()
results = benchmark.run_op_benchmark(sess=sess, op_or_tensor=z_tf,
feed_dict={x_tf: x_np}, burn_iters=2,
min_iters=n_iter,
store_memory_usage=False, name='example')
Этот блок кода может быть вставлен в ваш код следующим образом для сравнения двух тестов:
import os
import time
import numpy as np
import tensorflow as tf
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1'
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
np.random.seed(2020)
def conv_block(x, kernel_size=3):
# Define some part of graph here
bs, h, w, c = x.shape
in_channels = c
out_channels = c
with tf.compat.v1.variable_scope('var_scope'):
w_0 = tf.get_variable('w_0', [kernel_size, kernel_size, in_channels, out_channels], initializer=tf.keras.initializers.glorot_normal())
x = tf.nn.conv2d(x, w_0, [1, 1, 1, 1], 'SAME')
return x
def get_data_batch(spatial_size, n_channels):
bs = 1
h = spatial_size
w = spatial_size
c = n_channels
x_np = np.random.rand(bs, h, w, c)
x_np = x_np.astype(np.float32)
#print('x_np.shape', x_np.shape)
return x_np
def run_graph_part(f_name, spatial_size, n_channels, n_iter=100):
print('=' * 60)
print(f_name.__name__)
tf.reset_default_graph()
with tf.Session() as sess:
x_tf = tf.placeholder(tf.float32, [1, spatial_size, spatial_size, n_channels], name='input')
z_tf = f_name(x_tf)
sess.run(tf.global_variables_initializer())
x_np = get_data_batch(spatial_size, n_channels)
start_time = time.time()
for _ in range(n_iter):
z_np = sess.run(fetches=[z_tf], feed_dict={x_tf: x_np})[0]
avr_time = (time.time() - start_time) / n_iter
print('z_np.shape', z_np.shape)
print('avr_time', round(avr_time, 3))
n_total_params = 0
for v in tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='var_scope'):
n_total_params += np.prod(v.get_shape().as_list())
print('Number of parameters:', format(n_total_params, ',d'))
# USING TENSORFLOW BENCHMARK
benchmark = tf.test.Benchmark()
results = benchmark.run_op_benchmark(sess=sess, op_or_tensor=z_tf,
feed_dict={x_tf: x_np}, burn_iters=2, min_iters=n_iter,
store_memory_usage=False, name='example')
return results
if __name__ == '__main__':
results = run_graph_part(conv_block, spatial_size=128, n_channels=32, n_iter=100)
Эта реализация Класс бенчмаркинга в самой библиотеке tenorflow предоставляет подсказки относительно ответов на другие ваши вопросы. Поскольку реализация тензорного потока не требует использования нового feed_dict
для каждой итерации теста, может показаться, что ответ на вопрос 1) «Хорошо, что x_np
, используемый в l oop, такой же, или мне нужно восстановить его каждый раз? является то, что можно использовать один и тот же x_np
каждый л oop. Что касается вопроса 2), похоже, что необходим некоторый «разогрев». Число итераций записи по умолчанию, предложенное реализацией библиотеки tenorflow, равно 2. Что касается вопроса 3), timeit
является отличным инструментом для измерения времени выполнения небольших фрагментов кода. Однако сама библиотека tenorflow использует time.time()
аналогично тому, что вы сделали: run_op_benchmark
(источник) . Интересно, что реализация эталонного теста тензорного потока сообщает о медиане, а не о среднем времени выполнения операции (предположительно, чтобы сделать эталонный тест более устойчивым к выбросам).