class_docstr: Resnet block with optional bottleneck activated by default
  Arguments:
      down_conv_nn (len of 2 or 3) :
                      sizes of input, intermediate, output.
                      If length == 2 then intermediate =  num_outputs // 4
      radius : radius of the conv kernel
      sigma :
      density_parameter : density parameter for the kernel
      max_num_neighbors : maximum number of neighboors for the neighboor search
      activation : activation function
      has_bottleneck: wether to use the bottleneck or not
      bn_momentum
      bn : batch norm (can be None -> no batch norm)
      grid_size : size of the grid,
      prev_grid_size : size of the grid at previous step.
                      In case of a strided block, this is different than grid_size
class_docstr_tok: ["Resnet","block","with","optional","bottleneck","activated","by","default","Arguments",":","down_conv_nn","(","len","of","2","or","3",")",":","sizes","of","input",",","intermediate",",","output",".","If","length","==","2","then","intermediate","=","num_outputs","\/\/","4","radius",":","radius","of","the","conv","kernel","sigma",":","density_parameter",":","density","parameter","for","the","kernel","max_num_neighbors",":","maximum","number","of","neighboors","for","the","neighboor","search","activation",":","activation","function","has_bottleneck",":","wether","to","use","the","bottleneck","or","not","bn_momentum","bn",":","batch","norm","(","can","be","None","-",">","no","batch","norm",")","grid_size",":","size","of","the","grid",",","prev_grid_size",":","size","of","the","grid","at","previous","step",".","In","case","of","a","strided","block",",","this","is","different","than","grid_size"]
code: def __init__(
      self,
      down_conv_nn=None,
      grid_size=None,
      prev_grid_size=None,
      sigma=1,
      max_num_neighbors=16,
      activation=torch.nn.LeakyReLU(negative_slope=0.1),
      has_bottleneck=True,
      bn_momentum=0.02,
      bn=FastBatchNorm1d,
      deformable=False,
      add_one=False,
      **kwargs,
  ):
      super(ResnetBBlock, self).__init__()
      assert (
          len(down_conv_nn) == 2 or len(down_conv_nn) == 3
      ), "down_conv_nn should be of size 2 or 3"
      if len(down_conv_nn) == 2:
          num_inputs, num_outputs = down_conv_nn
          d_2 = num_outputs // 4
      else:
          num_inputs, d_2, num_outputs = down_conv_nn
      self.is_strided = prev_grid_size != grid_size
      self.has_bottleneck = has_bottleneck
  
      # Main branch
      if self.has_bottleneck:
          kp_size = [d_2, d_2]
      else:
          kp_size = [num_inputs, num_outputs]
  
      self.kp_conv = SimpleBlock(
          down_conv_nn=kp_size,
          grid_size=grid_size,
          prev_grid_size=prev_grid_size,
          sigma=sigma,
          max_num_neighbors=max_num_neighbors,
          activation=activation,
          bn_momentum=bn_momentum,
          bn=bn,
          deformable=deformable,
          add_one=add_one,
          **kwargs,
      )
  
      if self.has_bottleneck:
          if bn:
              self.unary_1 = torch.nn.Sequential(
                  Lin(num_inputs, d_2, bias=False),
                  bn(d_2, momentum=bn_momentum),
                  activation,
              )
              self.unary_2 = torch.nn.Sequential(
                  Lin(d_2, num_outputs, bias=False),
                  bn(num_outputs, momentum=bn_momentum),
                  activation,
              )
          else:
              self.unary_1 = torch.nn.Sequential(
                  Lin(num_inputs, d_2, bias=False), activation
              )
              self.unary_2 = torch.nn.Sequential(
                  Lin(d_2, num_outputs, bias=False), activation
              )
  
      # Shortcut
      if num_inputs != num_outputs:
          if bn:
              self.shortcut_op = torch.nn.Sequential(
                  Lin(num_inputs, num_outputs, bias=False),
                  bn(num_outputs, momentum=bn_momentum),
              )
          else:
              self.shortcut_op = Lin(
                  num_inputs, num_outputs, bias=False
              )
      else:
          self.shortcut_op = torch.nn.Identity()
  
      # Final activation
      self.activation = activation
  
imports: import torch
  import sys
  from torch.nn import Linear
  from .kernels import KPConvLayer, KPConvDeformableLayer
  from torch_points3d.core.common_modules.base_modules import BaseModule, FastBatchNorm1d
  from torch_points3d.core.spatial_ops import RadiusNeighbourFinder
  from torch_points3d.core.data_transform import GridSampling3D
  from torch_points3d.utils.enums import ConvolutionFormat
  from torch_points3d.core.base_conv.message_passing import GlobalBaseModule
  from torch_points3d.core.common_modules.base_modules import Identity
  from torch_points3d.utils.config import is_list
label_desc: Use image node_id 1 to create a new ResnetBBlock object from inherited base classes: BaseModule with example: obj = ResnetBBlock(down_conv_nn, grid_size, prev_grid_size, sigma, max_num_neighbors, activation, has_bottleneck, bn_momentum, bn, deformable, add_one)