docs: def log(self, step, **kwargs):
          """Record metrics at a specific step. E.g.
  
          my_history.log(34, loss=2.3, accuracy=0.2)
  
          Okay to call multiple times for the same step. New values overwrite
          older ones if they have the same metric name.
  
          step: An integer or tuple of integers. If a tuple, then the first
              value is considered to be the epoch and the second is the step
              within the epoch.
          """
          assert isinstance(step, (int, tuple)), "Step must be an int or a tuple of two ints"
          self.step = step
          # Any new metrics we haven't seen before?
          self.metrics |= set(kwargs.keys())
          # Insert (or update) record of the step
          if step not in self.history:
              self.history[step] = {}
          self.history[step].update({k:utils.to_data(v) for k, v in kwargs.items()})
          # Update step timestamp
          self.history[step]["__timestamp__"] = time.time()