class_docstr: Implementation of encoder module in `SAR.
  
  <https://arxiv.org/abs/1811.00751>`_.
  
  Args:
      enc_bi_rnn (bool): If True, use bidirectional RNN in encoder.
          Defaults to False.
      rnn_dropout (float): Dropout probability of RNN layer in encoder.
          Defaults to 0.0.
      enc_gru (bool): If True, use GRU, else LSTM in encoder. Defaults
          to False.
      d_model (int): Dim :math:`D_i` of channels from backbone. Defaults
          to 512.
      d_enc (int): Dim :math:`D_m` of encoder RNN layer. Defaults to 512.
      mask (bool): If True, mask padding in RNN sequence. Defaults to
          True.
      init_cfg (dict or list[dict], optional): Initialization configs.
          Defaults to [dict(type='Xavier', layer='Conv2d'),
          dict(type='Uniform', layer='BatchNorm2d')].
docstr: Args:
      feat (Tensor): Tensor of shape :math:`(N, D_i, H, W)`.
      data_samples (list[TextRecogDataSample], optional): Batch of
          TextRecogDataSample, containing valid_ratio information.
          Defaults to None.
  
  Returns:
      Tensor: A tensor of shape :math:`(N, D_m)`.
code: def forward(
      self,
      feat: torch.Tensor,
      data_samples: Optional[Sequence[TextRecogDataSample]] = None,
  ) -> torch.Tensor:
      """
      Args:
          feat (Tensor): Tensor of shape :math:`(N, D_i, H, W)`.
          data_samples (list[TextRecogDataSample], optional): Batch of
              TextRecogDataSample, containing valid_ratio information.
              Defaults to None.
  
      Returns:
          Tensor: A tensor of shape :math:`(N, D_m)`.
      """
      if data_samples is not None:
          assert len(data_samples) == feat.size(0)
  
      valid_ratios = None
      if data_samples is not None:
          valid_ratios = (
              [
                  data_sample.get("valid_ratio", 1.0)
                  for data_sample in data_samples
              ]
              if self.mask
              else None
          )
  
      h_feat = feat.size(2)
      feat_v = F.max_pool2d(
          feat, kernel_size=(h_feat, 1), stride=1, padding=0
      )
      feat_v = feat_v.squeeze(2)  # bsz * C * W
      feat_v = feat_v.permute(0, 2, 1).contiguous()  # bsz * W * C
  
      holistic_feat = self.rnn_encoder(feat_v)[0]  # bsz * T * C
  
      if valid_ratios is not None:
          valid_hf = []
          T = holistic_feat.size(1)
          for i, valid_ratio in enumerate(valid_ratios):
              valid_step = min(T, math.ceil(T * valid_ratio)) - 1
              valid_hf.append(holistic_feat[i, valid_step, :])
          valid_hf = torch.stack(valid_hf, dim=0)
      else:
          valid_hf = holistic_feat[:, -1, :]  # bsz * C
  
      holistic_feat = self.linear(valid_hf)  # bsz * C
  
      return holistic_feat
  
file_path: mmocr/mmocr/models/textrecog/encoders/sar_encoder.py
imports: import math
  from typing import Dict, Optional, Sequence, Union
  import torch
  import torch.nn
  import torch.nn.functional
  from mmocr.registry import MODELS
  from mmocr.structures import TextRecogDataSample
  from .base import BaseEncoder
label_desc: Use image node_id 2 for calling the SAREncoder obj's underlying member method code with example usage: obj.forward(feat, data_samples) and returns: holistic_feat