class_docstr: stats logging object useful for gathering statistics of training a deep net in pytorch
  Example::
  
      # init stats structure that logs statistics 'objective' and 'top1e'
      stats = Stats( ('objective','top1e') )
      network = init_net() # init a pytorch module (=nueral network)
      dataloader = init_dataloader() # init a dataloader
      for epoch in range(10):
          # start of epoch -> call new_epoch
          stats.new_epoch()
  
          # iterate over batches
          for batch in dataloader:
  
              output = network(batch) # run and save into a dict of output variables
  
              # stats.update() automatically parses the 'objective' and 'top1e' from
              # the "output" dict and stores this into the db
              stats.update(output)
              # prints the metric averages over given epoch
              std_out = stats.get_status_string()
              logger.info(str_out)
          # stores the training plots into '/tmp/epoch_stats.pdf'
          # and plots into a visdom server running at localhost (if running)
          stats.plot_stats(plot_file='/tmp/epoch_stats.pdf')
code: def plot_stats(
      self,
      visdom_env=None,
      plot_file=None,
      visdom_server=None,
      visdom_port=None,
  ):
      # use the cached visdom env if none supplied
      if visdom_env is None:
          visdom_env = self.visdom_env
      if visdom_server is None:
          visdom_server = self.visdom_server
      if visdom_port is None:
          visdom_port = self.visdom_port
      if plot_file is None:
          plot_file = self.plot_file
  
      stat_sets = list(self.stats.keys())
  
      logger.debug(
          f"printing charts to visdom env '{visdom_env}' ({visdom_server}:{visdom_port})"
      )
  
      novisdom = False
  
      viz = get_visdom_connection(
          server=visdom_server, port=visdom_port
      )
      if viz is None or not viz.check_connection():
          logger.info("no visdom server! -> skipping visdom plots")
          novisdom = True
  
      lines = []
  
      # plot metrics
      if not novisdom:
          viz.close(env=visdom_env, win=None)
  
      for stat in self.log_vars:
          vals = []
          stat_sets_now = []
          for stat_set in stat_sets:
              val = self.stats[stat_set][stat].get_epoch_averages()
              if val is None:
                  continue
              else:
                  val = np.array(val).reshape(-1)
                  stat_sets_now.append(stat_set)
              vals.append(val)
  
          if len(vals) == 0:
              continue
  
          lines.append((stat_sets_now, stat, vals))
  
      if not novisdom:
          for tmodes, stat, vals in lines:
              title = "%s" % stat
              opts = {"title": title, "legend": list(tmodes)}
              for i, (tmode, val) in enumerate(zip(tmodes, vals)):
                  update = "append" if i > 0 else None
                  valid = np.where(np.isfinite(val))[0]
                  if len(valid) == 0:
                      continue
                  x = np.arange(len(val))
                  viz.line(
                      Y=val[valid],
                      X=x[valid],
                      env=visdom_env,
                      opts=opts,
                      win=f"stat_plot_{title}",
                      name=tmode,
                      update=update,
                  )
  
      if plot_file:
          logger.info(f"plotting stats to {plot_file}")
          ncol = 3
          nrow = int(np.ceil(float(len(lines)) / ncol))
          matplotlib.rcParams.update({"font.size": 5})
          color = cycle(plt.cm.tab10(np.linspace(0, 1, 10)))
          fig = plt.figure(1)
          plt.clf()
          for idx, (tmodes, stat, vals) in enumerate(lines):
              c = next(color)
              plt.subplot(nrow, ncol, idx + 1)
              plt.gca()
              for vali, vals_ in enumerate(vals):
                  c_ = c * (1.0 - float(vali) * 0.3)
                  valid = np.where(np.isfinite(vals_))[0]
                  if len(valid) == 0:
                      continue
                  x = np.arange(len(vals_))
                  plt.plot(x[valid], vals_[valid], c=c_, linewidth=1)
              plt.ylabel(stat)
              plt.xlabel("epoch")
              plt.gca().yaxis.label.set_color(c[0:3] * 0.75)
              plt.legend(tmodes)
              gcolor = np.array(mcolors.to_rgba("lightgray"))
              grid_params = {"visible": True, "color": gcolor}
              plt.grid(
                  **grid_params,
                  which="major",
                  linestyle="-",
                  linewidth=0.4,
              )
              plt.grid(
                  **grid_params,
                  which="minor",
                  linestyle="--",
                  linewidth=0.2,
              )
              plt.minorticks_on()
  
          plt.tight_layout()
          plt.show()
          try:
              fig.savefig(plot_file)
          except PermissionError:
              warnings.warn(
                  "Cant dump stats due to insufficient permissions!"
              )
  
imports: import gzip
  import json
  import logging
  import time
  import warnings
  from collections.abc import Iterable
  from itertools import cycle
  import matplotlib
  import matplotlib.pyplot
  import numpy
  from matplotlib import colors
  from pytorch3d.implicitron.tools.vis_utils import get_visdom_connection
label_desc: Use image node_id 16 for calling the Stats obj's underlying member method code with example usage: obj.plot_stats(visdom_env, plot_file, visdom_server, visdom_port) without return types