class_docstr: Implements a CRNN architecture as described in `"An End-to-End Trainable Neural Network for Image-based
  Sequence Recognition and Its Application to Scene Text Recognition" <https://arxiv.org/pdf/1507.05717.pdf>`_.
  
  Args:
  ----
      feature_extractor: the backbone serving as feature extractor
      vocab: vocabulary used for encoding
      rnn_units: number of units in the LSTM layers
      exportable: onnx exportable returns only logits
      cfg: configuration dictionary
class_docstr_tok: ["Implements","a","CRNN","architecture","as","described","in","`","``","An","End-to-End","Trainable","Neural","Network","for","Image-based","Sequence","Recognition","and","Its","Application","to","Scene","Text","Recognition","''","<","https",":","\/\/arxiv.org\/pdf\/1507.05717.pdf",">","`","_",".","Args",":","--","--","feature_extractor",":","the","backbone","serving","as","feature","extractor","vocab",":","vocabulary","used","for","encoding","rnn_units",":","number","of","units","in","the","LSTM","layers","exportable",":","onnx","exportable","returns","only","logits","cfg",":","configuration","dictionary"]
code: def __init__(
      self,
      feature_extractor: nn.Module,
      vocab: str,
      rnn_units: int = 128,
      input_shape: Tuple[int, int, int] = (3, 32, 128),
      exportable: bool = False,
      cfg: Optional[Dict[str, Any]] = None,
  ) -> None:
      super().__init__()
      self.vocab = vocab
      self.cfg = cfg
      self.max_length = 32
      self.exportable = exportable
      self.feat_extractor = feature_extractor
  
      # Resolve the input_size of the LSTM
      with torch.inference_mode():
          out_shape = self.feat_extractor(
              torch.zeros((1, *input_shape))
          ).shape
      lstm_in = out_shape[1] * out_shape[2]
  
      self.decoder = nn.LSTM(
          input_size=lstm_in,
          hidden_size=rnn_units,
          batch_first=True,
          num_layers=2,
          bidirectional=True,
      )
  
      # features units = 2 * rnn_units because bidirectional layers
      self.linear = nn.Linear(
          in_features=2 * rnn_units, out_features=len(vocab) + 1
      )
  
      self.postprocessor = CTCPostProcessor(vocab=vocab)
  
      for n, m in self.named_modules():
          # Don't override the initialization of the backbone
          if n.startswith("feat_extractor."):
              continue
          if isinstance(m, nn.Conv2d):
              nn.init.kaiming_normal_(
                  m.weight.data, mode="fan_out", nonlinearity="relu"
              )
              if m.bias is not None:
                  m.bias.data.zero_()
          elif isinstance(m, nn.BatchNorm2d):
              m.weight.data.fill_(1.0)
              m.bias.data.zero_()
  
imports: from copy import deepcopy
  from itertools import groupby
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import torch
  from torch import nn
  from torch.nn import functional
  from doctr.datasets import VOCABS, decode_sequence
  from ...classification import mobilenet_v3_large_r, mobilenet_v3_small_r, vgg16_bn_r
  from ...utils.pytorch import load_pretrained_params
  from ..core import RecognitionModel, RecognitionPostProcessor
label_desc: Use image node_id 1 to create a new CRNN object from inherited base classes: RecognitionModel, nn with example: obj = CRNN(feature_extractor, vocab, rnn_units, input_shape, exportable, cfg)