Debugging TensorFlow Programs(调试TensorFlow程序)

调试TensorFlow程序

TensorFlow 调试器(tfdbg)是 TensorFlow 的专用调试器。它允许您在训练和推理期间查看运行 TensorFlow 图形的内部结构和状态,由于 TensorFlow 的计算图范例,使用通用调试器很难调试Pythonpdb

注意:支持的外部平台上的tfdbg的系统要求包括以下内容。在Mac OS X上,该ncurses库是必需的。它可以安装brew install homebrew/dupes/ncurses。在Windows上,pyreadline是必需的。如果你使用Anaconda3,你可以使用一个命令来安装它"C:\Program Files\Anaconda3\Scripts\pip.exe" install pyreadline

本教程演示如何使用tfdbg命令行界面(CLI)调试naninf的外观,这是TensorFlow模型开发中经常遇到的一种错误类型。以下示例适用于使用SessionTensorFlow 的低级API的用户。本文后面的部分将介绍如何将tfdbg与更高级别的API一起使用,即tf-learn Estimators和Experiment。要观察这样的问题,请在没有调试器的情况下运行以下命令(可以在此处找到源代码):

python -m tensorflow.python.debug.examples.debug_mnist

该代码为MNIST数字图像识别训练一个简单的神经网络。请注意,在第一个训练步骤之后,准确度略有增加,但之后会陷入低(几乎偶然)的水平:

Accuracy at step 0: 0.1113 Accuracy at step 1: 0.3183 Accuracy at step 2: 0.098 Accuracy at step 3: 0.098 Accuracy at step 4: 0.098

想知道可能发生了什么问题,您怀疑训练图中的某些节点会生成错误的数值,如infs和nans,因为这是此类训练失败的常见原因。让我们使用tfdbg来调试这个问题,并确定出现这个数字问题的确切图节点。

用tfdbg包装TensorFlow会话

为了在我们的例子中添加对tfdbg的支持,所需要的就是添加下面的代码行并用调试器包装器来包装Session对象。该代码已添加到debug_mnist.py中,因此您可以通过--debug命令行中的标志激活tfdbg CLI 。

# Let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug sess = tf_debug.LocalCLIDebugWrapperSession(sess)

这个包装与Session具有相同的接口,因此启用调试时不需要对代码进行其他更改。包装提供了其他功能,包括:

  • Session.run()调用之前和之后调用CLI ,让您控制执行并检查图形的内部状态。

在这个例子中,我们已经注册了一个张量过滤器称为tfdbg.has_inf_or_nan,它可以简单地确定是否存在任何中间张量中的任何值naninf张量(张量既不是Session.run()调用的输入或输出,也是从输入到输出的路径中)。这个过滤器是用于nans和infs的,它是我们随debug_data模块一起交付的常见用例。

注意:您也可以编写自己的自定义过滤器。请参阅API文档的DebugDumpDir.find()附加信息。

用tfdbg调试模型训练

让我们再次尝试训练模型,但这次--debug添加了标志:

python -m tensorflow.python.debug.examples.debug_mnist --debug

调试包装会话将在您要执行第一次Session.run()调用时提示您,并提供有关屏幕上显示的提取张量和Feed字典的信息。

这就是我们所说的运行启动CLI。它Session.run在执行任何事情之前列出了当前调用的提要和提取。

如果屏幕尺寸太小而无法全部显示信息内容,则可以调整它的大小。

使用PageUp / PageDown / Home / End键导航屏幕输出。在大多数键盘上缺少这些键Fn + Up / Fn + Down / Fn + Right / Fn + Left将会起作用。

在命令提示符处输入run命令(或者只是r):

tfdbg> run

run命令会导致tfdbg执行,直到下一次Session.run()调用结束,该调用将使用测试数据集计算模型的准确性。tfdbg扩展运行时图形来转储所有中间张量。运行结束后,tfdbg会在运行端CLI中显示所有转储的张量值。例如:

这张张量列表也可以在你执行run之后通过运行命令lt获得

tfdbg CLI经常使用的命令

在tfdbg>提示符下引用以下命令(引用代码tensorflow/python/debug/examples/debug_mnist.py):

命令语法或选项说明
It列举转储张量。It
-n <name_pattern>列出具有匹配给定正则表达式模式的名称的转储张量。lt -n Softmax.*
-t <op_pattern>列出具有匹配给定正则表达式模式的op类型的转储张量。lt -t MatMul
-s <sort_key>按给定的sort_key对输出进行排序,其可能的值是timestamp(缺省值),dump_size,op_type和tensor_name。lt -s dump_size
-r按相反顺序排序。lt -r -s dump_size
pt转储张量的打印值。
pt <张量>打印张量值。hidden/Relu:0
pt <张量>切片使用numpy样式阵列切片打印张量子阵列。pt hidden/relay:00:50, :
-a打印整个大张量,而不使用椭圆。(可能需要很长时间才能获得较大张量。)pt -a hidden/Relu:00:50, :
-r <范围>突出显示落入指定数值范围的元素。多个范围可以结合使用。pt hidden/Relu:0 -a -r [-inf,-1,1,inf]
-s包括张量数值的摘要(仅适用于布尔型和数值型非空张量,如int *和float *)。pt -s hidden/Relu:00:50, :
@coordinates导航到pt输出中的指定元素。@ 10,0 or @ 10,0
/regex给定正则表达式的风格较少的搜索。/INF
/滚动到搜索正则表达式匹配的下一行(如果有的话)。/
pf在Session.run的feed_dict中打印一个值。
pf <feed_tensor_name>打印feed_dict的值。另请注意,pf命令具有-a,-r和-s标志(未在下面列出),它们与pt的同名标志具有相同的语法和语义。pf input_xs:0
eval评估任意Python和numpy表达式。
eval <表达式>评估一个Python/numpy表达式,numpy可用作np并调试反引号中的张量名称。eval "np.matmul(( output/Identity:0 / Softmax:0 ).T, Softmax:0 )"
-a全面打印大型评估结果,即不使用省略号。eval -a 'np.sum(Softmax:0, axis = 1)'
ni显示节点信息。
-a在输出中包含节点属性。ni -a hidden/Relu
-d列出节点中可用的调试转储。ni -d hidden/Relu
-t显示节点创建的Python堆栈跟踪。ni -t hidden/Relu
li列出节点的输入
-r递归地列出节点的输入(输入树)。li -r hidden/ Relu:0
-d <max_depth>在-r模式下限制递归深度。li -r -d 3 hidden/Relu:0
-c包含控制输入。li -c -r hidden/Relu:0
lo列出节点的输出收件人
-r递归列出节点的输出接收者(输出树)。lo -r hidden/Relu:0
-d <max_depth>在-r模式下限制递归深度。lo -r -d 3 hidden/Relu:0
-c通过控制边包括收件人。lo -c -r hidden/Relu:0
ls列出参与节点创建的Python源文件。
-p <路径模式>将输出限制为与给定正则表达式路径模式匹配的源文件。ls -p .* debug_mnist.*
-n将输出限制为与给定正则表达式模式匹配的节点名称。ls -n Softmax.*
ps打印Python源文件。
ps <文件路径>打印给定的Python源文件source.py,并用每个节点创建的节点注释行(如果有的话)。ps /path/to/source.py
-t对Tensors执行注释,而不是默认的节点。ps -t /path/to/source.py
-b <line_number>从给定的行开始注释source.py。ps -b 30 /path/to/source.py
-m <max_elements>限制每行的注释中的元素数量。ps -m 100 /path/to/source.py
run继续下一个Session.run()run
-n在没有调试的情况下执行下一个Session.run,然后在运行之前立即下降到CLI。 run -n
-t <T>在没有调试的情况下执行Session.run T-1次,然后运行调试。然后在调试运行后立即下降到CLI。 run -t 10
-f <filter_name>继续执行Session.run,直到任何中间张量触发指定的张量过滤器(导致过滤器返回True)。 run -f has_inf_or_nan
--node_name_filter <pattern>执行下一个Session.run,仅查看名称与给定的正则表达式模式匹配的节点。 run --node_name_filter Softmax.*
--op_type_filter <pattern>执行下一个Session.run,只观察op类型与给定正则表达式模式匹配的节点。 run --op_type_filter Variable.*
--tensor_dtype_filter <pattern>执行下一个Session.run,只转储数据类型(dtypes)与给定正则表达式模式匹配的张量。run --tensor_dtype_filter int.*
-p在分析模式下执行下一个Session.run调用。run -p
ri显示有关运行当前运行的信息,包括提取和提要。ri
help打印一般帮助信息help
help <command>打印给定命令的帮助。help it

请注意,每次输入命令时,都会显示新的屏幕输出。这有点类似于浏览器中的网页。您可以通过点击这些屏幕间导航<--和-->附近的CLI的左上角的文字箭头。

tfdbg CLI的其他功能

除了上面列出的命令外,tfdbg CLI还提供了以下附加功能:

  • 要浏览以前的tfdbg命令,请输入几个字符,然后按向上或向下箭头键。tfdbg将向您显示以这些字符开始的命令的历史记录。

tfdbg> pt cross_entropy/Log:0[:, 0:10] > /tmp/xent_value_slices.txt

寻找nans和infs

在第一次Session.run()调用中,碰巧没有问题的数值。您可以使用该命令run或其简写形式继续下一次运行r

提示:如果您输入run或r重复输入,您将能够以Session.run()顺序方式移动呼叫。您也可以使用该-t标志一次向前移动多个Session.run()呼叫,例如:tfdbg> run -t 10

在每次调用之后(例如,通过使用上表中显示的命令),可以使用以下命令让调试器在不停止的情况下重复执行调用,而不是在运行结束UI中run反复输入和手动搜索nans和infs 在运行开始或运行结束提示符下,直到第一个或值出现在图中。这类似于某些过程式语言调试器中的条件断点Session.run()ptSession.run()naninf

tfdbg> run -f has_inf_or_nan

注:上述命令可正常工作,因为has_inf_or_nan创建包装会话时已为您注册称为张量过滤器。这个过滤器检测nans和infs(如前所述)。如果您已注册任何其他过滤器,则可以使用“run -f”使tfdbg运行,直到任何张量触发该过滤器(导致过滤器返回True)。def my_filter_callable(datum,tensor):#一个检测零值标量的过滤器。返回len(tensor.shape)== 0和张量== 0.0 sess.add_tensor_filter('my_filter',my_filter_callable)然后在tfdbg运行启动提示符运行,直到触发过滤器:tfdbg> run -f my_filter

请参见本API文档的谓词的预期的签名和返回值的详细信息Callable与使用add_tensor_filter()

当屏幕显示在第一行显示时,has_inf_or_nan过滤器在第四次Session.run()调用期间首先被触发:图表上的亚当优化器前向 - 后向训练过程。在这个运行中,36个(全部95个)中间张量包含naninf值。这些张量按时间顺序列出,其时间戳显示在左侧。在列表顶部,您可以看到第一个张量,其中不良数值首先出现:cross_entropy/Log:0

要查看张量的值,请单击带下划线的张量名称cross_entropy/Log:0或输入等效命令:

tfdbg> pt cross_entropy/Log:0

向下滚动一下,你会发现一些分散的inf值。如果实例inf和实例nan很难找到,可以使用以下命令执行正则表达式搜索并突出显示输出:

tfdbg> /inf

Or, alternatively:

tfdbg> /(inf|nan)

您还可以使用-s--numeric_summary命令快速总结张量中的数值类型:

tfdbg> pt -s cross_entropy/Log:0

从总结中,可以看到cross_entropy/Log:0张量的1000个元素中有几个是-infs(负无穷)。

为什么会出现这些无穷大?要进一步调试,cross_entropy/Log通过单击node_info顶部带下划线的菜单项或输入等效的node_infoni)命令来显示有关节点的更多信息:

tfdbg> ni cross_entropy/Log

您可以看到该节点具有操作类型Log,并且其输入是节点softmax/Softmax。运行以下命令仔细查看输入张量:

tfdbg> pt softmax/Softmax:0

检查输入张量中的值,搜索零:

tfdbg> /0\.000

确实有零。现在很明显,错误的数值的起源是节点cross_entropy/Log取零的日志。要找出Python源代码中的罪魁祸首,使用-tni命令的标志来显示节点构造的回溯:

tfdbg> ni -t cross_entropy/Log

如果您单击屏幕顶部的“node_info”,tfdbg会自动显示节点构造的回溯。

从回溯中,您可以看到op在以下行构建debug_mnist.py::

diff = y_ * tf.log(y)

tfdbg具有一个功能,可以很容易地将张量和操作追溯回Python源文件中的行。它可以用它们创建的ops或Tensors注释Python文件的行。要使用此功能,只需单击ni -t <op_name>命令的堆栈跟踪输出中带下划线的行号,或使用ps(或print_source)命令(如:)ps /path/to/source.py。例如,以下屏幕截图显示了ps命令的输出。

解决问题

要解决该问题,请编辑debug_mnist.py,更改原始行:

diff = -(y_ * tf.log(y))

到Softmax交叉熵的内置数值稳定实现:

diff = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=logits)

重新运行--debug标志如下:

python -m tensorflow.python.debug.examples.debug_mnist --debug

在tfdbg>提示符处输入以下命令:

run -f has_inf_or_nan`

确认没有张量被标记为包含naninf值,并且精度现在继续上升而不是卡住。成功!

调试tf-learn估计器和实验

本节介绍如何调试使用EstimatorExperimentAPI的TensorFlow程序。这些API提供的部分便利是它们Session在内部管理。这使得LocalCLIDebugWrapperSession前面几节中的描述不适用。幸运的是,您仍然可以使用hook提供的特殊s 来调试它们tfdbg

调试tf.contrib.learn估计器

目前,tfdbg可以调试tf-learn 的方法。要进行调试,请在参数中创建并提供它。例如:fit() evaluate()EstimatorEstimator.fit()LocalCLIDebugHookmonitors

# First, let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug # Create a LocalCLIDebugHook and use it as a monitor when calling fit(). hooks = [tf_debug.LocalCLIDebugHook()] classifier.fit(x=training_set.data, y=training_set.target, steps=1000, monitors=hooks)

要进行调试Estimator.evaluate(),请将挂钩分配给该hooks参数,如下例所示:

accuracy_score = classifier.evaluate(x=test_set.data, y=test_set.target, hooks=hooks)["accuracy"]

debug_tflearn_iris.py,基于{$ tflearn $ tflearn的虹膜教程},包含如何使用tfdbg一个完整的例子Estimator秒。要运行这个例子,请执行:

python -m tensorflow.python.debug.examples.debug_tflearn_iris --debug

调试tf.contrib.learn实验

Experiment是一个tf.contrib.learn比更高层次的构造Estimator。它提供了一个用于培训和评估模型的单一界面。要调试train()evaluate()调用Experiment对象,可以分别在调用其构造函数时使用关键字参数train_monitorseval_hooks。例如:

# First, let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug hooks = [tf_debug.LocalCLIDebugHook()] ex = experiment.Experiment(classifier, train_input_fn=iris_input_fn, eval_input_fn=iris_input_fn, train_steps=FLAGS.train_steps, eval_delay_secs=0, eval_steps=1, train_monitors=hooks, eval_hooks=hooks) ex.train() accuracy_score = ex.evaluate()["accuracy"]

debug_tflearn_irisExperiment模式下构建和运行示例,请执行以下操作:

python -m tensorflow.python.debug.examples.debug_tflearn_iris \ --use_experiment --debug

LocalCLIDebugHook也允许你配置一个watch_fn可以用来灵活指定Tensor在不同的Session.run()调用中看什么的函数,这是fetchesfeed_dict和其他状态的函数。有关更多详情,请参阅此API文档。

用TFDBG调试Keras模型

若要使用TFDBG Keras,让Keras后端使用TFDBG包裹的Session对象。例如,要使用CLI包装器:

import tensorflow as tf from keras import backend as keras_backend from tensorflow.python import debug as tf_debug keras_backend.set_session(tf_debug.LocalCLIDebugWrapperSession(tf.Session())) # Define your keras model, called "model". model.fit(...) # This will break into the TFDBG CLI.

用TFDBG调试tf-slim

TFDBG目前仅支持tf-slim培训训练。要调试训练过程中,提供LocalCLIDebugWrapperSessionsession_wrapper的说法slim.learning.train()。例如:

import tensorflow as tf from tensorflow.python import debug as tf_debug # ... Code that creates the graph and the train_op ... tf.contrib.slim.learning_train( train_op, logdir, number_of_steps=10, session_wrapper=tf_debug.LocalCLIDebugWrapperSession)

脱机调试远程运行会话

通常,您的模型运行在远程机器上或您没有终端访问权限的进程中。要在这种情况下执行模型调试,可以使用offline_analyzer(在下面描述)的offline_analyzer二进制tfdbg。它在转储的数据目录上运行。这可以针对较低级别的SessionAPI以及较高级别的API EstimatorExperimentAPI来完成。

调试远程tf.Sessions

如果您直接与tf.SessionAPI 交互,则python可以使用该方法配置RunOptions您调用Session.run()方法的原型tfdbg.watch_graph。这会导致中间张量和运行时图形在Session.run()调用发生时转储到您选择的共享存储位置(代价是性能较低)。例如:

from tensorflow.python import debug as tf_debug # ... Code where your session and graph are set up... run_options = tf.RunOptions() tf_debug.watch_graph( run_options, session.graph, debug_urls=["file:///shared/storage/location/tfdbg_dumps_1"]) # Be sure to specify different directories for different run() calls. session.run(fetches, feed_dict=feeds, options=run_options)

稍后,在您有终端访问权的环境中(例如,可以访问上面代码中指定的共享存储位置的本地计算机),您可以使用以下命令加载和检查共享存储上转储目录中的数据offline_analyzer二进制tfdbg。例如:

python -m tensorflow.python.debug.cli.offline_analyzer \ --dump_dir=/shared/storage/location/tfdbg_dumps_1

Session包装DumpingDebugWrapperSession提供了一种更简单,更灵活的方式来生成可脱机分析的文件系统转储。要使用它,只需将会话包装在一个tf_debug.DumpingDebugWrapperSession。例如:

# Let your BUILD target depend on "//tensorflow/python/debug:debug_py # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug sess = tf_debug.DumpingDebugWrapperSession( sess, "/shared/storage/location/tfdbg_dumps_1/", watch_fn=my_watch_fn)

watch_fn参数接受一个Callable是允许您配置什么tensors到观看不同的Session.run()调用,fetches的功能,并feed_dictrun()调用和其他国家。

C ++和其他语言

如果您的模型代码是用C ++或其他语言编写的,那么您还可以修改该debug_options字段RunOptions以生成可以脱机检查的调试转储。有关更多详细信息,请参阅原型定义。

调试远程运行tf-learn估计器和实验

如果您的远程TensorFlow服务器运行Estimators,则可以使用非交互式DumpingDebugHook。例如:

# Let your BUILD target depend on "//tensorflow/python/debug:debug_py # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug hooks = [tf_debug.DumpingDebugHook("/shared/storage/location/tfdbg_dumps_1")]

然后,hook可以按照LocalCLIDebugHook本文档前面所述示例的相同方式使用它。由于训练和/或评价; Estimator或Experiment发生,tfdbg创建具有下列名称模式目录:/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>。每个目录对应于Session.run()呼叫fit()或evaluate()调用的基础。您可以使用offline_analyzertfdbg提供的离线方式加载这些目录并在命令行界面中检查它们。例如:

python -m tensorflow.python.debug.cli.offline_analyzer \ --dump_dir="/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>"

经常问的问题

输出左侧的时间戳是否 反映了非调试会话中的实际性能?

:不可以。调试器会在图表中插入额外的专用调试节点来记录中间张量的值。这些节点减慢了图形的执行速度。如果您对分析模型感兴趣,请查看

  • tfdbg的分析模式:tfdbg> run -p。

我如何将tfdbg与 Bazel中的我联系起来?为什么我会看到如“ImportError:无法导入名称调试”的错误?Session

:在您的BUILD规则中,声明依赖关系:"//tensorflow:tensorflow_py""//tensorflow/python/debug:debug_py"。首先是即使没有调试器支持,也包括使用TensorFlow的依赖关系; 第二个启用调试器。然后,在你的Python文件中,添加:

from tensorflow.python import debug as tf_debug # Then wrap your TensorFlow Session with the local-CLI wrapper. sess = tf_debug.LocalCLIDebugWrapperSession(sess)

tfdbg是否可以帮助调试运行时错误,例如形状不匹配?

:是的。tfdbg在运行时拦截ops生成的错误,并在CLI中向用户显示一些调试指令的错误。看例子:

# Debugging shape mismatch during matrix multiplication. python -m tensorflow.python.debug.examples.debug_errors \ --error shape_mismatch --debug # Debugging uninitialized variable. python -m tensorflow.python.debug.examples.debug_errors \ --error uninitialized_variable --debug

如何让我的tfdbg包装的Sessions或Hooks只从主线程运行调试模式?

:这是一个常见的用例,其中Session对象是从多个线程并发使用的。通常,子线程负责后台任务,如运行入队操作。通常情况下,您只想调试主线程(或者不太频繁,只有一个子线程)。您可以使用thread_name_filter关键字参数LocalCLIDebugWrapperSession来实现这种类型的线程选择性调试。例如,要仅从主线程调试,请Session按如下所示构造一个包装:

sess = tf_debug.LocalCLIDebugWrapperSession(sess, thread_name_filter="MainThread$")

上面的例子依赖于Python中的主线程具有默认名称MainThread的事实。

我正在调试的模型非常大。tfdbg转储的数据填满了我磁盘的可用空间。我能做什么?

:在以下任何情况下,您可能会遇到此问题:

  • 具有许多中间张量的模型

有三种可能的解决方法或解决方案:

  • 构造函数LocalCLIDebugWrapperSessionLocalCLIDebugHook提供关键字参数,dump_root以指定tfdbg转储调试数据的路径。您可以使用它来让tfdbg将调试数据转储到具有较大可用空间的磁盘上。例如:

# For LocalCLIDebugHook hooks = [tf\_debug.LocalCLIDebugHook(dump\_root="/with/lots/of/space")] `&grave;&grave; Make sure that the directory pointed to by dump_root is empty or nonexistent. tfdbg cleans up the dump directories before exiting. * Reduce the batch size used during the runs. * Use the filtering options of tfdbg's`run` command to watch only specific nodes in the graph. For example: `tfdbg> run --node_name_filter .*hidden.* tfdbg> run --op_type_filter Variable.* tfdbg> run --tensor_dtype_filter int.*` The first command above watches only nodes whose name match the regular-expression pattern `.*hidden.*`. The second command watches only operations whose name match the pattern `Variable.*`. The third one watches only the tensors whose dtype match the pattern `int.*` (e.g., `int32`). **Q**: _Why can't I select text in the tfdbg CLI?_ **A**: This is because the tfdbg CLI enables mouse events in the terminal by default. This [mouse-mask](https://linux.die.net/man/3/mousemask) mode overrides default terminal interactions, including text selection. You can re-enable text selection by using the command `mouse off` or `m off`. **Q**: _Why does the tfdbg CLI show no dumped tensors when I debug code like the following?_ ```javascript

a = tf.ones(10, name="a")

b = tf.add(a, a, name="b")

sess = tf.Session()

sess = tf_debug.LocalCLIDebugWrapperSession(sess)

sess.run(b)

**A**: The reason why you see no data dumped is because every node in the executed TensorFlow graph is constant-folded by the TensorFlow runtime. In this exapmle, `a` is a constant tensor; therefore, the fetched tensor `b` is effectively also a constant tensor. TensorFlow's graph optimization folds the graph that contains `a` and `b` into a single node to speed up future runs of the graph, which is why `tfdbg` does not generate any intermediate tensor dumps. However, if `a` were a [`tf.Variable`](https://www.tensorflow.org/api_docs/python/tf/Variable), as in the following example: ```javascript

import numpy as np

a = tf.Variable(np.ones10, name="a")

b = tf.add(a, a, name="b")

sess = tf.Session()

sess.run(tf.global_variables_initializer())

sess = tf_debug.LocalCLIDebugWrapperSession(sess)

sess.run(b)

恒定折叠不会发生,并tfdbg应显示中间张量转储。