class_docstr: PointNet block allowing to embed a variable sized set of point observations into a fixed size feature vector via
  the PointNet mechanics. (https://arxiv.org/abs/1612.00593 from Stanford University).
  
  The block processed the input with one input transformation, two 1d convolutions each followed by an optional batch
  normalization and a non linearity. Then an optional feature transformation is applied before a final convolutional
  layer. Lastly a masked global pooling block is used to pool all values in the point dimension resulting in a
  two dimensional vector (batch_dim, feature_dim). The mask for pooling is an optional parameter.
  
  :param in_keys: One key identifying the input tensors, a second optional one identifying the masking tensor.
  :param out_keys: One key identifying the output tensors, a second optional one for identifying the features.
  :param in_shapes: List of input shapes.
  :param embedding_dim: The embedding dimension to use throughout the block, this is also specifies the dimension of
      the output. (Paper: 1024)
  :param pooling_func_name: A string in ('max', 'mean', 'sum') specifying the pooling function to use. (Paper: 'max')
  :param use_feature_transform: Whether to use the feature transformation after the second convolution. (Paper: True)
  :param use_batch_norm: Specify whether to use batch_norm (is disables for batches of size <2).
  :param non_lin: The non-linearity to apply after each layer.
class_docstr_tok: ["PointNet","block","allowing","to","embed","a","variable","sized","set","of","point","observations","into","a","fixed","size","feature","vector","via","the","PointNet","mechanics",".","(","https",":","\/\/arxiv.org\/abs\/1612.00593","from","Stanford","University",")",".","The","block","processed","the","input","with","one","input","transformation",",","two","1d","convolutions","each","followed","by","an","optional","batch","normalization","and","a","non","linearity",".","Then","an","optional","feature","transformation","is","applied","before","a","final","convolutional","layer",".","Lastly","a","masked","global","pooling","block","is","used","to","pool","all","values","in","the","point","dimension","resulting","in","a","two","dimensional","vector","(","batch_dim",",","feature_dim",")",".","The","mask","for","pooling","is","an","optional","parameter",".",":","param","in_keys",":","One","key","identifying","the","input","tensors",",","a","second","optional","one","identifying","the","masking","tensor",".",":","param","out_keys",":","One","key","identifying","the","output","tensors",",","a","second","optional","one","for","identifying","the","features",".",":","param","in_shapes",":","List","of","input","shapes",".",":","param","embedding_dim",":","The","embedding","dimension","to","use","throughout","the","block",",","this","is","also","specifies","the","dimension","of","the","output",".","(","Paper",":","1024",")",":","param","pooling_func_name",":","A","string","in","(","'max","'",",","'mean","'",",","'sum","'",")","specifying","the","pooling","function","to","use",".","(","Paper",":","'max","'",")",":","param","use_feature_transform",":","Whether","to","use","the","feature","transformation","after","the","second","convolution",".","(","Paper",":","True",")",":","param","use_batch_norm",":","Specify","whether","to","use","batch_norm","(","is","disables","for","batches","of","size","<","2",")",".",":","param","non_lin",":","The","non-linearity","to","apply","after","each","layer","."]
code: def __init__(
      self,
      in_keys: Union[str, List[str]],
      out_keys: Union[str, List[str]],
      in_shapes: Union[Sequence[int], List[Sequence[int]]],
      embedding_dim: int,
      pooling_func_name: str,
      use_feature_transform: bool,
      use_batch_norm: bool,
      non_lin: Union[str, type(nn.Module)],
  ):
      # Infer number of input dimension depending if mask is provided
      in_keys = in_keys if isinstance(in_keys, List) else [in_keys]
      in_num_dims = 3 if len(in_keys) == 1 else [3, 2]
      out_keys = out_keys if isinstance(out_keys, List) else [out_keys]
      self._return_features = len(out_keys) > 1
      out_num_dims = 2 if not self._return_features else [2, 3]
      super().__init__(
          in_keys=in_keys,
          out_keys=out_keys,
          in_shapes=in_shapes,
          in_num_dims=in_num_dims,
          out_num_dims=out_num_dims,
      )
  
      # Input parameter assertions: checks if the first input (X) has 2 dimensions (NN, KK).
      assert len(self.in_shapes[0]) == 2
      if len(self.in_keys) == 2:
          # checks that the mask has only one input dimension (NN)
          assert len(self.in_shapes[1]) == 1
          #  checks that the point dimension in X and Mask are the same
          assert self.in_shapes[0][-2] == self.in_shapes[1][-1], (
              f"Point dimension should fit: {self.in_shapes[0]} "
              f"vs {self.in_shapes[1]}"
          )
  
      # Init class variables
      self._use_feature_transform = use_feature_transform
      self._embedding_dim = embedding_dim
      self._use_batch_norm = use_batch_norm
      self._num_in_features = self.in_shapes[0][-1]
      self._num_points = self.in_shapes[0][-2]
      self._use_masking = len(self.in_keys) > 1
  
      self.input_transform = PointNetFeatureTransformNet(
          self._num_in_features,
          self._num_points,
          non_lin=non_lin,
          use_batch_norm=self._use_batch_norm,
          embedding_dim=embedding_dim,
          pooling_func_name=pooling_func_name,
          use_masking=self._use_masking,
      )
      if self._use_feature_transform:
          self.feature_transform = PointNetFeatureTransformNet(
              embedding_dim // 16,
              self._num_points,
              non_lin=non_lin,
              use_batch_norm=self._use_batch_norm,
              embedding_dim=embedding_dim,
              pooling_func_name=pooling_func_name,
              use_masking=self._use_masking,
          )
  
      self.conv1 = torch.nn.Conv1d(
          self._num_in_features, embedding_dim // 16, 1
      )
      self.conv2 = torch.nn.Conv1d(
          embedding_dim // 16, embedding_dim // 8, 1
      )
      self.conv3 = torch.nn.Conv1d(embedding_dim // 8, embedding_dim, 1)
  
      if self._use_batch_norm:
          self.bn1 = nn.BatchNorm1d(embedding_dim // 16)
          self.bn2 = nn.BatchNorm1d(embedding_dim // 8)
          self.bn3 = nn.BatchNorm1d(embedding_dim)
      else:
          self.bn1 = nn.Identity()
          self.bn2 = nn.Identity()
          self.bn3 = nn.Identity()
  
      # Set up the pooling operation with masking
      tensor_in_shape = (self._num_points, embedding_dim)
      self.pooling_block = MaskedGlobalPoolingBlock(
          in_keys="in_tensor"
          if not self._use_masking
          else ["in_tensor", self.in_keys[1]],
          in_shapes=tensor_in_shape
          if not self._use_masking
          else [tensor_in_shape, self.in_shapes[1]],
          pooling_func=pooling_func_name,
          pooling_dim=-2,
          out_keys="masking_out",
      )
  
      self.pooling_func_str = pooling_func_name
      self.non_lin_cls = Factory(base_type=nn.Module).type_from_name(
          non_lin
      )
      self.non_lin_1 = self.non_lin_cls()
      self.non_lin_2 = self.non_lin_cls()
  
      # Debugging parameter for displaying the internal processing of the input in more detail.
      self.print_internal_shape_representation = False
  
file_path: maze/maze/perception/blocks/feed_forward/point_net.py
imports: from collections import OrderedDict
  from typing import Union, List, Dict, Sequence, Optional
  import torch
  from torch import nn
  from maze.core.annotations import override
  from maze.core.utils.factory import Factory
  from maze.perception.blocks.general.masked_global_pooling import MaskedGlobalPoolingBlock
  from maze.perception.blocks.shape_normalization import ShapeNormalizationBlock
label_desc: Use image node_id 1 to create a new PointNetFeatureBlock object from inherited base classes: ShapeNormalizationBlock with example: obj = PointNetFeatureBlock(in_keys, out_keys, in_shapes, embedding_dim, pooling_func_name, use_feature_transform, use_batch_norm, non_lin)