内容简介:本文翻译自:与常规python代码相比,TensorFlow的符号特性使的TensorFlow的代码调试变得相对困难。这里我介绍一些TensorFlow附带的工具,使调试更容易。使用TensorFlow时最常见的错误可能是传递形状错误的张量。许多TensorFlow操作可以在不同秩(rank)和形状(shape)的张量上操作。这在使用API时很方便,但在出现问题时可能会导致额外的麻烦。
本文翻译自: 《Debugging TensorFlow models》 , 如有侵权请联系删除,仅限于学术交流,请勿商用。如有谬误,请联系指出。
与常规 python 代码相比,TensorFlow的符号特性使的TensorFlow的代码调试变得相对困难。这里我介绍一些TensorFlow附带的工具,使调试更容易。
使用TensorFlow时最常见的错误可能是传递形状错误的张量。许多TensorFlow操作可以在不同秩(rank)和形状(shape)的张量上操作。这在使用API时很方便,但在出现问题时可能会导致额外的麻烦。
例如,考虑下面这个 tf.matmul
操作,它可以使两个矩阵相乘:
a = tf.random_uniform([2, 3]) b = tf.random_uniform([3, 4]) c = tf.matmul(a, b) # c is a tensor of shape [2, 4] 复制代码
但是下面这个函数也可以实现矩阵乘法:
a = tf.random_uniform([10, 2, 3]) b = tf.random_uniform([10, 3, 4]) tf.matmul(a, b) # c is a tensor of shape [10, 2, 4] 复制代码
下面是我们之前在广播部分谈到的一个支持广播的添加操作的例子:
a = tf.constant([[1.], [2.]]) b = tf.constant([1., 2.]) c = a + b # c is a tensor of shape [2, 2] 复制代码
使用 tf.assert *
操作验证您的张量
减少不必要行为可能性的一种方法是使用 tf.assert *
操作验证中间张量的秩(rank)或形状(shape)。
a = tf.constant([[1.], [2.]]) b = tf.constant([1., 2.]) check_a = tf.assert_rank(a, 1) # This will raise an InvalidArgumentError exception check_b = tf.assert_rank(b, 1) with tf.control_dependencies([check_a, check_b]): c = a + b # c is a tensor of shape [2, 2] 复制代码
请记住,断言节点和其他操作一样都属于TensorFlow中图(Graph)的一部分,如果不进行评估,则会在执行 Session.run()
期间进行剔除。因此,请确保为断言操作创建显式依赖项,以强制TensorFlow执行它们。
你还可以在运行时使用断言验证张量的值:
check_pos = tf.assert_positive(a) 复制代码
有关断言操作的详细信息,请参阅官方文档。
使用 tf.Print
打印张量值
另一个对调试有帮助的内置函数是 tf.Print
,它可以将给定的张量记录到标准错误堆栈中:
input_copy = tf.Print(input, tensors_to_print_list) 复制代码
注意一下, tf.Print
函数将其第一个参数的副本作为返回值输出。一种让 tf.Print
强制运行的方式是将其输出传递给另一个操作去执行。例如,如果我们想在添加它们之前就打印张量a和b的值,我们可以这样做:
a = ... b = ... a = tf.Print(a, [a, b]) c = a + b 复制代码
或者,我们可以手动定义控件依赖项。
利用 tf.compute_gradient_error
检查梯度变化的值
并不是TensorFlow中的所有操作都有梯度变化,并且很容易在无意中构建出TensorFlow无法计算梯度变化的图。
让我们来看个例子:
import tensorflow as tf def non_differentiable_softmax_entropy(logits): probs = tf.nn.softmax(logits) return tf.nn.softmax_cross_entropy_with_logits(labels=probs, logits=logits) w = tf.get_variable("w", shape=[5]) y = -non_differentiable_softmax_entropy(w) opt = tf.train.AdamOptimizer() train_op = opt.minimize(y) sess = tf.Session() sess.run(tf.global_variables_initializer()) for i in range(10000): sess.run(train_op) print(sess.run(tf.nn.softmax(w))) 复制代码
我们正在使用 tf.nn.softmax_cross_entropy_with_logits
定义一个分类分布上的熵。然后我们使用Adam优化器来找到具有最大熵的权重。如果你通过了信息论的课程,你就会知道均匀分布包含最大熵。所以你预计他的结果应该会是 [0.2, 0.2, 0.2, 0.2, 0.2]
。但是你执行这段代码的话会得到一个你意想不到的结果:
[ 0.34081486 0.24287023 0.23465775 0.08935683 0.09230034] 复制代码
事实证明, tf.nn.softmax_cross_entropy_with_logits
对标签有未定义的梯度变化!但是,如果我们不知道这个现象,我们又怎么能发现这个问题呢?
幸运的是,TensorFlow带有一个数值微分器,可用于查找符号梯度误差。让我们看看我们如何使用它:
with tf.Session(): diff = tf.test.compute_gradient_error(w, [5], y, []) print(diff) 复制代码
如果你运行它,你会发现数值和符号之间的差异非常大(我试了下大约为0.06 - 0.1)。
现在让我们更改下我们的函数并再次执行下:
import tensorflow as tf import numpy as np def softmax_entropy(logits, dim=-1): plogp = tf.nn.softmax(logits, dim) * tf.nn.log_softmax(logits, dim) return -tf.reduce_sum(plogp, dim) w = tf.get_variable("w", shape=[5]) y = -softmax_entropy(w) print(w.get_shape()) print(y.get_shape()) with tf.Session() as sess: diff = tf.test.compute_gradient_error(w, [5], y, []) print(diff) 复制代码
差异应该在0.0001左右,这个结果看起来好多了。
现在,如果再次使用正确的版本运行优化器,你可以看到最终权重为:
[ 0.2 0.2 0.2 0.2 0.2] 复制代码
这就是我们想要的答案。
TensorFlow summaries 和 tfdbg(TensorFlow Debugger) 是另外两个用于调试的工具,请参阅官方文档以了解更多信息。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] 深度学习的模型调试小技巧
- 学习笔记TF016:CNN实现、数据集、TFRecord、加载图像、模型、训练、调试
- Stanford NLP 解读 ACL 2018 论文——用于调试 NLP 模型的语义等价对立规则
- iOS常用调试方法:断点调试
- 断点调试和日志调试之间的平衡点:函数计算调试之 Python 篇
- .NET高级调试系列-Windbg调试入门篇
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。