1# Copyright 2015 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"""Tests for tensorflow.kernels.logging_ops."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import os
22import string
23import sys
24import tempfile
25
26from tensorflow.python.eager import context
27from tensorflow.python.eager import function
28from tensorflow.python.framework import constant_op
29from tensorflow.python.framework import dtypes
30from tensorflow.python.framework import ops
31from tensorflow.python.framework import sparse_tensor
32from tensorflow.python.framework import test_util
33from tensorflow.python.ops import control_flow_ops
34from tensorflow.python.ops import gradients_impl
35from tensorflow.python.ops import logging_ops
36from tensorflow.python.ops import math_ops
37from tensorflow.python.ops import string_ops
38from tensorflow.python.ops import variables
39from tensorflow.python.platform import test
40
41
42class LoggingOpsTest(test.TestCase):
43
44  @test_util.run_deprecated_v1
45  def testAssertDivideByZero(self):
46    with self.cached_session() as sess:
47      epsilon = ops.convert_to_tensor(1e-20)
48      x = ops.convert_to_tensor(0.0)
49      y = ops.convert_to_tensor(1.0)
50      z = ops.convert_to_tensor(2.0)
51      # assert(epsilon < y)
52      # z / y
53      with sess.graph.control_dependencies([
54          control_flow_ops.Assert(
55              math_ops.less(epsilon, y), ["Divide-by-zero"])
56      ]):
57        out = math_ops.div(z, y)
58      self.assertAllEqual(2.0, self.evaluate(out))
59      # assert(epsilon < x)
60      # z / x
61      #
62      # This tests printing out multiple tensors
63      with sess.graph.control_dependencies([
64          control_flow_ops.Assert(
65              math_ops.less(epsilon, x), ["Divide-by-zero", "less than x"])
66      ]):
67        out = math_ops.div(z, x)
68      with self.assertRaisesOpError("less than x"):
69        self.evaluate(out)
70
71
72@test_util.run_all_in_graph_and_eager_modes
73class PrintV2Test(test.TestCase):
74
75  def testPrintOneTensor(self):
76    tensor = math_ops.range(10)
77    with self.captureWritesToStream(sys.stderr) as printed:
78      print_op = logging_ops.print_v2(tensor)
79      self.evaluate(print_op)
80
81    expected = "[0 1 2 ... 7 8 9]"
82    self.assertIn((expected + "\n"), printed.contents())
83
84  def testPrintOneStringTensor(self):
85    tensor = ops.convert_to_tensor([char for char in string.ascii_lowercase])
86    with self.captureWritesToStream(sys.stderr) as printed:
87      print_op = logging_ops.print_v2(tensor)
88      self.evaluate(print_op)
89
90    expected = "[\"a\" \"b\" \"c\" ... \"x\" \"y\" \"z\"]"
91    self.assertIn((expected + "\n"), printed.contents())
92
93  def testPrintOneTensorVarySummarize(self):
94    tensor = math_ops.range(10)
95    with self.captureWritesToStream(sys.stderr) as printed:
96      print_op = logging_ops.print_v2(tensor, summarize=1)
97      self.evaluate(print_op)
98
99    expected = "[0 ... 9]"
100    self.assertIn((expected + "\n"), printed.contents())
101
102    tensor = math_ops.range(10)
103    with self.captureWritesToStream(sys.stderr) as printed:
104      print_op = logging_ops.print_v2(tensor, summarize=2)
105      self.evaluate(print_op)
106
107    expected = "[0 1 ... 8 9]"
108    self.assertIn((expected + "\n"), printed.contents())
109
110    tensor = math_ops.range(10)
111    with self.captureWritesToStream(sys.stderr) as printed:
112      print_op = logging_ops.print_v2(tensor, summarize=3)
113      self.evaluate(print_op)
114
115    expected = "[0 1 2 ... 7 8 9]"
116    self.assertIn((expected + "\n"), printed.contents())
117
118    tensor = math_ops.range(10)
119    with self.captureWritesToStream(sys.stderr) as printed:
120      print_op = logging_ops.print_v2(tensor, summarize=-1)
121      self.evaluate(print_op)
122
123    expected = "[0 1 2 3 4 5 6 7 8 9]"
124    self.assertIn((expected + "\n"), printed.contents())
125
126  def testPrintOneVariable(self):
127    var = variables.Variable(math_ops.range(10))
128    if not context.executing_eagerly():
129      self.evaluate(variables.global_variables_initializer())
130    with self.captureWritesToStream(sys.stderr) as printed:
131      print_op = logging_ops.print_v2(var)
132      self.evaluate(print_op)
133    expected = "[0 1 2 ... 7 8 9]"
134    self.assertIn((expected + "\n"), printed.contents())
135
136  def testPrintTwoVariablesInStructWithAssignAdd(self):
137    var_one = variables.Variable(2.14)
138    plus_one = var_one.assign_add(1.0)
139    var_two = variables.Variable(math_ops.range(10))
140    if not context.executing_eagerly():
141      self.evaluate(variables.global_variables_initializer())
142    with self.captureWritesToStream(sys.stderr) as printed:
143      self.evaluate(plus_one)
144      print_op = logging_ops.print_v2(var_one, {"second": var_two})
145      self.evaluate(print_op)
146    expected = "3.14 {'second': [0 1 2 ... 7 8 9]}"
147    self.assertIn((expected + "\n"), printed.contents())
148
149  def testPrintTwoTensors(self):
150    tensor = math_ops.range(10)
151    with self.captureWritesToStream(sys.stderr) as printed:
152      print_op = logging_ops.print_v2(tensor, tensor * 10)
153      self.evaluate(print_op)
154    expected = "[0 1 2 ... 7 8 9] [0 10 20 ... 70 80 90]"
155    self.assertIn((expected + "\n"), printed.contents())
156
157  def testPrintTwoTensorsDifferentSep(self):
158    tensor = math_ops.range(10)
159    with self.captureWritesToStream(sys.stderr) as printed:
160      print_op = logging_ops.print_v2(tensor, tensor * 10, sep="<separator>")
161      self.evaluate(print_op)
162    expected = "[0 1 2 ... 7 8 9]<separator>[0 10 20 ... 70 80 90]"
163    self.assertIn(expected + "\n", printed.contents())
164
165  def testPrintPlaceholderGeneration(self):
166    tensor = math_ops.range(10)
167    with self.captureWritesToStream(sys.stderr) as printed:
168      print_op = logging_ops.print_v2("{}6", {"{}": tensor * 10})
169      self.evaluate(print_op)
170    expected = "{}6 {'{}': [0 10 20 ... 70 80 90]}"
171    self.assertIn((expected + "\n"), printed.contents())
172
173  def testPrintNoTensors(self):
174    with self.captureWritesToStream(sys.stderr) as printed:
175      print_op = logging_ops.print_v2(23, [23, 5], {"6": 12})
176      self.evaluate(print_op)
177    expected = "23 [23, 5] {'6': 12}"
178    self.assertIn((expected + "\n"), printed.contents())
179
180  def testPrintFloatScalar(self):
181    for dtype in [dtypes.bfloat16, dtypes.half, dtypes.float32, dtypes.float64]:
182      tensor = ops.convert_to_tensor(43.5, dtype=dtype)
183      with self.captureWritesToStream(sys.stderr) as printed:
184        print_op = logging_ops.print_v2(tensor)
185        self.evaluate(print_op)
186      expected = "43.5"
187      self.assertIn((expected + "\n"), printed.contents())
188
189  def testPrintStringScalar(self):
190    tensor = ops.convert_to_tensor("scalar")
191    with self.captureWritesToStream(sys.stderr) as printed:
192      print_op = logging_ops.print_v2(tensor)
193      self.evaluate(print_op)
194    expected = "scalar"
195    self.assertIn((expected + "\n"), printed.contents())
196
197  def testPrintStringScalarDifferentEnd(self):
198    tensor = ops.convert_to_tensor("scalar")
199    with self.captureWritesToStream(sys.stderr) as printed:
200      print_op = logging_ops.print_v2(tensor, end="<customend>")
201      self.evaluate(print_op)
202    expected = "scalar<customend>"
203    self.assertIn(expected, printed.contents())
204
205  def testPrintComplexTensorStruct(self):
206    tensor = math_ops.range(10)
207    small_tensor = constant_op.constant([0.3, 12.4, -16.1])
208    big_tensor = math_ops.mul(tensor, 10)
209    with self.captureWritesToStream(sys.stderr) as printed:
210      print_op = logging_ops.print_v2(
211          "first:", tensor, "middle:",
212          {"small": small_tensor, "Big": big_tensor}, 10,
213          [tensor * 2, tensor])
214      self.evaluate(print_op)
215    # Note that the keys in the dict will always be sorted,
216    # so 'Big' comes before 'small'
217    expected = ("first: [0 1 2 ... 7 8 9] "
218                "middle: {'Big': [0 10 20 ... 70 80 90], "
219                "'small': [0.3 12.4 -16.1]} "
220                "10 [[0 2 4 ... 14 16 18], [0 1 2 ... 7 8 9]]")
221    self.assertIn((expected + "\n"), printed.contents())
222
223  def testPrintSparseTensor(self):
224    ind = [[0, 0], [1, 0], [1, 3], [4, 1], [1, 4], [3, 2], [3, 3]]
225    val = [0, 10, 13, 4, 14, 32, 33]
226    shape = [5, 6]
227
228    sparse = sparse_tensor.SparseTensor(
229        constant_op.constant(ind, dtypes.int64),
230        constant_op.constant(val, dtypes.int64),
231        constant_op.constant(shape, dtypes.int64))
232
233    with self.captureWritesToStream(sys.stderr) as printed:
234      print_op = logging_ops.print_v2(sparse)
235      self.evaluate(print_op)
236    expected = ("'SparseTensor(indices=[[0 0]\n"
237                " [1 0]\n"
238                " [1 3]\n"
239                " ...\n"
240                " [1 4]\n"
241                " [3 2]\n"
242                " [3 3]], values=[0 10 13 ... 14 32 33], shape=[5 6])'")
243    self.assertIn((expected + "\n"), printed.contents())
244
245  def testPrintSparseTensorInDataStruct(self):
246    ind = [[0, 0], [1, 0], [1, 3], [4, 1], [1, 4], [3, 2], [3, 3]]
247    val = [0, 10, 13, 4, 14, 32, 33]
248    shape = [5, 6]
249
250    sparse = sparse_tensor.SparseTensor(
251        constant_op.constant(ind, dtypes.int64),
252        constant_op.constant(val, dtypes.int64),
253        constant_op.constant(shape, dtypes.int64))
254
255    with self.captureWritesToStream(sys.stderr) as printed:
256      print_op = logging_ops.print_v2([sparse])
257      self.evaluate(print_op)
258    expected = ("['SparseTensor(indices=[[0 0]\n"
259                " [1 0]\n"
260                " [1 3]\n"
261                " ...\n"
262                " [1 4]\n"
263                " [3 2]\n"
264                " [3 3]], values=[0 10 13 ... 14 32 33], shape=[5 6])']")
265    self.assertIn((expected + "\n"), printed.contents())
266
267  def testPrintOneTensorStdout(self):
268    tensor = math_ops.range(10)
269    with self.captureWritesToStream(sys.stdout) as printed:
270      print_op = logging_ops.print_v2(
271          tensor, output_stream=sys.stdout)
272      self.evaluate(print_op)
273    expected = "[0 1 2 ... 7 8 9]"
274    self.assertIn((expected + "\n"), printed.contents())
275
276  def testPrintTensorsToFile(self):
277    tmpfile_name = tempfile.mktemp(".printv2_test")
278    tensor_0 = math_ops.range(0, 10)
279    print_op_0 = logging_ops.print_v2(tensor_0,
280                                      output_stream="file://"+tmpfile_name)
281    self.evaluate(print_op_0)
282    tensor_1 = math_ops.range(11, 20)
283    print_op_1 = logging_ops.print_v2(tensor_1,
284                                      output_stream="file://"+tmpfile_name)
285    self.evaluate(print_op_1)
286    try:
287      f = open(tmpfile_name, "r")
288      line_0 = f.readline()
289      expected_0 = "[0 1 2 ... 7 8 9]"
290      self.assertTrue(expected_0 in line_0)
291      line_1 = f.readline()
292      expected_1 = "[11 12 13 ... 17 18 19]"
293      self.assertTrue(expected_1 in line_1)
294      f.close()
295      os.remove(tmpfile_name)
296    except IOError as e:
297      self.fail(e)
298
299  def testInvalidOutputStreamRaisesError(self):
300    tensor = math_ops.range(10)
301    with self.assertRaises(ValueError):
302      print_op = logging_ops.print_v2(
303          tensor, output_stream="unknown")
304      self.evaluate(print_op)
305
306  @test_util.run_deprecated_v1
307  def testPrintOpName(self):
308    tensor = math_ops.range(10)
309    print_op = logging_ops.print_v2(tensor, name="print_name")
310    self.assertEqual(print_op.name, "print_name")
311
312  @test_util.run_deprecated_v1
313  def testNoDuplicateFormatOpGraphModeAfterExplicitFormat(self):
314    tensor = math_ops.range(10)
315    formatted_string = string_ops.string_format("{}", tensor)
316    print_op = logging_ops.print_v2(formatted_string)
317    self.evaluate(print_op)
318    graph_ops = ops.get_default_graph().get_operations()
319    format_ops = [op for op in graph_ops if op.type == "StringFormat"]
320    # Should be only 1 format_op for graph mode.
321    self.assertEqual(len(format_ops), 1)
322
323  def testPrintOneTensorEagerOnOpCreate(self):
324    with context.eager_mode():
325      tensor = math_ops.range(10)
326      expected = "[0 1 2 ... 7 8 9]"
327      with self.captureWritesToStream(sys.stderr) as printed:
328        logging_ops.print_v2(tensor)
329      self.assertIn((expected + "\n"), printed.contents())
330
331  def testPrintsOrderedInDefun(self):
332    with context.eager_mode():
333
334      @function.defun
335      def prints():
336        logging_ops.print_v2("A")
337        logging_ops.print_v2("B")
338        logging_ops.print_v2("C")
339
340      with self.captureWritesToStream(sys.stderr) as printed:
341        prints()
342      self.assertTrue(("A\nB\nC\n"), printed.contents())
343
344  def testPrintInDefunWithoutExplicitEvalOfPrint(self):
345    @function.defun
346    def f():
347      tensor = math_ops.range(10)
348      logging_ops.print_v2(tensor)
349      return tensor
350
351    expected = "[0 1 2 ... 7 8 9]"
352    with self.captureWritesToStream(sys.stderr) as printed_one:
353      x = f()
354      self.evaluate(x)
355    self.assertIn((expected + "\n"), printed_one.contents())
356
357    # We execute the function again to make sure it doesn't only print on the
358    # first call.
359    with self.captureWritesToStream(sys.stderr) as printed_two:
360      y = f()
361      self.evaluate(y)
362    self.assertIn((expected + "\n"), printed_two.contents())
363
364
365class PrintGradientTest(test.TestCase):
366
367  @test_util.run_in_graph_and_eager_modes
368  def testPrintShape(self):
369    inp = constant_op.constant(2.0, shape=[100, 32])
370    inp_printed = logging_ops.Print(inp, [inp])
371    self.assertEqual(inp.get_shape(), inp_printed.get_shape())
372
373  def testPrintString(self):
374    inp = constant_op.constant(2.0, shape=[100, 32])
375    inp_printed = logging_ops.Print(inp, ["hello"])
376    self.assertEqual(inp.get_shape(), inp_printed.get_shape())
377
378  @test_util.run_deprecated_v1
379  def testPrintGradient(self):
380    inp = constant_op.constant(2.0, shape=[100, 32], name="in")
381    w = constant_op.constant(4.0, shape=[10, 100], name="w")
382    wx = math_ops.matmul(w, inp, name="wx")
383    wx_print = logging_ops.Print(wx, [w, w, w])
384    wx_grad = gradients_impl.gradients(wx, w)[0]
385    wx_print_grad = gradients_impl.gradients(wx_print, w)[0]
386    wxg = self.evaluate(wx_grad)
387    wxpg = self.evaluate(wx_print_grad)
388    self.assertAllEqual(wxg, wxpg)
389
390
391if __name__ == "__main__":
392  test.main()
393