          dtype = "float32" if metric == "loss" else "float64"
  
          retval = {}
          for idx, data in raw.items():
              buff = np.frombuffer(zlib.decompress(data[metric]), dtype=dtype)
              shape = data[f"{metric}_shape"]
              if len(shape) > 1:
                  buff = buff.reshape(-1, *shape[1:])
              val = {metric: buff}
              if metric == "loss":
                  val["labels"] = data["labels"]
              retval[idx] = val
  
          logger.debug("Obtained cached data: %s",
 
</s> remove         dtype = "float32" if metric == "loss" else "float64"

        retval = {}
 </s> add         retval: Dict[int, Dict[str, Union[np.ndarray, List[str]]]] = {} </s> remove                 val["labels"] = data["labels"]
 </s> add                 val["labels"] = data.labels </s> remove         cache = self._data[session_id]
        for metric in ("loss", "timestamps"):
            data = locals()[metric]
            dtype = "float32" if metric == "loss" else "float64"

            old = np.frombuffer(zlib.decompress(cache[metric]), dtype=dtype)
            if data.ndim > 1:
                old = old.reshape(-1, *data.shape[1:])

            new = np.concatenate((old, data))

            logger.debug("'%s' old_shape: %s new_shape: %s",
                         metric, cache[f"{metric}_shape"], new.shape)
            cache[f"{metric}_shape"] = new.shape
            cache[metric] = zlib.compress(new)
 </s> add         self._data[session_id].add_live_data(timestamps, loss) </s> remove             data = self._cache.get_data(idx, "loss")
            if not data:
 </s> add             full_data = self._cache.get_data(idx, "loss")
            if not full_data: </s> remove             data = data[idx]
            retval[idx] = {title: data["loss"][:, idx] for idx, title in enumerate(data["labels"])}
 </s> add             data = full_data[idx]
            loss = data["loss"]
            assert isinstance(loss, np.ndarray)
            retval[idx] = {title: loss[:, idx] for idx, title in enumerate(data["labels"])}

            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
          dtype = "float32" if metric == "loss" else "float64"
  
          retval = {}
          for idx, data in raw.items():
            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
            array = data.loss if metric == "loss" else data.timestamps
            val: Dict[str, Union[np.ndarray, List[str]]] = {str(metric): array}
              if metric == "loss":
                  val["labels"] = data["labels"]
              retval[idx] = val
  
          logger.debug("Obtained cached data: %s",
keep keep keep keep replace replace replace replace replace keep keep keep keep keep
 Bugfixes
  - plugin.train.unbalanced - decoder b
  - gui.stats - crash when log folder deleted
  - setup.py - install gcc=12.1.0 on linux (scipy dep)
  - setup.py - don't test ROCm unless valid
  - typofix - cli_args extract singleprocess help
typing
  - lib.gui.analysis.event_reader
  - lib.gpu_stats.directml - make platform specific
unit tests
  - lib.gui.analysis.event_reader 
lib/gui/analysis/event_reader.py