Skip to content

Commit 5e49467

Browse files
yatbeartensorflower-gardener
authored andcommitted
Invoke TensorBoard histogram v2 in tf.compat.v1.summary.histogram.
PiperOrigin-RevId: 426010859 Change-Id: Ib8cbb24b4270dec06fe1d6b36854460398784d4d
1 parent 8318a97 commit 5e49467

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

‎tensorflow/python/summary/summary.py‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ def image(name, tensor, max_outputs=3, collections=None, family=None):
239239
# `tf.compat.v1.summary.merge()` API.
240240
return _constant_op.constant(b'')
241241

242+
# Fall back to legacy v1 image implementation.
242243
if _distribute_summary_op_util.skip_summary():
243244
return _constant_op.constant('')
244245
with _summary_op_util.summary_scope(
@@ -280,8 +281,19 @@ def histogram(name, values, collections=None, family=None):
280281
buffer.
281282
282283
@compatibility(TF2)
283-
This API is not compatible with eager execution and `tf.function`. To migrate
284-
to TF2, please use `tf.summary.histogram` instead. Please check
284+
For compatibility purposes, when invoked in TF2 where the outermost context is
285+
eager mode, this API will check if there is a suitable TF2 summary writer
286+
context available, and if so will forward this call to that writer instead. A
287+
"suitable" writer context means that the writer is set as the default writer,
288+
and there is an associated non-empty value for `step` (see
289+
`tf.summary.SummaryWriter.as_default`, or alternatively
290+
`tf.summary.experimental.set_step`). For the forwarded call, the arguments
291+
here will be passed to the TF2 implementation of `tf.summary.histogram`, and
292+
the return value will be an empty bytestring tensor, to avoid duplicate
293+
summary writing. This forwarding is best-effort and not all arguments will be
294+
preserved.
295+
296+
To migrate to TF2, please use `tf.summary.histogram` instead. Please check
285297
[Migrating tf.summary usage to
286298
TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
287299
steps for migration.
@@ -306,6 +318,18 @@ def histogram(name, values, collections=None, family=None):
306318
307319
@end_compatibility
308320
"""
321+
# Special case: invoke v2 op for TF2 users who have a v2 writer.
322+
if _should_invoke_v2_op():
323+
# Defer the import to happen inside the symbol to prevent breakage due to
324+
# missing dependency.
325+
from tensorboard.summary.v2 import histogram as histogram_v2 # pylint: disable=g-import-not-at-top
326+
with _compat_summary_scope(name, family) as tag:
327+
histogram_v2(name=tag, data=values, step=_get_step_for_v2())
328+
# Return an empty Tensor, which will be acceptable as an input to the
329+
# `tf.compat.v1.summary.merge()` API.
330+
return _constant_op.constant(b'')
331+
332+
# Fall back to legacy v1 histogram implementation.
309333
if _distribute_summary_op_util.skip_summary():
310334
return _constant_op.constant('')
311335
with _summary_op_util.summary_scope(

‎tensorflow/python/summary/summary_v2_test.py‎

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def test_scalar_summary_v2__w_writer(self):
3636
"""Tests scalar v2 invocation with a v2 writer."""
3737
with test.mock.patch.object(
3838
summary_v2, 'scalar', autospec=True) as mock_scalar_v2:
39-
with summary_ops_v2.create_summary_file_writer('/tmp/test').as_default(
40-
step=1):
39+
with summary_ops_v2.create_summary_file_writer(
40+
self.get_temp_dir()).as_default(step=1):
4141
i = constant_op.constant(2.5)
4242
tensor = summary_lib.scalar('float', i)
4343
# Returns empty string.
@@ -62,7 +62,7 @@ def test_scalar_summary_v2__global_step_not_set(self):
6262
with test.mock.patch.object(
6363
summary_v2, 'scalar', autospec=True) as mock_scalar_v2:
6464
with summary_ops_v2.create_summary_file_writer(
65-
'/tmp/test').as_default():
65+
self.get_temp_dir()).as_default():
6666
summary_lib.scalar('float', constant_op.constant(2.5))
6767
mock_scalar_v2.assert_not_called()
6868

@@ -71,8 +71,8 @@ def test_scalar_summary_v2__family(self):
7171
"""Tests `family` arg handling when scalar v2 is invoked."""
7272
with test.mock.patch.object(
7373
summary_v2, 'scalar', autospec=True) as mock_scalar_v2:
74-
with summary_ops_v2.create_summary_file_writer('/tmp/test').as_default(
75-
step=1):
74+
with summary_ops_v2.create_summary_file_writer(
75+
self.get_temp_dir()).as_default(step=1):
7676
tensor = summary_lib.scalar(
7777
'float', constant_op.constant(2.5), family='otter')
7878
# Returns empty string.
@@ -86,8 +86,8 @@ def test_scalar_summary_v2__family_w_outer_scope(self):
8686
"""Tests `family` arg handling when there is an outer scope."""
8787
with test.mock.patch.object(
8888
summary_v2, 'scalar', autospec=True) as mock_scalar_v2:
89-
with summary_ops_v2.create_summary_file_writer('/tmp/test').as_default(
90-
step=1):
89+
with summary_ops_v2.create_summary_file_writer(
90+
self.get_temp_dir()).as_default(step=1):
9191
with ops.name_scope_v2('sea'):
9292
tensor = summary_lib.scalar(
9393
'float', constant_op.constant(3.5), family='crabnet')
@@ -104,7 +104,8 @@ def test_scalar_summary_v2__v1_set_step(self):
104104
global_step.assign(1024)
105105
with test.mock.patch.object(
106106
summary_v2, 'scalar', autospec=True) as mock_scalar_v2:
107-
with summary_ops_v2.create_summary_file_writer('/tmp/test').as_default():
107+
with summary_ops_v2.create_summary_file_writer(
108+
self.get_temp_dir()).as_default():
108109
i = constant_op.constant(2.5)
109110
tensor = summary_lib.scalar('float', i)
110111
# Returns empty string.
@@ -117,8 +118,8 @@ def test_image_summary_v2(self):
117118
"""Tests image v2 invocation."""
118119
with test.mock.patch.object(
119120
summary_v2, 'image', autospec=True) as mock_image_v2:
120-
with summary_ops_v2.create_summary_file_writer('/tmp/test').as_default(
121-
step=2):
121+
with summary_ops_v2.create_summary_file_writer(
122+
self.get_temp_dir()).as_default(step=2):
122123
i = array_ops.ones((5, 4, 4, 3))
123124
with ops.name_scope_v2('outer'):
124125
tensor = summary_lib.image('image', i, max_outputs=3, family='family')
@@ -128,6 +129,21 @@ def test_image_summary_v2(self):
128129
mock_image_v2.assert_called_once_with(
129130
'family/outer/family/image', data=i, step=2, max_outputs=3)
130131

132+
@test_util.run_v2_only
133+
def test_histogram_summary_v2(self):
134+
"""Tests histogram v2 invocation."""
135+
with test.mock.patch.object(
136+
summary_v2, 'histogram', autospec=True) as mock_histogram_v2:
137+
with summary_ops_v2.create_summary_file_writer(
138+
self.get_temp_dir()).as_default(step=3):
139+
i = array_ops.ones((1024,))
140+
tensor = summary_lib.histogram('histogram', i, family='family')
141+
# Returns empty string.
142+
self.assertEqual(tensor.numpy(), b'')
143+
self.assertEqual(tensor.dtype, dtypes.string)
144+
mock_histogram_v2.assert_called_once_with(
145+
'family/family/histogram', data=i, step=3)
146+
131147

132148
if __name__ == '__main__':
133149
test.main()

0 commit comments

Comments
 (0)