class_docstr: ContextWithImage Module.
  
  Encodes image features and context, and combines by summing or concatenation.
class_docstr_tok: ["ContextWithImage","Module",".","Encodes","image","features","and","context",",","and","combines","by","summing","or","concatenation","."]
docstr: Encode images with context.
  
  Performs early fusion, whereby image embeddings and token embeddings are computed
  before passing into the Transformer.
  
  Essentially overrides normal TransformerEncoder forward.
docstr_tok: ["Encode","images","with","context",".","Performs","early","fusion",",","whereby","image","embeddings","and","token","embeddings","are","computed","before","passing","into","the","Transformer",".","Essentially","overrides","normal","TransformerEncoder","forward","."]
code: def _forward_early_fusion(
      self,
      src_tokens: Optional[torch.LongTensor],
      image_features: Optional[Union[List[object], torch.Tensor]],
  ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
      """
      Encode images with context.
  
      Performs early fusion, whereby image embeddings and token embeddings are computed
      before passing into the Transformer.
  
      Essentially overrides normal TransformerEncoder forward.
      """
      context_tensor = context_mask = None
      image_tensor = image_mask = None
      if src_tokens is not None and image_features is not None:
          assert src_tokens.size(0) == len(image_features)
      if src_tokens is not None:
          context_tensor, context_mask = self.forward_embedding(
              src_tokens, segments=torch.zeros_like(src_tokens)  # type: ignore
          )
      if image_features is not None:
          # sometimes can just be a list of None
          valid_imgs = [
              v for v in image_features if isinstance(v, torch.Tensor)
          ]
          segments: Optional[torch.LongTensor] = None
          if valid_imgs:
              segments = torch.ones(  # type: ignore
                  (
                      len(image_features),
                      self.n_image_channels * self.n_image_tokens,
                  ),
                  dtype=torch.long,
                  device=valid_imgs[0].device,
              )
          image_tensor, image_mask = self.encode_images(
              image_features, segments=segments
          )
  
      # perform early fusion
      tensor = self._cat([context_tensor, image_tensor])
      mask: torch.BoolTensor = self._cat([context_mask, image_mask])  # type: ignore
  
      # WARNING: Below follows the rest of TransformerEncoder.forward
      if self.variant == "xlm":
          tensor = self.norm_embeddings(tensor)
      # --dropout on the embeddings
      tensor = self.dropout(tensor)
      tensor *= mask.unsqueeze(-1).type_as(tensor)
      # apply transformer layers
      tensor = self.forward_layers(tensor, mask)
      if self.variant == "prelayernorm":
          tensor = self.norm_embeddings(tensor)
      # reduce output
      tensor, out_mask = self.reduce_output(tensor, mask)
      return tensor, out_mask
  
imports: from enum import Enum
  from functools import reduce
  from typing import List, Tuple, Optional, Union
  import torch
  import torch.nn
  from parlai.agents.transformer.modules import TransformerGeneratorModel, TransformerEncoder
  from parlai.core.dict import DictionaryAgent
  from parlai.core.opt import Opt
label_desc: Use image node_id 5 for calling the ContextWithImageEncoder obj's underlying member method code with example usage: obj._forward_early_fusion(src_tokens, image_features) and returns: tensor,  out_mask