class_docstr: <a id="residual_block"></a>
  
  ## Residual Block
  
  This implements the residual block described in the paper.
  It has two $3       imes 3$ convolution layers.
  
  ![Residual Block](residual_block.svg)
  
  The first convolution layer maps from `in_channels` to `out_channels`,
  where the `out_channels` is higher than `in_channels` when we reduce the
  feature map size with a stride length greater than $1$.
  
  The second convolution layer maps from `out_channels` to `out_channels` and
  always has a stride length of 1.
  
  Both convolution layers are followed by batch normalization.
class_docstr_tok: ["<","a","id=","''","residual_block","''",">","<","\/a",">","#","#","Residual","Block","This","implements","the","residual","block","described","in","the","paper",".","It","has","two","$","3","imes","3","$","convolution","layers",".","!","[","Residual","Block","]","(","residual_block.svg",")","The","first","convolution","layer","maps","from","`","in_channels","`","to","`","out_channels","`",",","where","the","`","out_channels","`","is","higher","than","`","in_channels","`","when","we","reduce","the","feature","map","size","with","a","stride","length","greater","than","$","1","$",".","The","second","convolution","layer","maps","from","`","out_channels","`","to","`","out_channels","`","and","always","has","a","stride","length","of","1",".","Both","convolution","layers","are","followed","by","batch","normalization","."]
docstr: * `in_channels` is the number of channels in $x$
  * `out_channels` is the number of output channels
  * `stride` is the stride length in the convolution operation.
docstr_tok: ["*","`","in_channels","`","is","the","number","of","channels","in","$","x","$","*","`","out_channels","`","is","the","number","of","output","channels","*","`","stride","`","is","the","stride","length","in","the","convolution","operation","."]
code: def __init__(self, in_channels: int, out_channels: int, stride: int):
      """
      * `in_channels` is the number of channels in $x$
      * `out_channels` is the number of output channels
      * `stride` is the stride length in the convolution operation.
      """
      super().__init__()
  
      # First $3 \times 3$ convolution layer, this maps to `out_channels`
      self.conv1 = nn.Conv2d(
          in_channels,
          out_channels,
          kernel_size=3,
          stride=stride,
          padding=1,
      )
      # Batch normalization after the first convolution
      self.bn1 = nn.BatchNorm2d(out_channels)
      # First activation function (ReLU)
      self.act1 = nn.ReLU()
  
      # Second $3 \times 3$ convolution layer
      self.conv2 = nn.Conv2d(
          out_channels, out_channels, kernel_size=3, stride=1, padding=1
      )
      # Batch normalization after the second convolution
      self.bn2 = nn.BatchNorm2d(out_channels)
  
      # Shortcut connection should be a projection if the stride length is not $1$
      # or if the number of channels change
      if stride != 1 or in_channels != out_channels:
          # Projection $W_s x$
          self.shortcut = ShortcutProjection(
              in_channels, out_channels, stride
          )
      else:
          # Identity $x$
          self.shortcut = nn.Identity()
  
      # Second activation function (ReLU) (after adding the shortcut)
      self.act2 = nn.ReLU()
  
file_path: annotated_deep_learning_paper_implementations/labml_nn/resnet/__init__.py
imports: from typing import List, Optional
  import torch
  from torch import nn
  from labml_helpers.module import Module
label_desc: Use image node_id 1 to create a new ResidualBlock object from inherited base classes: Module with example: obj = ResidualBlock(in_channels, out_channels, stride)