class_docstr: The TensorBoardProjector callback is used to write images from the validation pass to Tensorboard using the
  TensorboardX library. Images are written to the given directory and, if required, so are associated features.
  
  Args:
      log_dir (str): The tensorboard log path for output
      comment (str): Descriptive comment to append to path
      num_images (int): The number of images to write
      avg_pool_size (int): Size of the average pool to perform on the image. This is recommended to reduce the overall
          image sizes and improve latency
      avg_data_channels (bool): If True, the image data will be averaged in the channel dimension
      write_data (bool): If True, the raw data will be written as an embedding
      write_features (bool): If True, the image features will be written as an embedding
      features_key (StateKey): The key in state to use for the embedding. Typically model output but can be used to show
          features from any layer of the model.
  
  State Requirements:
      - :attr:`torchbearer.state.EPOCH`: State should have the current epoch stored
      - :attr:`torchbearer.state.X`: State should have the current data stored
      - :attr:`torchbearer.state.Y_TRUE`: State should have the current targets stored
class_docstr_tok: ["The","TensorBoardProjector","callback","is","used","to","write","images","from","the","validation","pass","to","Tensorboard","using","the","TensorboardX","library",".","Images","are","written","to","the","given","directory","and",",","if","required",",","so","are","associated","features",".","Args",":","log_dir","(","str",")",":","The","tensorboard","log","path","for","output","comment","(","str",")",":","Descriptive","comment","to","append","to","path","num_images","(","int",")",":","The","number","of","images","to","write","avg_pool_size","(","int",")",":","Size","of","the","average","pool","to","perform","on","the","image",".","This","is","recommended","to","reduce","the","overall","image","sizes","and","improve","latency","avg_data_channels","(","bool",")",":","If","True",",","the","image","data","will","be","averaged","in","the","channel","dimension","write_data","(","bool",")",":","If","True",",","the","raw","data","will","be","written","as","an","embedding","write_features","(","bool",")",":","If","True",",","the","image","features","will","be","written","as","an","embedding","features_key","(","StateKey",")",":","The","key","in","state","to","use","for","the","embedding",".","Typically","model","output","but","can","be","used","to","show","features","from","any","layer","of","the","model",".","State","Requirements",":","-",":","attr",":","`","torchbearer.state.EPOCH","`",":","State","should","have","the","current","epoch","stored","-",":","attr",":","`","torchbearer.state.X","`",":","State","should","have","the","current","data","stored","-",":","attr",":","`","torchbearer.state.Y_TRUE","`",":","State","should","have","the","current","targets","stored"]
code: def on_step_validation(self, state):
      if not self.done:
          x = state[torchbearer.X].data.clone()
  
          if len(x.size()) == 3:
              x = x.unsqueeze(1)
  
          x = F.avg_pool2d(x, self.avg_pool_size).data
  
          data = None
  
          if state[torchbearer.EPOCH] == 0 and self.write_data:
              if self.avg_data_channels:
                  data = torch.mean(x, 1)
              else:
                  data = x
  
              data = data.view(data.size(0), -1)
  
          feature = None
  
          if self.write_features:
              feature = state[self.features_key].data.clone()
              feature = feature.view(feature.size(0), -1)
  
          label = state[torchbearer.Y_TRUE].data.clone()
  
          if state[torchbearer.BATCH] == 0:
              remaining = (
                  self.num_images
                  if self.num_images < label.size(0)
                  else label.size(0)
              )
  
              self._images = x[:remaining].to("cpu")
              self._labels = label[:remaining].to("cpu")
  
              if data is not None:
                  self._data = data[:remaining].to("cpu")
  
              if feature is not None:
                  self._features = feature[:remaining].to("cpu")
          else:
              remaining = self.num_images - self._labels.size(0)
  
              if remaining > label.size(0):
                  remaining = label.size(0)
  
              self._images = torch.cat(
                  (self._images, x[:remaining].to("cpu")), dim=0
              )
              self._labels = torch.cat(
                  (self._labels, label[:remaining].to("cpu")), dim=0
              )
  
              if data is not None:
                  self._data = torch.cat(
                      (self._data, data[:remaining].to("cpu")), dim=0
                  )
  
              if feature is not None:
                  self._features = torch.cat(
                      (self._features, feature[:remaining].to("cpu")),
                      dim=0,
                  )
  
          if self._labels.size(0) >= self.num_images:
              if state[torchbearer.EPOCH] == 0 and self.write_data:
                  self.writer.add_embedding(
                      self._data,
                      metadata=self._labels,
                      label_img=self._images,
                      tag="data",
                      global_step=-1,
                  )
              if self.write_features:
                  self.writer.add_embedding(
                      self._features,
                      metadata=self._labels,
                      label_img=self._images,
                      tag="features",
                      global_step=state[torchbearer.EPOCH],
                  )
              self.done = True
  
imports: import copy
  import os
  import warnings
  import torch
  import torch.nn.functional
  import torchbearer
  from torchbearer.callbacks import Callback
label_desc: Use image node_id 2 for calling the TensorBoardProjector obj's underlying member method code with example usage: obj.on_step_validation(state) without return types