class_docstr: This method should have a common interface such that it can be called after
  the encoder as well as after the decoder
class_docstr_tok: ["This","method","should","have","a","common","interface","such","that","it","can","be","called","after","the","encoder","as","well","as","after","the","decoder"]
docstr: Decoder step inputs correspond one-to-one to encoder outputs.
  HOWEVER: after the first step, encoder outputs (i.e, the first
  len(self.models) elements of inputs) must be tiled k (beam size)
  times on the batch dimension (axis 1).
docstr_tok: ["Decoder","step","inputs","correspond","one-to-one","to","encoder","outputs",".","HOWEVER",":","after","the","first","step",",","encoder","outputs","(","i.e",",","the","first","len","(","self.models",")","elements","of","inputs",")","must","be","tiled","k","(","beam","size",")","times","on","the","batch","dimension","(","axis","1",")","."]
code: def forward(
      self,
      prev_tokens: Tensor,
      prev_scores: Tensor,
      timestep: int,
      decoder_ips: List[Dict[str, Tensor]],
  ) -> Tuple[Tensor, Tensor, Tensor, Tensor, List[Dict[str, Tensor]]]:
      """
      Decoder step inputs correspond one-to-one to encoder outputs.
      HOWEVER: after the first step, encoder outputs (i.e, the first
      len(self.models) elements of inputs) must be tiled k (beam size)
      times on the batch dimension (axis 1).
      """
  
      # from flat to (batch x 1)
      prev_tokens = prev_tokens.unsqueeze(1)
  
      log_probs_per_model = torch.jit.annotate(List[Tensor], [])
      attn_weights_per_model = torch.jit.annotate(List[Tensor], [])
  
      futures = torch.jit.annotate(
          List[Tuple[Tensor, Dict[str, Tensor]]], []
      )
      for idx, model in enumerate(self.models):
          decoder_ip = decoder_ips[idx]
          incremental_state = self.incremental_states[str(idx)]
          # jit.fork() once https://github.com/pytorch/pytorch/issues/26578
          # lands
          fut = model.decoder(
              prev_tokens,
              decoder_ip,
              incremental_state=incremental_state,
              timestep=timestep,
          )
          futures.append(fut)
  
      # We do this in two separate loops only to permit model level parallelism
      # We fork in the first loop and wait in the second
      for idx, _model in enumerate(self.models):
          # jit.wait()
          fut = futures[idx]
          log_probs, features = fut
          log_probs_per_model.append(log_probs)
          if "attn_scores" in features:
              attn_weights_per_model.append(features["attn_scores"])
  
      (
          best_scores,
          best_tokens,
          prev_hypos,
          attention_weights,
      ) = self.beam_search_aggregate_topk(
          log_probs_per_model,
          attn_weights_per_model,
          prev_scores,
          self.beam_size,
          self.record_attention,
      )
  
      for model_state_ptr, model in enumerate(self.models):
          incremental_state = self.incremental_states[
              str(model_state_ptr)
          ]
          model.decoder.reorder_incremental_state(
              incremental_state, prev_hypos
          )
  
      return (
          best_tokens,
          best_scores,
          prev_hypos,
          attention_weights,
          decoder_ips,
      )
  
file_path: pytext/pytext/torchscript/seq2seq/decoder.py
imports: from typing import Dict, List, Tuple
  import torch
  import torch.jit
  import torch.jit.quantized
  from torch import nn, Tensor
label_desc: Use image node_id 3 for calling the DecoderBatchedStepEnsemble obj's underlying member method code with example usage: obj.forward(prev_tokens, prev_scores, timestep, decoder_ips) and returns: best_tokens,  best_scores,  prev_hypos,  attention_weights,  decoder_ips