code: def __init__(
      self,
      params,
      named_parameters,
      model,
      fp16_params,
      fp32_params,
      loss_scale,
      compression,
      backward_passes_per_step=1,
  ):
      super(self.__class__, self).__init__(params)
      self._compression = compression
  
      if named_parameters is not None:
          named_parameters = list(named_parameters)
      else:
          named_parameters = []
  
      self._model = model
      self.fp32_params = fp32_params
      self.fp16_params = fp16_params
      self.loss_scale = loss_scale
  
      # Track training steps
      # self._step = 0
  
      # make sure that named_parameters are tuples
      if any([not isinstance(p, tuple) for p in named_parameters]):
          raise ValueError(
              "named_parameters should be a sequence of "
              "tuples (name, parameter), usually produced by "
              "model.named_parameters()."
          )
  
      dups = _HalfPrecisionDistributedOptimizer.find_duplicates(
          [k for k, _ in named_parameters]
      )
      if len(dups) > 0:
          raise ValueError(
              "Parameter names in named_parameters must be unique. "
              "Found duplicates: %s" % ", ".join(dups)
          )
  
      if len(named_parameters) > 0:
          if isinstance(named_parameters[0][1], torch.Tensor):
              if any(
                  [
                      not isinstance(p, torch.Tensor)
                      for name, p in named_parameters
                  ]
              ):
                  raise ValueError(
                      "named_parameters should consistently be a sequence of "
                      "tuples (name, torch.Tensor)"
                  )
              self._is_tensor_instance = True
              # there is an issue when using torch.Tensor as key, so use its hash instead
              # https://github.com/pytorch/pytorch/issues/7733
              self._parameter_names = {
                  v.__hash__(): k for k, v in sorted(named_parameters)
              }
              self._tensor_list = [
                  tensor for name, tensor in named_parameters
              ]
          else:
              self._is_tensor_instance = False
              self._parameter_names = {
                  v: k for k, v in sorted(named_parameters)
              }
      else:
          self._is_tensor_instance = False
          self._parameter_names = {
              v: "push_pull.noname.%s" % i
              for param_group in self.param_groups
              for i, v in enumerate(param_group["params"])
          }
  
      self._fp32_to_fp16_map = {}
      self._fp16_to_fp32_map = {}
      for fp16_p, fp32_p in zip(self.fp16_params, self.fp32_params):
          if self._is_tensor_instance:
              self._fp32_to_fp16_map[fp32_p.__hash__()] = fp16_p
          else:
              self._fp32_to_fp16_map[fp32_p] = fp16_p
          self._fp16_to_fp32_map[fp16_p] = fp32_p
  
      self.backward_passes_per_step = backward_passes_per_step
      self._push_pull_delay = {
          v: self.backward_passes_per_step
          for _, v in sorted(named_parameters)
      }
      self._handles = {}
      self._grad_accs = []
      self._requires_update = set()
  
      if size() > 1:
          self._register_forward_hooks()
          self._register_backward_hooks()
  
      self._lock = threading.Lock()
  
      # declare tensors
      for name in self._parameter_names.values():
          declare("Gradient." + name)
      # We use two loops for load-balancing
      for name in self._parameter_names.values():
          declare("Parameter." + name)
  
      self.priorities = {}
      self.gradient_count = 0
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from byteps.torch import _DistributedOptimizer
  from byteps.torch.compression import Compression
  from byteps.torch.ops import push_pull_async_inplace
  from byteps.torch.ops import push_pull
  from byteps.torch.ops import poll, synchronize, declare
  from byteps.torch.ops import init, shutdown
  from byteps.torch.ops import size, local_size, rank, local_rank
  import time
  import threading
  import torch
  import collections
label_desc: Use image node_id 1 to create a new _HalfPrecisionDistributedOptimizer object from inherited base classes: torch.optim with example: obj = _HalfPrecisionDistributedOptimizer(params, named_parameters, model, fp16_params, fp32_params, loss_scale, compression, backward_passes_per_step)