1 # Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ============================================================================== 15 """Unit tests for debug_gradients module.""" 16 17 from __future__ import absolute_import 18 from __future__ import division 19 from __future__ import print_function 20 21 import shutil 22 import tempfile 23 24 from tensorflow.core.protobuf import config_pb2 25 from tensorflow.core.protobuf import rewriter_config_pb2 26 from tensorflow.python.client import session 27 from tensorflow.python.debug.lib import debug_data 28 from tensorflow.python.debug.lib import debug_gradients 29 from tensorflow.python.debug.lib import debug_utils 30 from tensorflow.python.framework import ops 31 from tensorflow.python.framework import test_util 32 from tensorflow.python.ops import gradients_impl 33 from tensorflow.python.ops import math_ops 34 from tensorflow.python.ops import variables 35 from tensorflow.python.platform import googletest 36 from tensorflow.python.training import gradient_descent 37 38 39 class IdentifyGradientTest(test_util.TensorFlowTestCase): 40 41 def setUp(self): 42 rewriter_config = rewriter_config_pb2.RewriterConfig( 43 disable_model_pruning=True, 44 dependency_optimization=rewriter_config_pb2.RewriterConfig.OFF) 45 graph_options = config_pb2.GraphOptions(rewrite_options=rewriter_config) 46 config = config_pb2.ConfigProto(graph_options=graph_options) 47 self.sess = session.Session(config=config) 48 with self.sess.as_default(): 49 self.u = variables.Variable(2.0, name="u") 50 self.v = variables.Variable(3.0, name="v") 51 self.w = math_ops.multiply(self.u.value(), self.v.value(), name="w") 52 53 def tearDown(self): 54 ops.reset_default_graph() 55 debug_gradients.clear_gradient_debuggers() 56 57 def testIdentifyGradientGivesCorrectTensorObjectWithoutContextManager(self): 58 grad_debugger = debug_gradients.GradientsDebugger() 59 id_grad_w = grad_debugger.identify_gradient(self.w) 60 y = math_ops.add(id_grad_w, -1.0, name="y") 61 62 grads = gradients_impl.gradients(y, [self.u, self.v]) 63 self.assertEqual(2, len(grads)) 64 u_grad = grads[0] 65 v_grad = grads[1] 66 67 self.sess.run(variables.global_variables_initializer()) 68 self.assertAllClose(5.0, self.sess.run(y)) 69 self.assertAllClose(3.0, self.sess.run(u_grad)) 70 self.assertAllClose(2.0, self.sess.run(v_grad)) 71 72 # Fetch the gradient tensor with the x-tensor object. 73 w_grad = grad_debugger.gradient_tensor(self.w) 74 self.assertIsInstance(w_grad, ops.Tensor) 75 self.assertAllClose(1.0, self.sess.run(w_grad)) 76 77 # Fetch the gradient tensor with the x-tensor's name. 78 w_grad = grad_debugger.gradient_tensor(self.w.name) 79 self.assertIsInstance(w_grad, ops.Tensor) 80 self.assertAllClose(1.0, self.sess.run(w_grad)) 81 82 # Fetch the gradient tensor with the x-tensor name. 83 w_grad = grad_debugger.gradient_tensor(self.w.name) 84 self.assertIsInstance(w_grad, ops.Tensor) 85 self.assertAllClose(1.0, self.sess.run(w_grad)) 86 87 def testIdentifyGradientGivesCorrectTensorObjectWithTfGradients(self): 88 grad_debugger = debug_gradients.GradientsDebugger() 89 id_grad_w = grad_debugger.identify_gradient(self.w) 90 y = math_ops.add(id_grad_w, -1.0, name="y") 91 92 with grad_debugger: 93 grads = gradients_impl.gradients(y, [self.u, self.v]) 94 self.assertEqual(2, len(grads)) 95 u_grad = grads[0] 96 v_grad = grads[1] 97 98 self.sess.run(variables.global_variables_initializer()) 99 self.assertAllClose(5.0, self.sess.run(y)) 100 self.assertAllClose(3.0, self.sess.run(u_grad)) 101 self.assertAllClose(2.0, self.sess.run(v_grad)) 102 103 # Fetch the gradient tensor with the x-tensor object. 104 w_grad = grad_debugger.gradient_tensor(self.w) 105 self.assertIsInstance(w_grad, ops.Tensor) 106 self.assertAllClose(1.0, self.sess.run(w_grad)) 107 108 # Fetch the gradient tensor with the x-tensor's name. 109 w_grad = grad_debugger.gradient_tensor(self.w.name) 110 self.assertIsInstance(w_grad, ops.Tensor) 111 self.assertAllClose(1.0, self.sess.run(w_grad)) 112 113 # Fetch the gradient tensor with the x-tensor name. 114 w_grad = grad_debugger.gradient_tensor(self.w.name) 115 self.assertIsInstance(w_grad, ops.Tensor) 116 self.assertAllClose(1.0, self.sess.run(w_grad)) 117 118 def testCallingIdentifyGradientTwiceWithTheSameGradientsDebuggerErrors(self): 119 grad_debugger = debug_gradients.GradientsDebugger() 120 grad_debugger.identify_gradient(self.w) 121 with self.assertRaisesRegexp(ValueError, 122 "The graph already contains an op named .*"): 123 grad_debugger.identify_gradient(self.w) 124 125 def testIdentifyGradientWorksOnMultipleLosses(self): 126 grad_debugger_1 = debug_gradients.GradientsDebugger() 127 grad_debugger_2 = debug_gradients.GradientsDebugger() 128 129 y = math_ops.add(self.w, -1.0, name="y") 130 debug_y = grad_debugger_1.identify_gradient(y) 131 z1 = math_ops.square(debug_y, name="z1") 132 133 debug_y = grad_debugger_2.identify_gradient(y) 134 z2 = math_ops.sqrt(debug_y, name="z2") 135 136 with grad_debugger_1: 137 gradient_descent.GradientDescentOptimizer(0.1).minimize(z1) 138 with grad_debugger_2: 139 gradient_descent.GradientDescentOptimizer(0.1).minimize(z2) 140 141 dz1_dy = grad_debugger_1.gradient_tensor(y) 142 dz2_dy = grad_debugger_2.gradient_tensor(y) 143 self.assertIsInstance(dz1_dy, ops.Tensor) 144 self.assertIsInstance(dz2_dy, ops.Tensor) 145 self.assertIsNot(dz1_dy, dz2_dy) 146 147 self.sess.run(variables.global_variables_initializer()) 148 self.assertAllClose(5.0**2, self.sess.run(z1)) 149 self.assertAllClose(5.0**0.5, self.sess.run(z2)) 150 self.assertAllClose(2.0 * 5.0, self.sess.run(dz1_dy)) 151 self.assertAllClose(0.5 * (5.0**-0.5), self.sess.run(dz2_dy)) 152 153 def testIdentifyGradientRaisesLookupErrorForUnknownXTensor(self): 154 grad_debugger_1 = debug_gradients.GradientsDebugger() 155 grad_debugger_2 = debug_gradients.GradientsDebugger() 156 id_grad_w = grad_debugger_1.identify_gradient(self.w) 157 y = math_ops.add(id_grad_w, -1.0, name="y") 158 159 # There are >1 gradient debuggers registered, and grad_debugger is not used 160 # as a context manager here, so the gradient w.r.t. self.w will not be 161 # registered. 162 gradients_impl.gradients(y, [self.u, self.v]) 163 164 with self.assertRaisesRegexp( 165 LookupError, 166 r"This GradientsDebugger has not received any gradient tensor for "): 167 grad_debugger_1.gradient_tensor(self.w) 168 with self.assertRaisesRegexp( 169 LookupError, 170 r"This GradientsDebugger has not received any gradient tensor for "): 171 grad_debugger_2.gradient_tensor(self.w) 172 173 def testIdentifyGradientRaisesTypeErrorForNonTensorOrTensorNameInput(self): 174 grad_debugger = debug_gradients.GradientsDebugger() 175 with self.assertRaisesRegexp( 176 TypeError, 177 r"x_tensor must be a str or tf\.Tensor or tf\.Variable, but instead " 178 r"has type .*Operation.*"): 179 grad_debugger.gradient_tensor(variables.global_variables_initializer()) 180 181 def testIdentifyGradientTensorWorksWithGradientDescentOptimizer(self): 182 grad_debugger = debug_gradients.GradientsDebugger() 183 id_grad_w = grad_debugger.identify_gradient(self.w) 184 y = math_ops.add(id_grad_w, -1.0, name="y") 185 186 with grad_debugger: 187 gradient_descent.GradientDescentOptimizer(0.1).minimize(y) 188 189 self.sess.run(variables.global_variables_initializer()) 190 191 # Fetch the gradient tensor with the x-tensor object. 192 w_grad = grad_debugger.gradient_tensor(self.w) 193 self.assertIsInstance(w_grad, ops.Tensor) 194 self.assertAllClose(1.0, self.sess.run(w_grad)) 195 196 def testWatchGradientsByXTensorNamesWorks(self): 197 y = math_ops.add(self.w, -1.0, name="y") 198 199 # The constructrion of the forward graph has completed. 200 # But we can still get the gradient tensors by using 201 # watch_gradients_by_tensor_names(). 202 grad_debugger = debug_gradients.GradientsDebugger() 203 with grad_debugger.watch_gradients_by_tensor_names(self.sess.graph, "w:0$"): 204 grads = gradients_impl.gradients(y, [self.u, self.v]) 205 self.assertEqual(2, len(grads)) 206 u_grad = grads[0] 207 v_grad = grads[1] 208 209 self.sess.run(variables.global_variables_initializer()) 210 self.assertAllClose(5.0, self.sess.run(y)) 211 self.assertAllClose(3.0, self.sess.run(u_grad)) 212 self.assertAllClose(2.0, self.sess.run(v_grad)) 213 214 w_grad = grad_debugger.gradient_tensor(self.w) 215 self.assertIsInstance(w_grad, ops.Tensor) 216 self.assertAllClose(1.0, self.sess.run(w_grad)) 217 218 w_grad = grad_debugger.gradient_tensor("w:0") 219 self.assertIsInstance(w_grad, ops.Tensor) 220 self.assertAllClose(1.0, self.sess.run(w_grad)) 221 222 def testWatchGradientsByXTensorNamesWorksWithoutContextManager(self): 223 y = math_ops.add(self.w, -1.0, name="y") 224 225 # The constructrion of the forward graph has completed. 226 # But we can still get the gradient tensors by using 227 # watch_gradients_by_tensor_names(). 228 grad_debugger = debug_gradients.GradientsDebugger() 229 grad_debugger.watch_gradients_by_tensor_names(self.sess.graph, "w:0$") 230 grads = gradients_impl.gradients(y, [self.u, self.v]) 231 self.assertEqual(2, len(grads)) 232 u_grad = grads[0] 233 v_grad = grads[1] 234 235 self.sess.run(variables.global_variables_initializer()) 236 self.assertAllClose(5.0, self.sess.run(y)) 237 self.assertAllClose(3.0, self.sess.run(u_grad)) 238 self.assertAllClose(2.0, self.sess.run(v_grad)) 239 240 w_grad = grad_debugger.gradient_tensor(self.w) 241 self.assertIsInstance(w_grad, ops.Tensor) 242 self.assertAllClose(1.0, self.sess.run(w_grad)) 243 244 w_grad = grad_debugger.gradient_tensor("w:0") 245 self.assertIsInstance(w_grad, ops.Tensor) 246 self.assertAllClose(1.0, self.sess.run(w_grad)) 247 248 def testWatchGradientsWorksOnRefTensor(self): 249 y = math_ops.add(self.w, -1.0, name="y") 250 251 grad_debugger = debug_gradients.GradientsDebugger() 252 with grad_debugger.watch_gradients_by_tensor_names(self.sess.graph, "u:0$"): 253 grads = gradients_impl.gradients(y, [self.u, self.v]) 254 self.assertEqual(2, len(grads)) 255 u_grad = grads[0] 256 v_grad = grads[1] 257 258 self.assertIs(u_grad, grad_debugger.gradient_tensor("u:0")) 259 260 self.sess.run(variables.global_variables_initializer()) 261 self.assertAllClose(3.0, self.sess.run(u_grad)) 262 self.assertAllClose(2.0, self.sess.run(v_grad)) 263 self.assertAllClose(3.0, self.sess.run( 264 grad_debugger.gradient_tensor("u:0"))) 265 266 def testWatchGradientsWorksOnMultipleTensors(self): 267 y = math_ops.add(self.w, -1.0, name="y") 268 269 grad_debugger = debug_gradients.GradientsDebugger() 270 with grad_debugger.watch_gradients_by_tensor_names(self.sess.graph, 271 "(u|w):0$"): 272 grads = gradients_impl.gradients(y, [self.u, self.v]) 273 self.assertEqual(2, len(grads)) 274 u_grad = grads[0] 275 276 self.assertEqual(2, len(grad_debugger.gradient_tensors())) 277 self.assertIs(u_grad, grad_debugger.gradient_tensor("u:0")) 278 self.assertIsInstance(grad_debugger.gradient_tensor("w:0"), ops.Tensor) 279 280 self.sess.run(variables.global_variables_initializer()) 281 self.assertAllClose(1.0, self.sess.run( 282 grad_debugger.gradient_tensor("w:0"))) 283 self.assertAllClose(3.0, self.sess.run( 284 grad_debugger.gradient_tensor("u:0"))) 285 286 def testWatchGradientsByXTensorsWorks(self): 287 y = math_ops.add(self.w, -1.0, name="foo/y") 288 z = math_ops.square(y, name="foo/z") 289 290 # The constructrion of the forward graph has completed. 291 # But we can still get the gradient tensors by using 292 # watch_gradients_by_x_tensors(). 293 grad_debugger = debug_gradients.GradientsDebugger() 294 with grad_debugger.watch_gradients_by_tensors(self.sess.graph, 295 [self.w, self.u, y]): 296 gradient_descent.GradientDescentOptimizer(0.1).minimize(z) 297 298 self.assertEqual(3, len(grad_debugger.gradient_tensors())) 299 u_grad = grad_debugger.gradient_tensor(self.u) 300 w_grad = grad_debugger.gradient_tensor(self.w) 301 y_grad = grad_debugger.gradient_tensor(y) 302 303 self.sess.run(variables.global_variables_initializer()) 304 self.assertAllClose(10.0, self.sess.run(y_grad)) 305 self.assertAllClose(10.0, self.sess.run(w_grad)) 306 self.assertAllClose(30.0, self.sess.run(u_grad)) 307 308 def testWatchGradientsByTensorCanWorkOnMultipleLosses(self): 309 y = math_ops.add(self.w, -1.0, name="y") 310 z1 = math_ops.square(y, name="z1") 311 z2 = math_ops.sqrt(y, name="z2") 312 313 grad_debugger_1 = debug_gradients.GradientsDebugger() 314 with grad_debugger_1.watch_gradients_by_tensors(self.sess.graph, y): 315 gradient_descent.GradientDescentOptimizer(0.1).minimize(z1) 316 317 grad_debugger_2 = debug_gradients.GradientsDebugger() 318 with grad_debugger_2.watch_gradients_by_tensors(self.sess.graph, y): 319 gradient_descent.GradientDescentOptimizer(0.1).minimize(z2) 320 321 dz1_dy = grad_debugger_1.gradient_tensor(y) 322 dz2_dy = grad_debugger_2.gradient_tensor(y) 323 self.assertIsInstance(dz1_dy, ops.Tensor) 324 self.assertIsInstance(dz2_dy, ops.Tensor) 325 self.assertIsNot(dz1_dy, dz2_dy) 326 327 self.sess.run(variables.global_variables_initializer()) 328 self.assertAllClose(5.0**2, self.sess.run(z1)) 329 self.assertAllClose(5.0**0.5, self.sess.run(z2)) 330 self.assertAllClose(2.0 * 5.0, self.sess.run(dz1_dy)) 331 self.assertAllClose(0.5 * (5.0**-0.5), self.sess.run(dz2_dy)) 332 333 def testGradientsValuesFromDumpWorks(self): 334 y = math_ops.add(self.w, -1.0, name="y") 335 z = math_ops.square(y, name="z") 336 337 grad_debugger = debug_gradients.GradientsDebugger() 338 with grad_debugger.watch_gradients_by_tensors(self.sess.graph, 339 [self.w, self.u, y]): 340 train_op = gradient_descent.GradientDescentOptimizer(0.1).minimize(z) 341 342 self.sess.run(variables.global_variables_initializer()) 343 344 run_options = config_pb2.RunOptions(output_partition_graphs=True) 345 dump_dir = tempfile.mkdtemp() 346 debug_url = "file://" + dump_dir 347 debug_utils.watch_graph(run_options, self.sess.graph, debug_urls=debug_url) 348 run_metadata = config_pb2.RunMetadata() 349 self.assertAllClose(2.0, self.sess.run(self.u)) 350 self.sess.run(train_op, options=run_options, run_metadata=run_metadata) 351 self.assertAllClose(-1.0, self.sess.run(self.u)) 352 353 dump = debug_data.DebugDumpDir( 354 dump_dir, partition_graphs=run_metadata.partition_graphs) 355 dump.set_python_graph(self.sess.graph) 356 357 y_grad_values = debug_gradients.gradient_values_from_dump( 358 grad_debugger, y, dump) 359 self.assertEqual(1, len(y_grad_values)) 360 self.assertAllClose(10.0, y_grad_values[0]) 361 362 w_grad_values = debug_gradients.gradient_values_from_dump( 363 grad_debugger, self.w, dump) 364 self.assertEqual(1, len(w_grad_values)) 365 self.assertAllClose(10.0, w_grad_values[0]) 366 367 u_grad_values = debug_gradients.gradient_values_from_dump( 368 grad_debugger, self.u, dump) 369 self.assertEqual(1, len(u_grad_values)) 370 self.assertAllClose(30.0, u_grad_values[0]) 371 372 with self.assertRaisesRegexp( 373 LookupError, 374 r"This GradientsDebugger has not received any gradient tensor for " 375 r"x-tensor v:0"): 376 debug_gradients.gradient_values_from_dump(grad_debugger, self.v, dump) 377 378 # Cleanup. 379 shutil.rmtree(dump_dir) 380 381 382 if __name__ == "__main__": 383 googletest.main() 384