class_docstr: VinVL Bert Encoder for image features
  From https://github.com/microsoft/Oscar/blob/master/oscar/modeling/modeling_bert.py
  Is a thin wrapper around BertEncoder that handles image features
code: def forward(
      self,
      input_ids: Tensor,
      img_feats: Tensor,
      token_type_ids: Optional[Tensor] = None,
      attention_mask: Optional[Tensor] = None,
      position_ids: Optional[Tensor] = None,
  ) -> Tuple[Tensor]:
      if attention_mask is None:
          attention_mask = torch.ones(
              (input_ids.size(0), input_ids.size(1) + img_feats.size(1))
          ).to(input_ids.device)
      if token_type_ids is None:
          token_type_ids = torch.zeros_like(input_ids)
      # We can provide a self-attention mask of dimensions
      # [batch_size, from_seq_length, to_seq_length]
      # ourselves in which case we just need to make it broadcastable to all heads.
      # attention_mask with dim 3 is to specify a unique mask for each feature,
      # it is broadcast over heads.
      if attention_mask.dim() == 3:
          extended_attention_mask = attention_mask[:, None, :, :]
      elif attention_mask.dim() == 2:
          # Provided a padding mask of dimensions [batch_size, seq_length]
          # Make the mask broadcastable to
          # [batch_size, num_heads, seq_length, seq_length]
          extended_attention_mask = attention_mask[:, None, None, :]
      else:
          raise ValueError(
              f"Wrong shape for input_ids (shape {input_ids.shape})"
              + " or attention_mask (shape {attention_mask.shape})"
          )
  
      # Since attention_mask is 1.0 for positions we want to attend and 0.0 for
      # masked positions, this operation will create a tensor which is 0.0 for
      # positions we want to attend and -10000.0 for masked positions.
      # Since we are adding it to the raw scores before the softmax, this is
      # effectively the same as removing these entirely.
      extended_attention_mask = extended_attention_mask.to(
          dtype=self.dtype
      )
      extended_attention_mask = (
          1.0 - extended_attention_mask
      ) * -10000.0
  
      # Do embeddings
      text_embedding_output = self.embeddings(
          input_ids,
          position_ids=position_ids,
          token_type_ids=token_type_ids,
      )
      img_embedding_output = self.img_embedding(img_feats)
      embedding_output = torch.cat(
          (text_embedding_output, img_embedding_output), 1
      )
  
      encoder_outputs = self.encoder(
          embedding_output,
          extended_attention_mask,
          output_hidden_states=True,
      )
      layers = namedtuple(
          "TransformerOutput", ["last_hidden_state", "hidden_layers"]
      )
      return layers(encoder_outputs[0], encoder_outputs[1])
  
imports: import logging
  from collections import namedtuple
  from dataclasses import asdict, dataclass
  from typing import Any, Dict, Optional, Tuple
  import torch
  from mmf.common.registry import registry
  from mmf.common.sample import SampleList
  from mmf.models.base_model import BaseModel
  from mmf.models.transformers.heads.contrastive import ThreeWayContrastive
  from mmf.models.transformers.heads.mlm import MLM
  from mmf.models.transformers.heads.mlp import MLP
  from mmf.utils.general import retry_n
  from omegaconf import MISSING, OmegaConf
  from torch import nn, Tensor
label_desc: Use image node_id 2 for calling the VinVLBase obj's underlying member method code with example usage: obj.forward(input_ids, img_feats, token_type_ids, attention_mask, position_ids) and returns: layers