class_docstr: A training engine hybrid pipeline, data, and model parallel training.
  
  This engine is created by ``deepspeed.initialize()`` when a :class:`PipelineModule`
  is provided.
code: def _exec_backward_pass(self, buffer_id):
      assert self.optimizer is not None, (
          "must provide optimizer during "
          "init in order to use backward"
      )
  
      self.mem_status("BEFORE BWD", reset_max=True)
  
      # The last stage just runs backward on the loss using DeepSpeed's typical
      # mechanisms.
      if self.is_last_stage():
          super().backward(self.loss)
          self.mem_status("AFTER BWD")
          return
  
      outputs = self.pipe_buffers["outputs"][buffer_id]
  
      if self.wall_clock_breakdown():
          self.timers("backward_microstep").start()
          self.timers("backward").start()
          self.timers("backward_inner_microstep").start()
          self.timers("backward_inner").start()
  
      # Reconstruct if we previously partitioned the output. We must be
      # careful to also restore the computational graph of the tensors we partitioned.
      if self.is_pipe_partitioned:
          if self.is_grad_partitioned:
              part_output = PartitionedTensor.from_meta(
                  meta=outputs[0],
                  local_part=outputs[1],
                  group=self.grid.get_slice_parallel_group(),
              )
              self.pipe_buffers["output_tensors"][
                  buffer_id
              ].data = part_output.full()
              outputs = (
                  self.pipe_buffers["output_tensors"][buffer_id],
                  *outputs[2:],
              )
          else:
              # Already restored from partition
              self.pipe_buffers["output_tensors"][
                  buffer_id
              ].data = outputs[0]
              outputs = (
                  self.pipe_buffers["output_tensors"][buffer_id],
                  *outputs[1:],
              )
  
      grad_tensors = self.grad_layer
      if self.is_grad_partitioned:
          # print(f'RANK={self.global_rank} BEFORE-BWD restoring grad={self.grad_layer[0].size()} {self.grad_layer[1].size()}')
          part_grad = PartitionedTensor.from_meta(
              meta=self.grad_layer[0],
              local_part=self.grad_layer[1],
              group=self.grid.get_slice_parallel_group(),
          )
          grad_tensors = (part_grad.full(), *grad_tensors[2:])
          part_grad = None
          # print(f'RANK={self.global_rank} BEFORE-BWD restored grad={self.grad_layer[0].size()} {self.grad_layer[1].size()}')
  
      if self.bfloat16_enabled() and not self.is_last_stage():
          # manually call because we don't call optimizer.backward()
          self.optimizer.clear_lp_grads()
  
      # This handles either a single tensor or tuple of tensors.
      if isinstance(outputs, tuple):
          out_tensors = [t for t in outputs if t.is_floating_point()]
          assert len(out_tensors) == len(grad_tensors)
          torch.autograd.backward(
              tensors=out_tensors, grad_tensors=grad_tensors
          )
      else:
          torch.autograd.backward(
              tensors=(outputs,), grad_tensors=(grad_tensors,)
          )
  
      if self.bfloat16_enabled() and not self.is_last_stage():
          # manually call because we don't call optimizer.backward()
          self.optimizer.update_hp_grads(clear_lp_grads=False)
  
      # Free up the memory from the output of forward()
      self.pipe_buffers["output_tensors"][buffer_id] = None
      self.pipe_buffers["outputs"][buffer_id] = None
      grad_tensors = None
  
      if self.wall_clock_breakdown():
          self.timers("backward_inner").stop()
          self.timers("backward_inner_microstep").stop()
          self.timers("backward").stop()
          self.timers("backward_microstep").stop()
  
      self.mem_status("AFTER BWD")
  
imports: from types import MethodType
  import torch
  from deepspeed import comm
  from deepspeed.utils import logger
  from deepspeed.utils.timer import ThroughputTimer
  from ..engine import DeepSpeedEngine, MEMORY_OPT_ALLREDUCE_SIZE
  from ..utils import PartitionedTensor
  from ..dataloader import RepeatingLoader
  from .module import PipelineModule, PipelineError
  from .None import p2p
  from .None import schedule
label_desc: Use image node_id 25 for calling the PipelineEngine obj's underlying member method code with example usage: obj._exec_backward_pass(buffer_id) without return types