docstr: Forward pass of the model.
  
  Args:
      inputs: Inputs to the model. Can be a dictionary of input names to
          input tensors or a tuple of (inputs, targets) where inputs is
          a dictionary of input names to input tensors and targets is a
          dictionary of target names to target tensors.
      mask: A mask for the inputs.
  
  Returns:
      A dictionary of output {feature name}::{tensor_name} -> output tensor.
docstr_tok: ["Forward","pass","of","the","model",".","Args",":","inputs",":","Inputs","to","the","model",".","Can","be","a","dictionary","of","input","names","to","input","tensors","or","a","tuple","of","(","inputs",",","targets",")","where","inputs","is","a","dictionary","of","input","names","to","input","tensors","and","targets","is","a","dictionary","of","target","names","to","target","tensors",".","mask",":","A","mask","for","the","inputs",".","Returns",":","A","dictionary","of","output","{","feature","name","}",":",":","{","tensor_name","}","-",">","output","tensor","."]
code: def forward(
      self,
      inputs: Union[
          Dict[str, torch.Tensor],
          Dict[str, np.ndarray],
          Tuple[Dict[str, torch.Tensor], Dict[str, torch.Tensor]],
      ],
      mask=None,
  ) -> Dict[str, torch.Tensor]:
      """Forward pass of the model.
  
      Args:
          inputs: Inputs to the model. Can be a dictionary of input names to
              input tensors or a tuple of (inputs, targets) where inputs is
              a dictionary of input names to input tensors and targets is a
              dictionary of target names to target tensors.
          mask: A mask for the inputs.
  
      Returns:
          A dictionary of output {feature name}::{tensor_name} -> output tensor.
      """
  
      if isinstance(inputs, tuple):
          inputs, targets = inputs
          # Convert targets to tensors.
          for target_feature_name, target_value in targets.items():
              if not isinstance(target_value, torch.Tensor):
                  targets[target_feature_name] = torch.from_numpy(
                      target_value
                  )
              else:
                  targets[target_feature_name] = target_value
      else:
          targets = None
  
      assert list(inputs.keys()) == self.input_features.keys()
  
      encoder_outputs = self.encode(inputs)
      combiner_outputs = self.combine(encoder_outputs)
      decoder_outputs = self.decode(combiner_outputs, targets, mask)
  
      # Compute the number of used tokens.
      decoder_outputs[USED_TOKENS] = get_used_tokens_for_ecd(
          inputs, targets
      )
      return decoder_outputs
  
imports: import logging
  import os
  from typing import Dict, Tuple, Union
  import numpy
  import torch
  from ludwig.accounting.used_tokens import get_used_tokens_for_ecd
  from ludwig.combiners.combiners import create_combiner
  from ludwig.constants import MODEL_ECD, MODEL_LLM, USED_TOKENS
  from ludwig.globals import MODEL_WEIGHTS_FILE_NAME
  from ludwig.models.base import BaseModel
  from ludwig.schema.model_types.ecd import ECDModelConfig
  from ludwig.utils import output_feature_utils
  from ludwig.utils.augmentation_utils import AugmentationPipelines
  from ludwig.utils.data_utils import clear_data_cache
  from ludwig.utils.fs_utils import open_file
  from ludwig.utils.state_dict_backward_compatibility import update_state_dict
  from ludwig.utils.torch_utils import get_torch_device
label_desc: Use image node_id 7 for calling the ECD obj's underlying member method code with example usage: obj.forward(inputs, mask) and returns: decoder_outputs