使用tf.profiler监控图
参考:
1. 引入相关包
import tensorflow as tf
from tensorflow.python.profiler import model_analyzer
from tensorflow.python.profiler import option_builder
注意:只有tf 1.3以上的版本才有profiler功能
2. 创建相关实例
#... 省略图的构建代码...
sess.run(init) # 初始化变量
graph_profiler = model_analyzer.Profiler(graph=sess.graph)# 创建tf.profiler实例,作为记录、处理和显示数据的主体
run_metadata = tf.RunMetadata() # 创建RunMetadata, 用于在每次session.Run()时汇总统计数据
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)#定义trace level为FULL_TRACE,这样我们才能搜集到包括GPU硬件在内的最全统计数据
3. 执行sess.run,在想要记录的iteration中搜集统计数据并添加到tfprofiler实例中
feed_dict = dict()
for step in range(max_step):
feed_dict = {
images_placeholder: images_feed,
labels_placeholder: labels_feed,
}
if step % 5 == 0:
_, loss_value = sess.run(fetches=[train_op, loss],feed_dict=feed_dict, options=run_options, run_metadata=run_metadata)#每 5步,搜集一下统计数据:
#将本步搜集的统计数据添加到tfprofiler实例中
graph_profiler.add_step(step=step, run_meta=run_metadata)
else:
_, loss_value = sess.run(fetches=[train_op, loss],
feed_dict=feed_dict)
4. 定义option
option用于设置过滤条件、显示字段,完整option 参见Options
比较常用的有:
=========================Options=============================
- max_depth 4 命名空间的深度阈值,超过该阈值的分支不予展示
- min_bytes 0 展示占用内存超过该阈值的OP
- min_micros 10 展示耗时超过该阈值的OP
- min_params 0 展示超过该阈值的参数大小的OP
- min_float_ops 0 展示超过该阈值的浮点计算量的 OP
- min_occurrence 0 展示超过该阈值的出现次数的 OP
- step -1 展示训练时候哪一步的统计情况,默认为最后一步
- order_by micros 统计结果排序字段设定
- account_type_regexes _trainable_variables
#Selectively counting statistics based on node types ,比如这里设定展示可训练变量;account_type_regexes=['.*gpu:0.*'] 设定展示 GPU 运行的变量;
以下四个选项可以更加灵活的设置展示哪些 OP
- start_name_regexes .* #从哪儿可以开始匹配
- trim_name_regexes #从哪儿停止匹配
- show_name_regexes siamese.* #展示什么字段的 OP
- hide_name_regexes #隐藏什么字段的 OP
- account_displayed_op_only false
- select micros 选择展示的属性,这里选择查看计算耗时(micros)/查看内存占用则设置为bytes,
- output stdout: 输出方式,这里是标准输出
下面为一个例子:
# a readout of memory usage for each node in graph
profile_scope_opts_builder = option_builder.ProfileOptionBuilder(
option_builder.ProfileOptionBuilder.trainable_variables_parameter())
# set to timeline output
profile_scope_opts_builder.with_timeline_output(timeline_file='/tmp/train_profiler.json')
profile_scope_opts_builder.with_min_memory(min_bytes=1024*1024) # only show >1Mb
profile_scope_opts_builder.select(['params','bytes','input_shapes','micros','device'])
profile_scope_opt_builder.order_by('bytes')
其中with_timeline_output表示要以Timeline形式输出,可选的方法还有:
- with_file_output(outfile=”filename”) # 以文件形式输出
- with_stdout_output() # print输出
6.选择视图模式
tf.Profiler有4种视图模式为:
- ‘code’: 统计按照每行代码进行聚集,最终看到的是每行代码的耗时和内存占用;
- ‘op’: 统计按照每种OP 的类型,最终看到每种操作耗时和内存占用;
- ‘scope’: 统计按照命名空间的层级进行,最后看到每个命名空间及其子空间的情况;
- ‘graph’: 统计按照计算图上的顺序进行,也就是每个节点的输入输出等情况; 各模式的详情例子见上面的参考blog链接
一下我们选择‘scope’模式
graph_profiler.profile_name_scope(profile_scope_opt_builder.build())
其它模式对应的函数为:
- ‘code’: profile_python(builder.build())
- ‘op’: profile_operations(builder.build())
- ‘scope’: profile_name_scope(builder.build())
- ‘graph’: profile_graph(builder.build())
5. 查看记录内容
在运行我们的python程序后,我们就可以在浏览器中查看profiler记录的内容:
打开chrome浏览器,输入about:tracing, 然后load “/tmp/train_profiler.json” 文件,显示如图:
不幸的是,如果你是在服务器上运行的程序,你只能在将服务器上的“/tmp/train_profiler.json”下载到本地,然后再进行查看。
6. 我遇到的bug
运行程序时出现错误提示:
Couldn't open CUDA library libcupti.so.8.0. LD_LIBRARY_PATH: /usr/local/cuda/lib64:
解决方法: 根据提示,应该是LD_LIBRARY_PATH的路径不太对,现有路径“/usr/local/cuda/lib64:”下为cuda 9.0 版本,因此需要修改LD_LIBRARY_PATH中的内容
直接修改LD_LIBRARY_PATH内容可能会有一定的风险,(也有权限等问题),所以建议修改当前用户的.bashrc 文件:
# 在.bashrc中添加下面这行
export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/extras/CUPTI/lib64/
# 或者添加下面这一行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/extras/CUPTI/lib64/
其中[/usr/local/cuda-8.0/lib64]是linux中cuda 8.0的位置,[/usr/local/cuda-8.0/extras/CUPTI/lib64/]是linux中libcupti.so.8.0的位置。
当然,如果你没有安装cuda 8.0,那就从安装cuda开始吧。
后记
后来我发现了有比上面更简便的方法,但所谓简便,即封装的更好,灵活性也就更差,但仍记录在此,以防以后忘记。
1. 引入相关包
import tensorflow as tf
2. 创建option实例,并进行相关设置
# Create options to profile the time and memory information.
builder = tf.profiler.ProfileOptionBuilder
builder_opts = builder(builder.time_and_memory())
# builder_opts = builder(builder.time_and_memory())
builder_opts.with_timeline_output(timeline_file='tmp/%s_profiler.json'%FLAGS.dataset)
builder_opts.with_min_memory(min_bytes=1024*1024) # only show >1Mb
builder_opts.select(['params','bytes','input_shapes','micros','device'])
builder_opts.order_by('bytes')
builder_opts = builder_opts.build()
3. 使用tfprof进行变量跟踪
with tf.contrib.tfprof.ProfileContext('tmp/%s_profiler.json'%FLAGS.dataset, trace_steps=range(0,20,5), dump_steps=range(0,20,5)) as pctx:
# Initialize session
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
with tf.Session(config=config) as sess:
# Init variables
sess.run(tf.global_variables_initializer())
# Enable tracing for next session.run.
pctx.trace_next_step()
# Dump the profile to '/tmp/train_dir' after the step.
pctx.dump_next_step()
for epoch in range(FLAGS.epochs):
outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict)
pctx.profiler.profile_graph(options=builder_opts)
# pctx.add_auto_profiling('op', builder_opts, [1, 9, 19])
4. 查看记录内容
这一步跟之前一模一样。