class_docstr: Efficiently aggregating validation metrics during a multi-slot distributed trial is done in
  three steps:
  
  1. Gather all the values to be reduced during the reduction window (either a training or a
     validation workload).  In a multi-slot trial, this is done on each slot in parallel.
  
  2. Calculate the per-slot reduction.  This will return some intermediate value that each slot
     will contribute to the final metric calculation.  It can be as simple as a list of all the
     raw values from step 1, but reducing the intermediate value locally will distribute the
     final metric calculation more efficiently and will reduce network communication costs.
  
  3. Reduce the per-slot reduction values from Step 2 into a final metric.
  
  The MetricReducer API makes it possible for users to define a maximally efficient custom metric
  by exposing these steps to users:
  
     -  Step 1 is defined by the user; it is not part of the interface.  This flexibility
        gives the user full control when gathering individual values for reduction.
  
     -  Step 2 is the MetricReducer.per_slot_reduce() interface.
  
     -  Step 3 is the MetricReducer.cross_slot_reduce() interface.
  
     -  The MetricReducer.reset() interface allows for MetricReducer reuse across many train and
        validation workloads.
  
  Example implementation and usage:
  
  .. code:: python
  
      class MyAvgMetricReducer(pytorch.MetricReducer):
          def __init__(self):
              self.reset()
  
          def reset(self):
              self.sum = 0
              self.counts = 0
  
          # User-defined mechanism for collecting values throughout
          # training or validation. This update() mechanism demonstrates
          # a computationally- and memory-efficient way to store the values.
          def update(self, value):
              self.sum += sum(value)
              self.counts += 1
  
          def per_slot_reduce(self):
              # Because the chosen update() mechanism is so
              # efficient, this is basically a noop.
              return self.sum, self.counts
  
          def cross_slot_reduce(self, per_slot_metrics):
              # per_slot_metrics is a list of (sum, counts) tuples
              # returned by the self.pre_slot_reduce() on each slot
              sums, counts = zip(*per_slot_metrics)
              return sum(sums) / sum(counts)
  
  
      class MyPyTorchTrial(pytorch.PyTorchTrial):
          def __init__(self, context):
              # Register your custom reducer.
              self.my_avg = context.wrap_reducer(
                  MyAvgMetricReducer(), name="my_avg"
              )
              ...
  
          def train_batch(self, batch, epoch_idx, batch_idx):
              ...
              # You decide how/when you call update().
              self.my_avg.update(my_val)
  
              # The "my_avg" metric will be included in the final
              # metrics after the workload has completed; no need
              # to return it here.
              return {"loss": loss}
  
  
  See also: :meth:`determined.pytorch.PyTorchExperimentalContext.wrap_reducer`.
class_docstr_tok: ["Efficiently","aggregating","validation","metrics","during","a","multi-slot","distributed","trial","is","done","in","three","steps",":","1",".","Gather","all","the","values","to","be","reduced","during","the","reduction","window","(","either","a","training","or","a","validation","workload",")",".","In","a","multi-slot","trial",",","this","is","done","on","each","slot","in","parallel",".","2",".","Calculate","the","per-slot","reduction",".","This","will","return","some","intermediate","value","that","each","slot","will","contribute","to","the","final","metric","calculation",".","It","can","be","as","simple","as","a","list","of","all","the","raw","values","from","step","1",",","but","reducing","the","intermediate","value","locally","will","distribute","the","final","metric","calculation","more","efficiently","and","will","reduce","network","communication","costs",".","3",".","Reduce","the","per-slot","reduction","values","from","Step","2","into","a","final","metric",".","The","MetricReducer","API","makes","it","possible","for","users","to","define","a","maximally","efficient","custom","metric","by","exposing","these","steps","to","users",":","-","Step","1","is","defined","by","the","user",";","it","is","not","part","of","the","interface",".","This","flexibility","gives","the","user","full","control","when","gathering","individual","values","for","reduction",".","-","Step","2","is","the","MetricReducer.per_slot_reduce","(",")","interface",".","-","Step","3","is","the","MetricReducer.cross_slot_reduce","(",")","interface",".","-","The","MetricReducer.reset","(",")","interface","allows","for","MetricReducer","reuse","across","many","train","and","validation","workloads",".","Example","implementation","and","usage",":","..","code",":",":","python","class","MyAvgMetricReducer","(","pytorch.MetricReducer",")",":","def","__init__","(","self",")",":","self.reset","(",")","def","reset","(","self",")",":","self.sum","=","0","self.counts","=","0","#","User-defined","mechanism","for","collecting","values","throughout","#","training","or","validation",".","This","update","(",")","mechanism","demonstrates","#","a","computationally-","and","memory-efficient","way","to","store","the","values",".","def","update","(","self",",","value",")",":","self.sum","+=","sum","(","value",")","self.counts","+=","1","def","per_slot_reduce","(","self",")",":","#","Because","the","chosen","update","(",")","mechanism","is","so","#","efficient",",","this","is","basically","a","noop",".","return","self.sum",",","self.counts","def","cross_slot_reduce","(","self",",","per_slot_metrics",")",":","#","per_slot_metrics","is","a","list","of","(","sum",",","counts",")","tuples","#","returned","by","the","self.pre_slot_reduce","(",")","on","each","slot","sums",",","counts","=","zip","(","*","per_slot_metrics",")","return","sum","(","sums",")","\/","sum","(","counts",")","class","MyPyTorchTrial","(","pytorch.PyTorchTrial",")",":","def","__init__","(","self",",","context",")",":","#","Register","your","custom","reducer",".","self.my_avg","=","context.wrap_reducer","(","MyAvgMetricReducer","(",")",",","name=","''","my_avg","''",")","...","def","train_batch","(","self",",","batch",",","epoch_idx",",","batch_idx",")",":","...","#","You","decide","how\/when","you","call","update","(",")",".","self.my_avg.update","(","my_val",")","#","The","``","my_avg","''","metric","will","be","included","in","the","final","#","metrics","after","the","workload","has","completed",";","no","need","#","to","return","it","here",".","return","{","``","loss","''",":","loss","}","See","also",":",":","meth",":","`","determined.pytorch.PyTorchExperimentalContext.wrap_reducer","`","."]
docstr: Reset reducer state for another set of values.
  
  This will be called before any train or validation workload begins.
docstr_tok: ["Reset","reducer","state","for","another","set","of","values",".","This","will","be","called","before","any","train","or","validation","workload","begins","."]
code: def reset(self) -> None:
      """
      Reset reducer state for another set of values.
  
      This will be called before any train or validation workload begins.
      """
      pass
  
imports: import abc
  import enum
  import itertools
  from typing import Any, Callable, Dict, List, Optional, TypeVar, Union, overload
  import numpy
label_desc: Use image node_id 1 for calling the MetricReducer obj's underlying member method code with example usage: obj.reset() without return types