class_docstr: Use MLP to fuse different models' features (single-modal and multimodal) for NER.
  Specifically, it adapts the features of each model to specified dimensions,
  concatenates the adapted features, and fuses the features through MLP.
docstr: Parameters
  ----------
  batch
      A dictionary containing the input mini-batch data. The fusion model doesn't need to
      directly access the mini-batch data since it aims to fuse the individual models'
      output features.
  Returns
  -------
  It returns dictionary containing the fusion model's logits and features.
docstr_tok: ["Parameters","--","--","--","--","--","batch","A","dictionary","containing","the","input","mini-batch","data",".","The","fusion","model","does","n't","need","to","directly","access","the","mini-batch","data","since","it","aims","to","fuse","the","individual","models'","output","features",".","Returns","--","--","--","-","It","returns","dictionary","containing","the","fusion","model","'s","logits","and","features","."]
code: def forward(
      self,
      batch: dict,
  ):
      """
      Parameters
      ----------
      batch
          A dictionary containing the input mini-batch data. The fusion model doesn't need to
          directly access the mini-batch data since it aims to fuse the individual models'
          output features.
      Returns
      -------
      It returns dictionary containing the fusion model's logits and features.
      """
      multimodal_features = []
      ner_output = run_model(self.ner_model, batch)
      for per_model, per_adapter in zip(
          self.other_models, self.adapter
      ):
          per_output = run_model(per_model, batch)
          multimodal_features.append(
              per_adapter(per_output[per_model.prefix][FEATURES])
          )
  
      features = self.fusion_mlp(torch.cat(multimodal_features, dim=1))
      features = features.unsqueeze(dim=1).repeat(
          1, ner_output[self.ner_model.prefix][FEATURES].size()[1], 1
      )
      features = torch.cat(
          (ner_output[self.ner_model.prefix][FEATURES], features),
          dim=-1,
      )
  
      logits = self.head(features)
      logits_label = torch.argmax(F.log_softmax(logits, dim=-1), dim=-1)
      fusion_output = {
          self.prefix: {
              LOGITS: logits,
              FEATURES: features,
              NER_ANNOTATION: logits_label,
              TOKEN_WORD_MAPPING: ner_output[self.ner_model.prefix][
                  TOKEN_WORD_MAPPING
              ],
              WORD_OFFSETS: ner_output[self.ner_model.prefix][
                  WORD_OFFSETS
              ],
          }
      }
  
      return fusion_output
  
file_path: autogluon/multimodal/src/autogluon/multimodal/models/fusion/fusion_ner.py
imports: import logging
  from typing import List, Optional
  import torch
  import torch.nn.functional
  from torch import nn
  from ...constants import AUTOMM, FEATURES, LABEL, LOGITS, NER_ANNOTATION, NER_TEXT, TOKEN_WORD_MAPPING, WORD_OFFSETS
  from ..mlp import MLP
  from ..utils import run_model
  from .base import AbstractMultimodalFusionModel
label_desc: Use image node_id 3 for calling the MultimodalFusionNER obj's underlying member method code with example usage: obj.forward(batch) and returns: fusion_output