class_docstr: LSTM-based decoder over multiple time steps.
class_docstr_tok: ["LSTM-based","decoder","over","multiple","time","steps","."]
docstr: Runs max_sequence_length LSTM decoding time steps.
  
  Args:
      combiner_outputs: Dictionary of tensors from the outputs of the combiner and other output features.
      target: Tensor [batch_size, max_sequence_length] with target symbols.
  
  Returns:
      Tensor of logits [batch_size, max_sequence_length, vocab_size].
docstr_tok: ["Runs","max_sequence_length","LSTM","decoding","time","steps",".","Args",":","combiner_outputs",":","Dictionary","of","tensors","from","the","outputs","of","the","combiner","and","other","output","features",".","target",":","Tensor","[","batch_size",",","max_sequence_length","]","with","target","symbols",".","Returns",":","Tensor","of","logits","[","batch_size",",","max_sequence_length",",","vocab_size","]","."]
code: def forward(
      self,
      combiner_outputs: Dict[str, torch.Tensor],
      target: torch.Tensor,
  ) -> torch.Tensor:
      """Runs max_sequence_length LSTM decoding time steps.
  
      Args:
          combiner_outputs: Dictionary of tensors from the outputs of the combiner and other output features.
          target: Tensor [batch_size, max_sequence_length] with target symbols.
  
      Returns:
          Tensor of logits [batch_size, max_sequence_length, vocab_size].
      """
      # Prepare the decoder initial state.
      decoder_hidden, decoder_cell_state = get_lstm_init_state(
          combiner_outputs, self.reduce_sequence, self.num_layers
      )
      batch_size = decoder_hidden.size()[1]
  
      # Initialize the decoder with start symbols.
      decoder_input = self.decoder_input.repeat(batch_size)
  
      # Tensor to store decoder output logits.
      logits = self.logits.unsqueeze(0).repeat(batch_size, 1, 1)
  
      # Decode until max length.
      for di in range(self.max_sequence_length):
          (
              decoder_output,
              decoder_hidden,
              decoder_cell_state,
          ) = self.lstm_decoder(
              decoder_input, decoder_hidden, decoder_cell_state
          )
  
          # decoder_output: [batch_size, 1, vocab_size]
          # Squeeze out the multilayer dimension and save logits.
          logits[:, di, :] = decoder_output.squeeze(1)
  
          # Determine inputs for next time step.
          # Using teacher forcing causes the model to converge faster but when the trained network is exploited, it
          # may be unstable: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.378.4095&rep=rep1&type=pdf.
          # TODO: Use a configurable ratio for how often to use teacher forcing during training.
          if target is None:
              _, topi = decoder_output.topk(1)
              # Squeeze out multilayer and vocabulary dimensions.
              decoder_input = (
                  topi.squeeze(1).squeeze(1).detach()
              )  # detach from history as input
          else:
              # Teacher forcing.
              decoder_input = target[:, di]
  
      return logits
  
imports: import logging
  from typing import Dict, Tuple
  import torch
  import torch.nn
  from ludwig.api_annotations import DeveloperAPI
  from ludwig.constants import LOGITS, PREDICTIONS, PROBABILITIES, SEQUENCE, TEXT
  from ludwig.decoders.base import Decoder
  from ludwig.decoders.registry import register_decoder
  from ludwig.decoders.sequence_decoder_utils import get_lstm_init_state, get_rnn_init_state
  from ludwig.modules.reduction_modules import SequenceReducer
  from ludwig.schema.decoders.sequence_decoders import SequenceGeneratorDecoderConfig
  from ludwig.utils import strings_utils
label_desc: Use image node_id 2 for calling the SequenceLSTMDecoder obj's underlying member method code with example usage: obj.forward(combiner_outputs, target) and returns: logits