class_docstr: Implements a ResNet architecture
  
  Args:
  ----
      num_blocks: number of resnet block in each stage
      output_channels: number of channels in each stage
      stage_downsample: whether the first residual block of a stage should downsample
      stage_conv: whether to add a conv_sequence after each stage
      stage_pooling: pooling to add after each stage (if None, no pooling)
      origin_stem: whether to use the orginal ResNet stem or ResNet-31's
      stem_channels: number of output channels of the stem convolutions
      attn_module: attention module to use in each stage
      include_top: whether the classifier head should be instantiated
      num_classes: number of output classes
      input_shape: shape of inputs
code: def __init__(
      self,
      num_blocks: List[int],
      output_channels: List[int],
      stage_downsample: List[bool],
      stage_conv: List[bool],
      stage_pooling: List[Optional[Tuple[int, int]]],
      origin_stem: bool = True,
      stem_channels: int = 64,
      attn_module: Optional[Callable[[int], layers.Layer]] = None,
      include_top: bool = True,
      num_classes: int = 1000,
      cfg: Optional[Dict[str, Any]] = None,
      input_shape: Optional[Tuple[int, int, int]] = None,
  ) -> None:
      inplanes = stem_channels
      if origin_stem:
          _layers = [
              *conv_sequence(
                  inplanes,
                  "relu",
                  True,
                  kernel_size=7,
                  strides=2,
                  input_shape=input_shape,
              ),
              layers.MaxPool2D(
                  pool_size=(3, 3), strides=2, padding="same"
              ),
          ]
      else:
          _layers = [
              *conv_sequence(
                  inplanes // 2,
                  "relu",
                  True,
                  kernel_size=3,
                  input_shape=input_shape,
              ),
              *conv_sequence(inplanes, "relu", True, kernel_size=3),
              layers.MaxPool2D(pool_size=2, strides=2, padding="valid"),
          ]
  
      for n_blocks, out_chan, down, conv, pool in zip(
          num_blocks,
          output_channels,
          stage_downsample,
          stage_conv,
          stage_pooling,
      ):
          _layers.extend(
              resnet_stage(
                  n_blocks, out_chan, out_chan != inplanes, down
              )
          )
          if attn_module is not None:
              _layers.append(attn_module(out_chan))
          if conv:
              _layers.extend(
                  conv_sequence(
                      out_chan,
                      activation="relu",
                      bn=True,
                      kernel_size=3,
                  )
              )
          if pool:
              _layers.append(
                  layers.MaxPool2D(
                      pool_size=pool, strides=pool, padding="valid"
                  )
              )
          inplanes = out_chan
  
      if include_top:
          _layers.extend(
              [
                  layers.GlobalAveragePooling2D(),
                  layers.Dense(num_classes),
              ]
          )
  
      super().__init__(_layers)
      self.cfg = cfg
  
imports: from copy import deepcopy
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import tensorflow
  from tensorflow.keras import layers
  from tensorflow.keras.applications import ResNet50
  from tensorflow.keras.models import Sequential
  from doctr.datasets import VOCABS
  from ...utils import conv_sequence, load_pretrained_params
label_desc: Use image node_id 1 to create a new ResNet object from inherited base classes: Sequential with example: obj = ResNet(num_blocks, output_channels, stage_downsample, stage_conv, stage_pooling, origin_stem, stem_channels, attn_module, include_top, num_classes, cfg, input_shape)