class_docstr: Decoder model with a language modeling head on top for ONNX Runtime inference.
class_docstr_tok: ["Decoder","model","with","a","language","modeling","head","on","top","for","ONNX","Runtime","inference","."]
code: def forward(
      self,
      input_ids: torch.LongTensor,
      encoder_hidden_states: torch.FloatTensor,
      decoder_attention_mask: Optional[torch.LongTensor] = None,
      encoder_attention_mask: Optional[torch.LongTensor] = None,
      past_key_values: Optional[Tuple[Tuple[torch.FloatTensor]]] = None,
      labels: Optional[torch.LongTensor] = None,
      use_cache_branch: None = None,
  ) -> Seq2SeqLMOutput:
      # Adding use_cache_branch in the signature here is just a hack for IO Binding
  
      use_torch = isinstance(input_ids, torch.Tensor)
      self.parent_model.raise_on_numpy_input_io_binding(use_torch)
  
      # Flatten the past_key_values
      if past_key_values is not None:
          past_key_values = tuple(
              past_key_value
              for pkv_per_layer in past_key_values
              for past_key_value in pkv_per_layer
          )
  
      # no-ops if merged decoder is not used
      use_merged_no_cache = (
          past_key_values is None and self.parent_model.use_merged
      )
      use_merged_cache = (
          past_key_values is not None and self.parent_model.use_merged
      )
      (
          use_cache_branch_tensor,
          past_key_values,
      ) = self.prepare_inputs_for_merged(
          input_ids, past_key_values, use_torch=use_torch
      )
  
      if self.parent_model.use_io_binding:
          known_output_shapes = (
              self.compute_past_key_values_output_shapes(
                  input_ids,
                  encoder_hidden_states,
                  use_cache_branch=use_cache_branch_tensor.item()
                  if use_cache_branch_tensor is not None
                  else None,
                  past_key_values=past_key_values,
              )
          )
  
          outputs_to_not_bind = self.get_outputs_not_to_bind(
              use_merged_cache
          )
  
          model_inputs = [input_ids]
  
          if "encoder_hidden_states" in self.input_names:
              model_inputs.append(encoder_hidden_states)
  
          if "decoder_attention_mask" in self.input_names:
              model_inputs.append(decoder_attention_mask)
  
          if "encoder_attention_mask" in self.input_names:
              model_inputs.append(encoder_attention_mask)
  
          if past_key_values is not None:
              model_inputs += past_key_values
  
          if "labels" in self.input_names:
              model_inputs.append(labels)
              known_output_shapes.update({"loss": []})
  
          if use_cache_branch_tensor is not None:
              model_inputs.append(use_cache_branch_tensor)
  
          (
              io_binding,
              output_shapes,
              output_buffers,
          ) = self.parent_model._prepare_io_binding(
              self.session,
              *model_inputs,
              known_output_shapes=known_output_shapes,
              ordered_input_names=self._ordered_input_names,
              outputs_to_not_bind=outputs_to_not_bind,
          )
  
          # Set -1 for sequence_length as it could be larger than the real sequence_length
          for name, shape in output_shapes.items():
              if name in self.key_value_output_names:
                  output_shapes[name] = shape[:2] + (-1,) + shape[3:]
  
          io_binding.synchronize_inputs()
          self.session.run_with_iobinding(io_binding)
          io_binding.synchronize_outputs()
  
          # Tuple of length equal to : number of layer * number of past_key_value per decoder layer (2 corresponds to the
          # self-attention layer and 2 to the cross-attention layer)
          out_past_key_values = ()
          for name in self.key_value_output_names:
              # TODO: this should be improved
              if (
                  name
                  in self.past_key_values_cross_attention_output_names
                  and use_merged_cache
              ):
                  continue
              out_past_key_values += (
                  output_buffers[name].view(output_shapes[name]),
              )
  
          logits = output_buffers["logits"].view(
              output_shapes["logits"]
          )
  
          loss = None
          if "loss" in self.output_names:
              loss = output_buffers["loss"].view(output_shapes["loss"])
  
          if not self.use_past_in_outputs:
              out_past_key_values = None
          elif not self.use_past_in_inputs or use_merged_no_cache:
              out_past_key_values = tuple(
                  out_past_key_values[i : i + self.num_pkv]
                  for i in range(
                      0, len(out_past_key_values), self.num_pkv
                  )
              )
          else:
              if self.use_legacy_outputs is True:
                  msg = (
                      "For the decoder with past, using ONNX models outputting cross attention past key values"
                      " is deprecated and the support will be removed in optimum 2.0. We recommend exporting again the model"
                      " with optimum>=1.7.3."
                  )
                  warn_once(logger, msg=msg)
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + self.num_pkv]
                      for i in range(
                          0, len(out_past_key_values), self.num_pkv
                      )
                  )
              # grab the cross attention key/values from the inputs
              elif self.num_pkv == 2:
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + self.num_pkv]
                      + past_key_values[
                          2 * i + 2 : 2 * i + 2 + self.num_pkv
                      ]
                      for i in range(
                          0, len(out_past_key_values), self.num_pkv
                      )
                  )
              elif self.num_pkv == 4:
                  # despite num_pkv being 4, we did not bind the cross-attention output
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + 2]
                      + past_key_values[2 * i + 2 : 2 * i + 4]
                      for i in range(0, len(out_past_key_values), 2)
                  )
              else:
                  raise ValueError("Unsupported num_pkv")
      else:
          if use_torch:
              onnx_inputs = {
                  "input_ids": input_ids.cpu().detach().numpy(),
              }
  
              # Add the encoder_hidden_states inputs when needed
              if "encoder_hidden_states" in self.input_names:
                  onnx_inputs["encoder_hidden_states"] = (
                      encoder_hidden_states.cpu().detach().numpy()
                  )
  
              # Add the decoder_attention_mask inputs when needed
              if "decoder_attention_mask" in self.input_names:
                  onnx_inputs["decoder_attention_mask"] = (
                      decoder_attention_mask.cpu().detach().numpy()
                  )
  
              # Add the encoder_attention_mask inputs when needed
              if "encoder_attention_mask" in self.input_names:
                  onnx_inputs["encoder_attention_mask"] = (
                      encoder_attention_mask.cpu().detach().numpy()
                  )
  
              if past_key_values is not None:
                  # Add the past_key_values to the decoder inputs
                  for input_name, past_key_value in zip(
                      self.key_value_input_names, past_key_values
                  ):
                      onnx_inputs[input_name] = (
                          past_key_value.cpu().detach().numpy()
                      )
  
              if "labels" in self.input_names:
                  # TODO: Any preprocessing like  `self._shift_right(labels)`?
                  onnx_inputs["labels"] = labels.cpu().detach().numpy()
  
              if self.parent_model.use_merged is True:
                  onnx_inputs["use_cache_branch"] = (
                      use_cache_branch_tensor.cpu().detach().numpy()
                  )
          else:
              onnx_inputs = {
                  "input_ids": input_ids,
              }
  
              # Add the encoder_hidden_states inputs when needed
              if "encoder_hidden_states" in self.input_names:
                  onnx_inputs[
                      "encoder_hidden_states"
                  ] = encoder_hidden_states
  
              # Add the decoder_attention_mask inputs when needed
              if "decoder_attention_mask" in self.input_names:
                  onnx_inputs[
                      "decoder_attention_mask"
                  ] = decoder_attention_mask
  
              # Add the encoder_attention_mask inputs when needed
              if "encoder_attention_mask" in self.input_names:
                  onnx_inputs[
                      "encoder_attention_mask"
                  ] = encoder_attention_mask
  
              if past_key_values is not None:
                  # Add the past_key_values to the decoder inputs
                  for input_name, past_key_value in zip(
                      self.key_value_input_names, past_key_values
                  ):
                      onnx_inputs[input_name] = past_key_value
  
              if "labels" in self.input_names:
                  # TODO: Any preprocessing like  `self._shift_right(labels)`?
                  onnx_inputs["labels"] = labels
  
              if self.parent_model.use_merged is True:
                  onnx_inputs[
                      "use_cache_branch"
                  ] = use_cache_branch_tensor
  
          # Run inference
          outputs = self.session.run(None, onnx_inputs)
  
          # TODO: using two loops here is probably unefficient
          # Tuple of length equal to : number of layer * number of past_key_value per decoder layer (2 corresponds to the
          # self-attention layer and 2 to the cross-attention layer)
          out_past_key_values = tuple(
              torch.from_numpy(outputs[self.output_names[key]]).to(
                  self.device
              )
              for key in self.key_value_output_names
          )
  
          logits = outputs[self.output_names["logits"]]
          if use_torch:
              logits = torch.from_numpy(logits).to(self.device)
  
          loss = None
          if "loss" in self.output_names:
              loss = outputs[self.output_names["loss"]]
              if use_torch:
                  loss = torch.from_numpy(loss).to(self.device)
  
          # TODO: this is extremely ugly and unreadable. What if cross-attention k/v change?
          # Tuple of tuple of length `n_layers`, with each tuple of length equal to:
          # * 4 for the decoder without cache (k/v of self-attention + k/v of cross-attention)
          # * 2 for the decoder with cache (k/v of self-attention as cross-attention cache is constant)
          if not self.use_past_in_outputs:
              out_past_key_values = None
          elif (
              not self.use_past_in_inputs
              or use_merged_no_cache
              or self.no_cross_attention_cache
          ):
              out_past_key_values = tuple(
                  out_past_key_values[i : i + self.num_pkv]
                  for i in range(
                      0, len(out_past_key_values), self.num_pkv
                  )
              )
          else:
              if self.use_legacy_outputs is True:
                  msg = (
                      "For the decoder with past, using ONNX models outputting cross attention past key values"
                      " is deprecated and the support will be removed in optimum 2.0. We recommend exporting again the model"
                      " with optimum>=1.7.3."
                  )
                  warn_once(logger, msg=msg)
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + self.num_pkv]
                      for i in range(
                          0, len(out_past_key_values), self.num_pkv
                      )
                  )
              # grab the cross attention key/values from the inputs
              elif self.num_pkv == 2:
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + self.num_pkv]
                      + past_key_values[
                          2 * i + 2 : 2 * i + 2 + self.num_pkv
                      ]
                      for i in range(
                          0, len(out_past_key_values), self.num_pkv
                      )
                  )
              elif self.num_pkv == 4:
                  out_past_key_values = tuple(
                      out_past_key_values[i : i + 2]
                      + past_key_values[i + 2 : i + 4]
                      for i in range(
                          0, len(out_past_key_values), self.num_pkv
                      )
                  )
              else:
                  raise ValueError("Unsupported num_pkv")
  
      return Seq2SeqLMOutput(
          loss=loss, logits=logits, past_key_values=out_past_key_values
      )
  
imports: from abc import abstractmethod
  from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple, Union
  import numpy
  import torch
  from transformers.modeling_outputs import BaseModelOutput, Seq2SeqLMOutput
  from onnxruntime import InferenceSession
  from ..utils import NormalizedConfigManager
  from ..utils.logging import warn_once
  from .utils import get_ordered_input_names, logging
label_desc: Use image node_id 4 for calling the ORTDecoderForSeq2Seq obj's underlying member method code with example usage: obj.forward(input_ids, encoder_hidden_states, decoder_attention_mask, encoder_attention_mask, past_key_values, labels, use_cache_branch) and returns: Seq2SeqLMOutput