【问题标题】:How to Display Custom Images in Tensorboard (e.g. Matplotlib Plots)?如何在 Tensorboard 中显示自定义图像(例如 Matplotlib Plots)?
【发布时间】:2016-11-27 09:14:03
【问题描述】:

Tensorboard 自述文件的Image Dashboard 部分说:

由于图像仪表板支持任意 png,因此您可以使用它来将自定义可视化(例如 matplotlib 散点图)嵌入到 TensorBoard 中。

我看到了如何将 pyplot 图像写入文件,作为张量读回,然后与 tf.image_summary() 一起使用以将其写入 TensorBoard,但自述文件中的这句话表明有一种更直接的方法.有没有?如果是这样,是否有任何进一步的文档和/或如何有效地做到这一点的例子?

【问题讨论】:

    标签: python tensorflow matplotlib pytorch tensorboard


    【解决方案1】:

    如果您将图像放在内存缓冲区中,这很容易做到。下面,我展示了一个示例,其中将 pyplot 保存到缓冲区,然后转换为 TF 图像表示,然后发送到图像摘要。

    import io
    import matplotlib.pyplot as plt
    import tensorflow as tf
    
    
    def gen_plot():
        """Create a pyplot plot and save to buffer."""
        plt.figure()
        plt.plot([1, 2])
        plt.title("test")
        buf = io.BytesIO()
        plt.savefig(buf, format='png')
        buf.seek(0)
        return buf
    
    
    # Prepare the plot
    plot_buf = gen_plot()
    
    # Convert PNG buffer to TF image
    image = tf.image.decode_png(plot_buf.getvalue(), channels=4)
    
    # Add the batch dimension
    image = tf.expand_dims(image, 0)
    
    # Add image summary
    summary_op = tf.summary.image("plot", image)
    
    # Session
    with tf.Session() as sess:
        # Run
        summary = sess.run(summary_op)
        # Write summary
        writer = tf.train.SummaryWriter('./logs')
        writer.add_summary(summary)
        writer.close()
    

    这给出了以下 TensorBoard 可视化:

    【讨论】:

    • 谢谢。你的例子确实有效。出于某种原因,尽管当我在我的实际脚本(有其他摘要等)中集成相同的方法时,解决方案似乎并不稳定。它将一个或两个图像写入摘要文件,然后失败并显示以下错误消息:'tensorflow.python.framework.errors.NotFoundError: FetchOutputs node ImageSummary_2:0: not found'。也许是某种时间问题。有什么想法吗?
    • 我不知道为什么会这样。不看代码很难说。
    • tf.image_summary 现在已弃用。 API 已更改。请改用tf.summary.image(参见user guide
    • 相应地更新了答案
    • 现在 SummaryWriter 已被弃用。 (见github.com/tensorflow/tensorflow/issues/8164)改为使用'writer = tf.summary.FileWriter('./logs')'
    【解决方案2】:

    下一个脚本不使用中间 RGB/PNG 编码。还修复了执行过程中额外操作构造的问题,重复使用单个摘要。

    图的大小预计在执行过程中保持不变

    有效的解决方案:

    import matplotlib.pyplot as plt
    import tensorflow as tf
    import numpy as np
    
    def get_figure():
      fig = plt.figure(num=0, figsize=(6, 4), dpi=300)
      fig.clf()
      return fig
    
    
    def fig2rgb_array(fig, expand=True):
      fig.canvas.draw()
      buf = fig.canvas.tostring_rgb()
      ncols, nrows = fig.canvas.get_width_height()
      shape = (nrows, ncols, 3) if not expand else (1, nrows, ncols, 3)
      return np.fromstring(buf, dtype=np.uint8).reshape(shape)
    
    
    def figure_to_summary(fig):
      image = fig2rgb_array(fig)
      summary_writer.add_summary(
        vis_summary.eval(feed_dict={vis_placeholder: image}))
    
    
    if __name__ == '__main__':
          # construct graph
          x = tf.Variable(initial_value=tf.random_uniform((2, 10)))
          inc = x.assign(x + 1)
    
          # construct summary
          fig = get_figure()
          vis_placeholder = tf.placeholder(tf.uint8, fig2rgb_array(fig).shape)
          vis_summary = tf.summary.image('custom', vis_placeholder)
    
          with tf.Session() as sess:
            tf.global_variables_initializer().run()
            summary_writer = tf.summary.FileWriter('./tmp', sess.graph)
    
            for i in range(100):
              # execute step
              _, values = sess.run([inc, x])
              # draw on the plot
              fig = get_figure()
              plt.subplot('111').scatter(values[0], values[1])
              # save the summary
              figure_to_summary(fig)
    

    【讨论】:

      【解决方案3】:

      这是为了完成 Andrzej Pronobis 的回答。紧跟他的好帖子,我设置了这个最小的工作示例

          plt.figure()
          plt.plot([1, 2])
          plt.title("test")
          buf = io.BytesIO()
          plt.savefig(buf, format='png')
          buf.seek(0)
          image = tf.image.decode_png(buf.getvalue(), channels=4)
          image = tf.expand_dims(image, 0)
          summary = tf.summary.image("test", image, max_outputs=1)
          writer.add_summary(summary, step)
      

      其中 writer 是 tf.summary.FileWriter 的一个实例。 这给了我以下错误: AttributeError: 'Tensor' 对象没有属性 'value' this github post 对此有解决方案:摘要必须在添加到编写器之前进行评估(转换为字符串)。所以我的工作代码仍然如下(只需在最后一行添加 .eval() 调用):

          plt.figure()
          plt.plot([1, 2])
          plt.title("test")
          buf = io.BytesIO()
          plt.savefig(buf, format='png')
          buf.seek(0)
          image = tf.image.decode_png(buf.getvalue(), channels=4)
          image = tf.expand_dims(image, 0)
          summary = tf.summary.image("test", image, max_outputs=1)
          writer.add_summary(summary.eval(), step)
      

      这可能足够短,可以作为对他的回答的评论,但这些很容易被忽略(而且我可能也在做其他不同的事情),所以在这里,希望对您有所帮助!

      【讨论】:

        【解决方案4】:

        我的回答有点晚了。使用tf-matplotlib,一个简单的散点图可以归结为:

        import tensorflow as tf
        import numpy as np
        
        import tfmpl
        
        @tfmpl.figure_tensor
        def draw_scatter(scaled, colors): 
            '''Draw scatter plots. One for each color.'''  
            figs = tfmpl.create_figures(len(colors), figsize=(4,4))
            for idx, f in enumerate(figs):
                ax = f.add_subplot(111)
                ax.axis('off')
                ax.scatter(scaled[:, 0], scaled[:, 1], c=colors[idx])
                f.tight_layout()
        
            return figs
        
        with tf.Session(graph=tf.Graph()) as sess:
        
            # A point cloud that can be scaled by the user
            points = tf.constant(
                np.random.normal(loc=0.0, scale=1.0, size=(100, 2)).astype(np.float32)
            )
            scale = tf.placeholder(tf.float32)        
            scaled = points*scale
        
            # Note, `scaled` above is a tensor. Its being passed `draw_scatter` below. 
            # However, when `draw_scatter` is invoked, the tensor will be evaluated and a
            # numpy array representing its content is provided.   
            image_tensor = draw_scatter(scaled, ['r', 'g'])
            image_summary = tf.summary.image('scatter', image_tensor)      
            all_summaries = tf.summary.merge_all() 
        
            writer = tf.summary.FileWriter('log', sess.graph)
            summary = sess.run(all_summaries, feed_dict={scale: 2.})
            writer.add_summary(summary, global_step=0)
        

        执行时,这会在 Tensorboard 内产生以下绘图

        请注意,tf-matplotlib 负责评估任何张量输入,避免 pyplot 线程问题并支持运行时关键绘图的 blitting。

        【讨论】:

          【解决方案5】:

          最后有一些关于“记录任意图像数据”的official documentation@matplotlib 创建图像的示例。
          他们写道:

          在下面的代码中,您将使用 matplotlib 的 subplot() 函数将前 25 张图像记录为一个漂亮的网格。然后,您将在 TensorBoard 中查看网格:

          # Clear out prior logging data.
          !rm -rf logs/plots
          
          logdir = "logs/plots/" + datetime.now().strftime("%Y%m%d-%H%M%S")
          file_writer = tf.summary.create_file_writer(logdir)
          
          def plot_to_image(figure):
            """Converts the matplotlib plot specified by 'figure' to a PNG image and
            returns it. The supplied figure is closed and inaccessible after this call."""
            # Save the plot to a PNG in memory.
            buf = io.BytesIO()
            plt.savefig(buf, format='png')
            # Closing the figure prevents it from being displayed directly inside
            # the notebook.
            plt.close(figure)
            buf.seek(0)
            # Convert PNG buffer to TF image
            image = tf.image.decode_png(buf.getvalue(), channels=4)
            # Add the batch dimension
            image = tf.expand_dims(image, 0)
            return image
          
          def image_grid():
            """Return a 5x5 grid of the MNIST images as a matplotlib figure."""
            # Create a figure to contain the plot.
            figure = plt.figure(figsize=(10,10))
            for i in range(25):
              # Start next subplot.
              plt.subplot(5, 5, i + 1, title=class_names[train_labels[i]])
              plt.xticks([])
              plt.yticks([])
              plt.grid(False)
              plt.imshow(train_images[i], cmap=plt.cm.binary)
            
            return figure
          
          # Prepare the plot
          figure = image_grid()
          # Convert to image and log
          with file_writer.as_default():
            tf.summary.image("Training data", plot_to_image(figure), step=0)
          
          %tensorboard --logdir logs/plots
          

          【讨论】:

            【解决方案6】:

            已弃用:对于 PyTorch,请使用内置的 SummaryWriter.add_figure(参见其他 answer)!

            PyTorch 解决方案:

            • 使用 MatPlotLib 图
            • 将其绘制到画布上
            • 然后转换为numpy:
            # make the canvas
            figure = plt.figure(figsize=(10,10))
            canvas = matplotlib.backends.backend_agg.FigureCanvas(figure)
            
            # insert plotting code here; you can use imshow or subplot, etc.
            for i in range(25):
                plt.subplot(5, 5, i + 1, title=class_names[train_labels[i]])
                plt.xticks([])
                plt.yticks([])
                plt.grid(False)
                plt.imshow(train_images[i], cmap=plt.cm.binary)
            
            # convert canvas to figure
            canvas.draw()
            image = np.frombuffer(canvas.tostring_rgb(), dtype='uint8').reshape((1000,1000,3)).transpose((2, 0, 1))
            

            结果可以直接添加到 Tensorboard:

            tensorboard.add_image('name', image, global_step)
            

            【讨论】:

            【解决方案7】:

            Pytorch Lightning 中的解决方案

            这不是完整的类,而是您必须添加以使其在框架中工作的内容。

            import pytorch_lightning as pl
            import seaborn as sn
            import pandas as pd
            import numpy as np
            import matplotlib.pyplot as plt
            from PIL import Image
            
            def __init__(self, config, trained_vae, latent_dim):
                self.val_confusion = pl.metrics.classification.ConfusionMatrix(num_classes=self._config.n_clusters)
                self.logger: Optional[TensorBoardLogger] = None
            
            def forward(self, x):
                ...
                return log_probs
            
            def validation_step(self, batch, batch_index):
                if self._config.dataset == "mnist":
                    orig_batch, label_batch = batch
                    orig_batch = orig_batch.reshape(-1, 28 * 28)
            
                log_probs = self.forward(orig_batch)
                loss = self._criterion(log_probs, label_batch)
            
                self.val_confusion.update(log_probs, label_batch)
                return {"loss": loss, "labels": label_batch}
            
            def validation_step_end(self, outputs):
                return outputs
            
            def validation_epoch_end(self, outs):
                tb = self.logger.experiment
            
                # confusion matrix
                conf_mat = self.val_confusion.compute().detach().cpu().numpy().astype(np.int)
                df_cm = pd.DataFrame(
                    conf_mat,
                    index=np.arange(self._config.n_clusters),
                    columns=np.arange(self._config.n_clusters))
                plt.figure()
                sn.set(font_scale=1.2)
                sn.heatmap(df_cm, annot=True, annot_kws={"size": 16}, fmt='d')
                buf = io.BytesIO()
                
                plt.savefig(buf, format='jpeg')
                buf.seek(0)
                im = Image.open(buf)
                im = torchvision.transforms.ToTensor()(im)
                tb.add_image("val_confusion_matrix", im, global_step=self.current_epoch)
            

            和电话

            logger = TensorBoardLogger(save_dir=tb_logs_folder, name='Classifier')
            trainer = Trainer(
                default_root_dir=classifier_checkpoints_path,
                logger=logger,
            )
            

            【讨论】:

              【解决方案8】:

              可以使用add_figure 函数将 Matplotlib 绘图直接添加到张量板上:

              import numpy as np, matplotlib.pyplot as plt
              from torch.utils.tensorboard import SummaryWriter
              
              # Example plot
              x = np.linspace(0,10)
              plt.plot(x, np.sin(x))
              
              # Adding plot to tensorboard
              with SummaryWriter('runs/SO_test') as writer:
                writer.add_figure('Fig1', plt.gcf())
              
              # Loading tensorboard
              %tensorboard --logdir=runs
              

              【讨论】:

                猜你喜欢
                • 2017-10-02
                • 1970-01-01
                • 2021-07-14
                • 1970-01-01
                • 1970-01-01
                • 2021-03-27
                • 2022-12-11
                • 2019-12-31
                • 2019-09-08
                相关资源
                最近更新 更多