class_docstr: PPNet Stage block (usually strided + non strided)
  
  Arguments: Accepted kwargs
      block_names: Name of the blocks to be used as part of this dual block
      down_conv_nn: Size of the convs e.g. [64,128],
      grid_size: Size of the grid for each block,
      prev_grid_size: Size of the grid in the previous KPConv
      has_bottleneck: Wether a block should implement the bottleneck
      bottleneck_ratio: bottleneck ratio, intermediate =  num_outputs // bottleneck ratio
      max_num_neighbors: Max number of neighboors for the radius search,
      position_embedding: Position Embedding type
      reduction: Reduction type in local aggregation
      output_conv: whether to use a convolution after aggregation
      bn_momentum: the value used for the running_mean and running_var
class_docstr_tok: ["PPNet","Stage","block","(","usually","strided","+","non","strided",")","Arguments",":","Accepted","kwargs","block_names",":","Name","of","the","blocks","to","be","used","as","part","of","this","dual","block","down_conv_nn",":","Size","of","the","convs","e.g",".","[","64,128","]",",","grid_size",":","Size","of","the","grid","for","each","block",",","prev_grid_size",":","Size","of","the","grid","in","the","previous","KPConv","has_bottleneck",":","Wether","a","block","should","implement","the","bottleneck","bottleneck_ratio",":","bottleneck","ratio",",","intermediate","=","num_outputs","\/\/","bottleneck","ratio","max_num_neighbors",":","Max","number","of","neighboors","for","the","radius","search",",","position_embedding",":","Position","Embedding","type","reduction",":","Reduction","type","in","local","aggregation","output_conv",":","whether","to","use","a","convolution","after","aggregation","bn_momentum",":","the","value","used","for","the","running_mean","and","running_var"]
code: def __init__(
      self,
      block_names=None,
      down_conv_nn=None,
      grid_size=None,
      prev_grid_size=None,
      has_bottleneck=None,
      bottleneck_ratio=None,
      max_num_neighbors=None,
      position_embedding=None,
      reduction=None,
      output_conv=None,
      bn_momentum=None,
      **kwargs,
  ):
      super(PPStageBlock, self).__init__()
  
      assert len(block_names) == len(down_conv_nn)
  
      self.blocks = torch.nn.ModuleList()
      for i, class_name in enumerate(block_names):
          # Constructing extra keyword arguments
          block_kwargs = {}
          for key, arg in kwargs.items():
              block_kwargs[key] = arg[i] if is_list(arg) else arg
  
          # Building the block
          aggcls = getattr(sys.modules[__name__], class_name)
          block = aggcls(
              down_conv_nn=down_conv_nn[i],
              grid_size=grid_size[i],
              prev_grid_size=prev_grid_size[i],
              has_bottleneck=has_bottleneck[i],
              max_num_neighbors=max_num_neighbors[i],
              bottleneck_ratio=bottleneck_ratio,
              position_embedding=position_embedding,
              reduction=reduction,
              output_conv=output_conv,
              bn_momentum=bn_momentum,
              **block_kwargs,
          )
          self.blocks.append(block)
  
imports: import torch
  import sys
  from torch.nn import Linear
  from .ops import PosPoolLayer
  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.utils.config import is_list
label_desc: Use image node_id 1 to create a new PPStageBlock object from inherited base classes: BaseModule with example: obj = PPStageBlock(block_names, down_conv_nn, grid_size, prev_grid_size, has_bottleneck, bottleneck_ratio, max_num_neighbors, position_embedding, reduction, output_conv, bn_momentum)