def setUp(self): self.log_dir = tempfile.mkdtemp() # We use numpy.random to generate audio. We seed to avoid non-determinism # in this test. numpy.random.seed(42) # Create old-style audio summaries for run "foo". tf.reset_default_graph() sess = tf.Session() placeholder = tf.placeholder(tf.float32) tf.summary.audio(name="baz", tensor=placeholder, sample_rate=44100) merged_summary_op = tf.summary.merge_all() foo_directory = os.path.join(self.log_dir, "foo") writer = tf.summary.FileWriter(foo_directory) writer.add_graph(sess.graph) for step in xrange(2): # The floats (sample data) range from -1 to 1. writer.add_summary(sess.run(merged_summary_op, feed_dict={ placeholder: numpy.random.rand(42, 22050) * 2 - 1 }), global_step=step) writer.close() # Create new-style audio summaries for run "bar". tf.reset_default_graph() sess = tf.Session() audio_placeholder = tf.placeholder(tf.float32) labels_placeholder = tf.placeholder(tf.string) summary.op("quux", audio_placeholder, sample_rate=44100, labels=labels_placeholder, description="how do you pronounce that, anyway?") merged_summary_op = tf.summary.merge_all() bar_directory = os.path.join(self.log_dir, "bar") writer = tf.summary.FileWriter(bar_directory) writer.add_graph(sess.graph) for step in xrange(2): # The floats (sample data) range from -1 to 1. writer.add_summary(sess.run(merged_summary_op, feed_dict={ audio_placeholder: numpy.random.rand(42, 11025, 1) * 2 - 1, labels_placeholder: [ tf.compat.as_bytes('step **%s**, sample %s' % (step, sample)) for sample in xrange(42) ], }), global_step=step) writer.close() # Start a server with the plugin. multiplexer = event_multiplexer.EventMultiplexer({ "foo": foo_directory, "bar": bar_directory, }) context = base_plugin.TBContext( logdir=self.log_dir, multiplexer=multiplexer) self.plugin = audio_plugin.AudioPlugin(context) wsgi_app = application.TensorBoardWSGIApp( self.log_dir, [self.plugin], multiplexer, reload_interval=0) self.server = werkzeug_test.Client(wsgi_app, wrappers.BaseResponse)
def compute_and_check_summary_pb(self, name, audio, max_outputs=3, display_name=None, description=None, audio_tensor=None, feed_dict=None): """Use both `op` and `pb` to get a summary, asserting validity. "Validity" means that the `op` and `pb` functions must return the same protobufs, and also that each encoded audio value appears to be a valid WAV file. If either of these conditions fails, the test will immediately fail. Otherwise, the valid protobuf will be returned. Returns: A `Summary` protocol buffer. """ if audio_tensor is None: audio_tensor = tf.constant(audio) op = summary.op(name, audio_tensor, self.samples_per_second, max_outputs=max_outputs, display_name=display_name, description=description) pb = summary.pb(name, audio, self.samples_per_second, max_outputs=max_outputs, display_name=display_name, description=description) pb_via_op = self.pb_via_op(op, feed_dict=feed_dict) self.assertProtoEquals(pb, pb_via_op) audios = tf.make_ndarray(pb.value[0].tensor)[:, 0].tolist() invalid_audios = [x for x in audios if not x.startswith(b'RIFF')] self.assertFalse(invalid_audios) return pb
def test_new_style_audio(self): audio = tf.reshape(tf.linspace(0.0, 100.0, 4 * 10 * 2), (4, 10, 2)) op = audio_summary.op('k488', tf.cast(audio, tf.float32), sample_rate=44100, display_name='Piano Concerto No.23', description='In **A major**.') value = self._value_from_op(op) assert value.HasField('tensor'), value self._assert_noop(value)
def test_new_style_audio(self): audio = tf.reshape(tf.linspace(0.0, 100.0, 4 * 10 * 2), (4, 10, 2)) op = audio_summary.op('k488', tf.cast(audio, tf.float32), sample_rate=44100, display_name='Piano Concerto No.23', description='In **A major**.') value = self._value_from_op(op) assert value.HasField('tensor'), value self._assert_noop(value)
def testNewStyleAudioSummary(self): """Verify processing of tensorboard.plugins.audio.summary.""" event_sink = _EventGenerator(self, zero_out_timestamps=True) writer = test_util.FileWriter(self.get_temp_dir()) writer.event_writer = event_sink with self.test_session() as sess: ipt = tf.random_normal(shape=[5, 441, 2]) with tf.name_scope('1'): audio_summary.op('one', ipt, sample_rate=44100, max_outputs=1) with tf.name_scope('2'): audio_summary.op('two', ipt, sample_rate=44100, max_outputs=2) with tf.name_scope('3'): audio_summary.op('three', ipt, sample_rate=44100, max_outputs=3) merged = tf.summary.merge_all() writer.add_graph(sess.graph) for i in xrange(10): summ = sess.run(merged) writer.add_summary(summ, global_step=i) accumulator = ea.EventAccumulator(event_sink) accumulator.Reload() tags = [ u'1/one/audio_summary', u'2/two/audio_summary', u'3/three/audio_summary', ] self.assertTagsEqual(accumulator.Tags(), { ea.TENSORS: tags, ea.GRAPH: True, ea.META_GRAPH: False, })
def testNewStyleAudioSummary(self): """Verify processing of tensorboard.plugins.audio.summary.""" event_sink = _EventGenerator(self, zero_out_timestamps=True) writer = tf.summary.FileWriter(self.get_temp_dir()) writer.event_writer = event_sink with self.test_session() as sess: ipt = tf.random_normal(shape=[5, 441, 2]) with tf.name_scope('1'): audio_summary.op('one', ipt, sample_rate=44100, max_outputs=1) with tf.name_scope('2'): audio_summary.op('two', ipt, sample_rate=44100, max_outputs=2) with tf.name_scope('3'): audio_summary.op('three', ipt, sample_rate=44100, max_outputs=3) merged = tf.summary.merge_all() writer.add_graph(sess.graph) for i in xrange(10): summ = sess.run(merged) writer.add_summary(summ, global_step=i) accumulator = ea.EventAccumulator(event_sink) accumulator.Reload() tags = [ u'1/one/audio_summary', u'2/two/audio_summary', u'3/three/audio_summary', ] self.assertTagsEqual(accumulator.Tags(), { ea.TENSORS: tags, ea.GRAPH: True, ea.META_GRAPH: False, })
def test_new_style_audio(self): with tf.compat.v1.Graph().as_default(): audio = tf.reshape(tf.linspace(0.0, 100.0, 4 * 10 * 2), (4, 10, 2)) op = audio_summary.op( "k488", tf.cast(audio, tf.float32), sample_rate=44100, display_name="Piano Concerto No.23", description="In **A major**.", ) value = self._value_from_op(op) assert value.HasField("tensor"), value self._assert_noop(value)
def testNewStyleAudioSummary(self): """Verify processing of tensorboard.plugins.audio.summary.""" event_sink = _EventGenerator(self, zero_out_timestamps=True) writer = test_util.FileWriter(self.get_temp_dir()) writer.event_writer = event_sink with tf.compat.v1.Graph().as_default(): with self.test_session() as sess: ipt = tf.random.normal(shape=[5, 441, 2]) with tf.name_scope("1"): audio_summary.op("one", ipt, sample_rate=44100, max_outputs=1) with tf.name_scope("2"): audio_summary.op("two", ipt, sample_rate=44100, max_outputs=2) with tf.name_scope("3"): audio_summary.op("three", ipt, sample_rate=44100, max_outputs=3) merged = tf.compat.v1.summary.merge_all() writer.add_graph(sess.graph) for i in range(10): summ = sess.run(merged) writer.add_summary(summ, global_step=i) accumulator = ea.EventAccumulator(event_sink) accumulator.Reload() tags = [ graph_metadata.RUN_GRAPH_NAME, "1/one/audio_summary", "2/two/audio_summary", "3/three/audio_summary", ] self.assertTagsEqual( accumulator.Tags(), { ea.TENSORS: tags, ea.GRAPH: True, ea.META_GRAPH: False, }, ) self.assertItemsEqual( accumulator.ActivePlugins(), [audio_metadata.PLUGIN_NAME, graph_metadata.PLUGIN_NAME], )
def run(logdir, run_name, wave_name, wave_constructor): """Generate wave data of the given form. The provided function `wave_constructor` should accept a scalar tensor of type float32, representing the frequency (in Hz) at which to construct a wave, and return a tensor of shape [1, _samples(), `n`] representing audio data (for some number of channels `n`). Waves will be generated at frequencies ranging from A4 to A5. Arguments: logdir: the top-level directory into which to write summary data run_name: the name of this run; will be created as a subdirectory under logdir wave_name: the name of the wave being generated wave_constructor: see above """ tf.compat.v1.reset_default_graph() tf.compat.v1.set_random_seed(0) # On each step `i`, we'll set this placeholder to `i`. This allows us # to know "what time it is" at each step. step_placeholder = tf.compat.v1.placeholder(tf.float32, shape=[]) # We want to linearly interpolate a frequency between A4 (440 Hz) and # A5 (880 Hz). with tf.name_scope("compute_frequency"): f_min = 440.0 f_max = 880.0 t = step_placeholder / (FLAGS.steps - 1) frequency = f_min * (1.0 - t) + f_max * t # Let's log this frequency, just so that we can make sure that it's as # expected. tf.compat.v1.summary.scalar("frequency", frequency) # Now, we pass this to the wave constructor to get our waveform. Doing # so within a name scope means that any summaries that the wave # constructor produces will be namespaced. with tf.name_scope(wave_name): waveform = wave_constructor(frequency) # We also have the opportunity to annotate each audio clip with a # label. This is a good place to include the frequency, because it'll # be visible immediately next to the audio clip. with tf.name_scope("compute_labels"): samples = tf.shape(input=waveform)[0] wave_types = tf.tile(["*Wave type:* `%s`." % wave_name], [samples]) frequencies = tf.strings.join([ "*Frequency:* ", tf.tile([tf.as_string(frequency, precision=2)], [samples]), " Hz.", ]) samples = tf.strings.join([ "*Sample:* ", tf.as_string(tf.range(samples) + 1), " of ", tf.as_string(samples), ".", ]) labels = tf.strings.join([wave_types, frequencies, samples], separator=" ") # We can place a description next to the summary in TensorBoard. This # is a good place to explain what the summary represents, methodology # for creating it, etc. Let's include the source code of the function # that generated the wave. source = "\n".join(" %s" % line.rstrip() for line in inspect.getsourcelines(wave_constructor)[0]) description = "A wave of type `%r`, generated via:\n\n%s" % ( wave_name, source, ) # Here's the crucial piece: we interpret this result as audio. summary.op( "waveform", waveform, FLAGS.sample_rate, labels=labels, display_name=wave_name, description=description, ) # Now, we can collect up all the summaries and begin the run. summ = tf.compat.v1.summary.merge_all() sess = tf.compat.v1.Session() writer = tf.summary.FileWriter(os.path.join(logdir, run_name)) writer.add_graph(sess.graph) sess.run(tf.compat.v1.global_variables_initializer()) for step in xrange(FLAGS.steps): s = sess.run(summ, feed_dict={step_placeholder: float(step)}) writer.add_summary(s, global_step=step) writer.close()
def audio(self, *args, **kwargs): return tf.compat.v1.Summary.FromString( summary.op(*args, **kwargs).numpy())
def test_requires_wav_in_op(self): with six.assertRaisesRegex(self, ValueError, 'Unknown encoding'): summary.op('k488', self.stereo, 44100, encoding='pptx')
def test_requires_rank_3_in_op(self): with six.assertRaisesRegex(self, ValueError, 'must have rank 3'): summary.op('k488', tf.constant([[1, 2, 3], [4, 5, 6]]), 44100)
def run(logdir, run_name, wave_name, wave_constructor): """Generate wave data of the given form. The provided function `wave_constructor` should accept a scalar tensor of type float32, representing the frequency (in Hz) at which to construct a wave, and return a tensor of shape [1, _samples(), `n`] representing audio data (for some number of channels `n`). Waves will be generated at frequencies ranging from A4 to A5. Arguments: logdir: the top-level directory into which to write summary data run_name: the name of this run; will be created as a subdirectory under logdir wave_name: the name of the wave being generated wave_constructor: see above """ tf.reset_default_graph() tf.set_random_seed(0) # On each step `i`, we'll set this placeholder to `i`. This allows us # to know "what time it is" at each step. step_placeholder = tf.placeholder(tf.float32, shape=[]) # We want to linearly interpolate a frequency between A4 (440 Hz) and # A5 (880 Hz). with tf.name_scope('compute_frequency'): f_min = 440.0 f_max = 880.0 t = step_placeholder / (FLAGS.steps - 1) frequency = f_min * (1.0 - t) + f_max * t # Let's log this frequency, just so that we can make sure that it's as # expected. tf.summary.scalar('frequency', frequency) # Now, we pass this to the wave constructor to get our waveform. Doing # so within a name scope means that any summaries that the wave # constructor produces will be namespaced. with tf.name_scope(wave_name): waveform = wave_constructor(frequency) # We also have the opportunity to annotate each audio clip with a # label. This is a good place to include the frequency, because it'll # be visible immediately next to the audio clip. with tf.name_scope('compute_labels'): samples = tf.shape(waveform)[0] wave_types = tf.tile(["*Wave type:* `%s`." % wave_name], [samples]) frequencies = tf.string_join([ "*Frequency:* ", tf.tile([tf.as_string(frequency, precision=2)], [samples]), " Hz.", ]) samples = tf.string_join([ "*Sample:* ", tf.as_string(tf.range(samples) + 1), " of ", tf.as_string(samples), ".", ]) labels = tf.string_join([wave_types, frequencies, samples], separator=" ") # We can place a description next to the summary in TensorBoard. This # is a good place to explain what the summary represents, methodology # for creating it, etc. Let's include the source code of the function # that generated the wave. source = '\n'.join(' %s' % line.rstrip() for line in inspect.getsourcelines(wave_constructor)[0]) description = ("A wave of type `%r`, generated via:\n\n%s" % (wave_name, source)) # Here's the crucial piece: we interpret this result as audio. summary.op('waveform', waveform, FLAGS.sample_rate, labels=labels, display_name=wave_name, description=description) # Now, we can collect up all the summaries and begin the run. summ = tf.summary.merge_all() sess = tf.Session() writer = tf.summary.FileWriter(os.path.join(logdir, run_name)) writer.add_graph(sess.graph) sess.run(tf.global_variables_initializer()) for step in xrange(FLAGS.steps): s = sess.run(summ, feed_dict={step_placeholder: float(step)}) writer.add_summary(s, global_step=step) writer.close()
def setUp(self): self.log_dir = tempfile.mkdtemp() # We use numpy.random to generate audio. We seed to avoid non-determinism # in this test. numpy.random.seed(42) # Create old-style audio summaries for run "foo". tf.compat.v1.reset_default_graph() sess = tf.compat.v1.Session() placeholder = tf.compat.v1.placeholder(tf.float32) tf.compat.v1.summary.audio(name="baz", tensor=placeholder, sample_rate=44100) merged_summary_op = tf.compat.v1.summary.merge_all() foo_directory = os.path.join(self.log_dir, "foo") with test_util.FileWriterCache.get(foo_directory) as writer: writer.add_graph(sess.graph) for step in xrange(2): # The floats (sample data) range from -1 to 1. writer.add_summary(sess.run(merged_summary_op, feed_dict={ placeholder: numpy.random.rand(42, 22050) * 2 - 1 }), global_step=step) # Create new-style audio summaries for run "bar". tf.compat.v1.reset_default_graph() sess = tf.compat.v1.Session() audio_placeholder = tf.compat.v1.placeholder(tf.float32) labels_placeholder = tf.compat.v1.placeholder(tf.string) summary.op("quux", audio_placeholder, sample_rate=44100, labels=labels_placeholder, description="how do you pronounce that, anyway?") merged_summary_op = tf.compat.v1.summary.merge_all() bar_directory = os.path.join(self.log_dir, "bar") with test_util.FileWriterCache.get(bar_directory) as writer: writer.add_graph(sess.graph) for step in xrange(2): # The floats (sample data) range from -1 to 1. writer.add_summary(sess.run(merged_summary_op, feed_dict={ audio_placeholder: numpy.random.rand(42, 11025, 1) * 2 - 1, labels_placeholder: [ tf.compat.as_bytes('step **%s**, sample %s' % (step, sample)) for sample in xrange(42) ], }), global_step=step) # Start a server with the plugin. multiplexer = event_multiplexer.EventMultiplexer({ "foo": foo_directory, "bar": bar_directory, }) context = base_plugin.TBContext( logdir=self.log_dir, multiplexer=multiplexer) self.plugin = audio_plugin.AudioPlugin(context) # Setting a reload interval of -1 disables reloading. We disable reloading # because we seek to block tests from running til after one reload finishes. # This setUp method thus manually reloads the multiplexer. TensorBoard would # otherwise reload in a non-blocking thread. wsgi_app = application.TensorBoardWSGIApp( self.log_dir, [self.plugin], multiplexer, reload_interval=-1, path_prefix='') self.server = werkzeug_test.Client(wsgi_app, wrappers.BaseResponse) multiplexer.Reload()
def test_requires_wav_in_op(self): with six.assertRaisesRegex(self, ValueError, 'Unknown encoding'): summary.op('k488', self.stereo, 44100, encoding='pptx')
def test_requires_rank_3_in_op(self): with six.assertRaisesRegex(self, ValueError, 'must have rank 3'): summary.op('k488', tf.constant([[1, 2, 3], [4, 5, 6]]), 44100)