SummaryWriter().add_graph yields "empty images" in Tensorboard

username: little_adventurer
cooked: <p>Hello,</p>
<p>Firstly thank you for all the amazing work and suggestions you lot patiently provide us with.</p>
<p>Secondly, I am trying to implement the tensorboard visualizations based on the following tutorial:<br>
<a href="https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html#inspect-the-model-using-tensorboard" class="onebox" target="_blank" rel="noopener nofollow ugc">https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html#inspect-the-model-using-tensorboard</a></p>
<p>I can add scalars without any issues, and am sort of adding the images with their predictions.</p>
<p>However, as you can see in the following screenshot, the graphs are not displayed correctly:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/0/2/02bb2b430722b5879523ed2780597ec1a27491c4.png" data-download-href="https://discuss.pytorch.org/uploads/default/02bb2b430722b5879523ed2780597ec1a27491c4" title="Screenshot from 2020-07-30 16-30-30"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/0/2/02bb2b430722b5879523ed2780597ec1a27491c4_2_345x159.png" alt="Screenshot from 2020-07-30 16-30-30" data-base62-sha1="o9XGrPoGc5IXHkXs8dWPeA1ycs" width="345" height="159" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/0/2/02bb2b430722b5879523ed2780597ec1a27491c4_2_345x159.png, https://discuss.pytorch.org/uploads/default/optimized/3X/0/2/02bb2b430722b5879523ed2780597ec1a27491c4_2_517x238.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/0/2/02bb2b430722b5879523ed2780597ec1a27491c4_2_690x318.png 2x" data-dominant-color="FDFAFA"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">Screenshot from 2020-07-30 16-30-30</span><span class="informations">832×385 7.68 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>As sanity check, I am displaying the images in question while inferring. They seem to be fine (except for the horrible resolution - any advice on that too):<br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/f/2/f22bc61ea31eb773277642bc723648bc88ea724a.png" alt="Screenshot from 2020-07-30 16-36-40" data-base62-sha1="yylkE51LEeYppC6jLoKxZHblzqa" width="287" height="439"></p>
<p>My code for visualisations is as follows:</p>
<pre><code class="lang-auto">    def _img_to_prob(self, images):
        
        output = self.model(images)

        # convert output probabilities to predicted classes 
        _, preds_tensor = torch.max(output, 1)

        preds = np.squeeze(preds_tensor.cpu().numpy())

        return preds, [F.softmax(el, dim=0)[i].item() for i,el in zip(preds, output)]

    def _display_images(self, img, one_channel = False):       
        if one_channel:
            img = img.mean(dim = 0)
    
        img = img/2+0.5 # unnormalise
        # Detach from the img tensor from the GPU
        npimg = img.cpu().numpy()
    
        if one_channel:
            plt.imshow(npimg, cmap="Greys")
    
        plt.imshow(np.transpose(npimg, (1,2,0)))
    
    
    def _visualise_preds(self, images, labels, one_channel):
        """
        Generates a matplotlib Figure using a trained network, along with images
        and labels of a set of images, that shows the networks top prediction 
        along with it's probability alongisde the actual label. 
        Coloured based on the correctness of the prediction.
        """
        print(f"Images have shape: {images.shape}")

        preds, probs = self._img_to_prob(images)
        fig = plt.Figure(figsize=(12, 12))

        for i in np.arange(4):
            ax = fig.add_subplot(1, 4, i+1, xticks = [], yticks = [])
            self._display_images(images[i], one_channel = one_channel)
            
            #sanity check; display image
            plt.title(f"Label: {labels[i]}, predicted: {preds[i]}")
            plt.imshow(np.transpose(images[i].cpu().numpy(), (1,2,0)))
            plt.show()
            
#             ax.show()
#             plt.show()
            
            ax.set_title("{0}, {1:.1f}%\n(label: {2})".format(
                classes[preds[i]],
                probs[i] * 100.0,
                classes[labels[i]]),
                        color=("green" if preds[i]==labels[i].item() else "red"))
        
        return fig
        
</code></pre>
<p>Much appreciated!</p>
<p>[edit]<br>
I am adding the validation loop in order to showcase how they are being added to Tensorboard</p>
<pre><code class="lang-auto">
            running_val_loss = 0
            print("epoch",epoch)
            print("epoch%eval_per", epoch%self.eval_period)
            # Validation loop every self.eval_period epochs
            if epoch%self.eval_period == 0:
                print(f"Starting evaluating at epoch: {epoch}")
                with torch.no_grad():
                    for idx,data in enumerate(self.valloader):

                        # set model in eval() mode
                        self.model.eval()

                        inputs,labels = data
                        # Place inputs/lables on the GPU
                        inputs = inputs.to(self.device)
                        labels = labels.to(self.device)

                        # Predict outputs
                        outputs = self.model(inputs)

                        # Obtain and append val_batch_loss
                        val_loss = self.criterion(outputs,labels)
                        val_batch_loss.append(loss.item())
                        running_val_loss += val_loss

                        # Obtain and append val_batch_acc
                        correct_preds = [torch.argmax(i) == torch.argmax(j) for i,j in zip(outputs,labels)]

                        val_acc = correct_preds.count(True)/len(correct_preds)
                        val_batch_acc.append(val_acc)

                    val_epoch_loss.append(torch.tensor(val_batch_loss).mean())
                    val_epoch_acc.append(torch.tensor(val_batch_acc).mean())
                    
                    
                    # Visualise the predictions on the last validation batch
                    
                    print(f"len inputs of last batch: {len(inputs)}")
                    
                    self.writer.add_scalar("Validation Loss", 
                                           running_val_loss/len(self.valloader),
                                           global_step = epoch
                                          )
                    
                    self.writer.add_figure("Predictions vs. GT",
                                           self._visualise_preds(inputs, labels, False),
                                           global_step = epoch
                                          )
                    
                    running_val_loss = 0.0
                    
</code></pre>