FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Add tf.summary.write and tf.summary.summary_scope for TF 2.0 · NervanaSystems/tensorflow@92937fb · GitHub

This repository was archived by the owner on Jan 3, 2023. It is now read-only.

Repository navigation

Commit 92937fb

Browse files
authored andcommitted
Add tf.summary.write and tf.summary.summary_scope for TF 2.0
The write() op is the TF 2.0 version of tf.contrib.summary.generic() and still backed by the WriteSummary C++ op, but with some changes: - first parameter is now the full summary tag, instead of deriving tag from "name" - step parameter is now mandatory since there's no global step - recording is "on by default" - no longer requires always_record_summaries() - no more "family" parameter - this should be done via proper scoping The summary_scope() is a helper for writing TF 2.0 summary ops like scalar(), etc. that provides better semantics for how tags are generated relative to name scopes. PiperOrigin-RevId: 225414160
1 parent 78c246b commit 92937fb

5 files changed

Lines changed: 412 additions & 8 deletions

File tree

‎tensorflow/python/framework/test_util.py‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,12 +1023,13 @@ def also_run_as_tf_function(f):
10231023
"""
10241024

10251025
def decorated(*args, **kwds):
1026+
def bound_f():
1027+
f(*args, **kwds)
10261028
with context.eager_mode():
10271029
# Running in eager mode
1028-
f(*args, **kwds)
1029-
1030-
defun_f = def_function.function(f)
1031-
defun_f(*args, **kwds)
1030+
bound_f()
1031+
# Running as TF function
1032+
def_function.function(bound_f)()
10321033

10331034
return decorated
10341035

‎tensorflow/python/kernel_tests/BUILD‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,25 @@ tf_py_test(
10681068
],
10691069
)
10701070

1071+
tf_py_test(
1072+
name = "summary_ops_test",
1073+
size = "small",
1074+
srcs = ["summary_ops_test.py"],
1075+
additional_deps = [
1076+
"//tensorflow/core:protos_all_py",
1077+
"//tensorflow/python:client_testlib",
1078+
"//tensorflow/python:constant_op",
1079+
"//tensorflow/python:framework_ops",
1080+
"//tensorflow/python:framework_test_lib",
1081+
"//tensorflow/python:lib",
1082+
"//tensorflow/python:platform",
1083+
"//tensorflow/python:summary_ops_v2",
1084+
"//tensorflow/python:tensor_util",
1085+
"//tensorflow/python/eager:function",
1086+
"//tensorflow/python/eager:context",
1087+
],
1088+
)
1089+
10711090
tf_py_test(
10721091
name = "summary_v1_ops_test",
10731092
size = "small",
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
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+
"""Tests for V2 summary ops from summary_ops_v2."""
16+
17+
from __future__ import absolute_import
18+
from __future__ import division
19+
from __future__ import print_function
20+
21+
import os
22+
23+
from tensorflow.core.framework import summary_pb2
24+
from tensorflow.core.util import event_pb2
25+
from tensorflow.python.eager import context
26+
from tensorflow.python.eager import def_function
27+
from tensorflow.python.framework import constant_op
28+
from tensorflow.python.framework import ops
29+
from tensorflow.python.framework import tensor_util
30+
from tensorflow.python.framework import test_util
31+
from tensorflow.python.lib.io import tf_record
32+
from tensorflow.python.ops import summary_ops_v2 as summary_ops
33+
from tensorflow.python.platform import gfile
34+
from tensorflow.python.platform import test
35+
36+
37+
class SummaryOpsTest(test_util.TensorFlowTestCase):
38+
39+
def testWrite(self):
40+
logdir = self.get_temp_dir()
41+
with context.eager_mode():
42+
with summary_ops.create_file_writer(logdir).as_default():
43+
output = summary_ops.write('tag', 42, step=12)
44+
self.assertTrue(output.numpy())
45+
events = events_from_logdir(logdir)
46+
self.assertEqual(2, len(events))
47+
self.assertEqual(12, events[1].step)
48+
value = events[1].summary.value[0]
49+
self.assertEqual('tag', value.tag)
50+
self.assertEqual(42, to_numpy(value))
51+
52+
def testWrite_fromFunction(self):
53+
logdir = self.get_temp_dir()
54+
@def_function.function
55+
def f():
56+
with summary_ops.create_file_writer(logdir).as_default():
57+
return summary_ops.write('tag', 42, step=12)
58+
with context.eager_mode():
59+
output = f()
60+
self.assertTrue(output.numpy())
61+
events = events_from_logdir(logdir)
62+
self.assertEqual(2, len(events))
63+
self.assertEqual(12, events[1].step)
64+
value = events[1].summary.value[0]
65+
self.assertEqual('tag', value.tag)
66+
self.assertEqual(42, to_numpy(value))
67+
68+
def testWrite_metadata(self):
69+
logdir = self.get_temp_dir()
70+
metadata = summary_pb2.SummaryMetadata()
71+
metadata.plugin_data.plugin_name = 'foo'
72+
with context.eager_mode():
73+
with summary_ops.create_file_writer(logdir).as_default():
74+
summary_ops.write('obj', 0, 0, metadata=metadata)
75+
summary_ops.write('bytes', 0, 0, metadata=metadata.SerializeToString())
76+
m = constant_op.constant(metadata.SerializeToString())
77+
summary_ops.write('string_tensor', 0, 0, metadata=m)
78+
events = events_from_logdir(logdir)
79+
self.assertEqual(4, len(events))
80+
self.assertEqual(metadata, events[1].summary.value[0].metadata)
81+
self.assertEqual(metadata, events[2].summary.value[0].metadata)
82+
self.assertEqual(metadata, events[3].summary.value[0].metadata)
83+
84+
def testWrite_name(self):
85+
@def_function.function
86+
def f():
87+
output = summary_ops.write('tag', 42, step=12, name='anonymous')
88+
self.assertTrue(output.name.startswith('anonymous'))
89+
f()
90+
91+
def testWrite_ndarray(self):
92+
logdir = self.get_temp_dir()
93+
with context.eager_mode():
94+
with summary_ops.create_file_writer(logdir).as_default():
95+
summary_ops.write('tag', [[1, 2], [3, 4]], step=12)
96+
events = events_from_logdir(logdir)
97+
value = events[1].summary.value[0]
98+
self.assertAllEqual([[1, 2], [3, 4]], to_numpy(value))
99+
100+
def testWrite_tensor(self):
101+
logdir = self.get_temp_dir()
102+
with context.eager_mode():
103+
t = constant_op.constant([[1, 2], [3, 4]])
104+
with summary_ops.create_file_writer(logdir).as_default():
105+
summary_ops.write('tag', t, step=12)
106+
expected = t.numpy()
107+
events = events_from_logdir(logdir)
108+
value = events[1].summary.value[0]
109+
self.assertAllEqual(expected, to_numpy(value))
110+
111+
def testWrite_tensor_fromFunction(self):
112+
logdir = self.get_temp_dir()
113+
@def_function.function
114+
def f(t):
115+
with summary_ops.create_file_writer(logdir).as_default():
116+
summary_ops.write('tag', t, step=12)
117+
with context.eager_mode():
118+
t = constant_op.constant([[1, 2], [3, 4]])
119+
f(t)
120+
expected = t.numpy()
121+
events = events_from_logdir(logdir)
122+
value = events[1].summary.value[0]
123+
self.assertAllEqual(expected, to_numpy(value))
124+
125+
def testWrite_stringTensor(self):
126+
logdir = self.get_temp_dir()
127+
with context.eager_mode():
128+
with summary_ops.create_file_writer(logdir).as_default():
129+
summary_ops.write('tag', [b'foo', b'bar'], step=12)
130+
events = events_from_logdir(logdir)
131+
value = events[1].summary.value[0]
132+
self.assertAllEqual([b'foo', b'bar'], to_numpy(value))
133+
134+
@test_util.also_run_as_tf_function
135+
def testWrite_noDefaultWriter(self):
136+
with context.eager_mode():
137+
self.assertFalse(summary_ops.write('tag', 42, step=0))
138+
139+
def testWrite_shouldRecordSummaries(self):
140+
logdir = self.get_temp_dir()
141+
with context.eager_mode():
142+
with summary_ops.create_file_writer(logdir).as_default():
143+
self.assertTrue(summary_ops.write('default_on', 1, step=0))
144+
with summary_ops.always_record_summaries():
145+
self.assertTrue(summary_ops.write('set_on', 1, step=0))
146+
with summary_ops.never_record_summaries():
147+
self.assertFalse(summary_ops.write('set_off', 1, step=0))
148+
events = events_from_logdir(logdir)
149+
self.assertEqual(3, len(events))
150+
self.assertEqual('default_on', events[1].summary.value[0].tag)
151+
self.assertEqual('set_on', events[2].summary.value[0].tag)
152+
153+
def testWrite_shouldRecordSummaries_fromFunction(self):
154+
logdir = self.get_temp_dir()
155+
@def_function.function
156+
def f(tag_prefix):
157+
with summary_ops.create_file_writer(logdir).as_default():
158+
default_output = summary_ops.write(tag_prefix + '_default', 1, step=0)
159+
with summary_ops.always_record_summaries():
160+
on_output = summary_ops.write(tag_prefix + '_on', 1, step=0)
161+
with summary_ops.never_record_summaries():
162+
off_output = summary_ops.write(tag_prefix + '_off', 1, step=0)
163+
return [default_output, on_output, off_output]
164+
with context.eager_mode():
165+
self.assertAllEqual([True, True, False], f('default'))
166+
with summary_ops.always_record_summaries():
167+
self.assertAllEqual([True, True, False], f('on'))
168+
with summary_ops.never_record_summaries():
169+
self.assertAllEqual([False, True, False], f('off'))
170+
events = events_from_logdir(logdir)
171+
self.assertEqual(6, len(events))
172+
self.assertEqual('default_default', events[1].summary.value[0].tag)
173+
self.assertEqual('default_on', events[2].summary.value[0].tag)
174+
self.assertEqual('on_default', events[3].summary.value[0].tag)
175+
self.assertEqual('on_on', events[4].summary.value[0].tag)
176+
self.assertEqual('off_on', events[5].summary.value[0].tag)
177+
178+
@test_util.also_run_as_tf_function
179+
def testSummaryScope(self):
180+
with summary_ops.summary_scope('foo') as (tag, scope):
181+
self.assertEqual('foo', tag)
182+
self.assertEqual('foo/', scope)
183+
with summary_ops.summary_scope('bar') as (tag, scope):
184+
self.assertEqual('foo/bar', tag)
185+
self.assertEqual('foo/bar/', scope)
186+
with summary_ops.summary_scope('with/slash') as (tag, scope):
187+
self.assertEqual('foo/with/slash', tag)
188+
self.assertEqual('foo/with/slash/', scope)
189+
with ops.name_scope(None):
190+
with summary_ops.summary_scope('unnested') as (tag, scope):
191+
self.assertEqual('unnested', tag)
192+
self.assertEqual('unnested/', scope)
193+
194+
@test_util.also_run_as_tf_function
195+
def testSummaryScope_defaultName(self):
196+
with summary_ops.summary_scope(None) as (tag, scope):
197+
self.assertEqual('summary', tag)
198+
self.assertEqual('summary/', scope)
199+
with summary_ops.summary_scope(None, 'backup') as (tag, scope):
200+
self.assertEqual('backup', tag)
201+
self.assertEqual('backup/', scope)
202+
203+
@test_util.also_run_as_tf_function
204+
def testSummaryScope_handlesCharactersIllegalForScope(self):
205+
with summary_ops.summary_scope('f?o?o') as (tag, scope):
206+
self.assertEqual('f?o?o', tag)
207+
self.assertEqual('foo/', scope)
208+
# If all characters aren't legal for a scope name, use default name.
209+
with summary_ops.summary_scope('???', 'backup') as (tag, scope):
210+
self.assertEqual('???', tag)
211+
self.assertEqual('backup/', scope)
212+
213+
@test_util.also_run_as_tf_function
214+
def testSummaryScope_nameNotUniquifiedForTag(self):
215+
constant_op.constant(0, name='foo')
216+
with summary_ops.summary_scope('foo') as (tag, _):
217+
self.assertEqual('foo', tag)
218+
with summary_ops.summary_scope('foo') as (tag, _):
219+
self.assertEqual('foo', tag)
220+
with ops.name_scope('with'):
221+
constant_op.constant(0, name='slash')
222+
with summary_ops.summary_scope('with/slash') as (tag, _):
223+
self.assertEqual('with/slash', tag)
224+
225+
226+
def events_from_file(filepath):
227+
"""Returns all events in a single event file.
228+
229+
Args:
230+
filepath: Path to the event file.
231+
232+
Returns:
233+
A list of all tf.Event protos in the event file.
234+
"""
235+
records = list(tf_record.tf_record_iterator(filepath))
236+
result = []
237+
for r in records:
238+
event = event_pb2.Event()
239+
event.ParseFromString(r)
240+
result.append(event)
241+
return result
242+
243+
244+
def events_from_logdir(logdir):
245+
"""Returns all events in the single eventfile in logdir.
246+
247+
Args:
248+
logdir: The directory in which the single event file is sought.
249+
250+
Returns:
251+
A list of all tf.Event protos from the single event file.
252+
253+
Raises:
254+
AssertionError: If logdir does not contain exactly one file.
255+
"""
256+
assert gfile.Exists(logdir)
257+
files = gfile.ListDirectory(logdir)
258+
assert len(files) == 1, 'Found not exactly one file in logdir: %s' % files
259+
return events_from_file(os.path.join(logdir, files[0]))
260+
261+
262+
def to_numpy(summary_value):
263+
return tensor_util.MakeNdarray(summary_value.tensor)
264+
265+
266+
if __name__ == '__main__':
267+
test.main()

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL