class_docstr: Feature Transform Net as proposed in https://arxiv.org/abs/1612.00593. This Module implements three
  convolutional stacks, each consisting of a 1d Convolution (kernel size =1) followed by an optional batch
  normalization and a specified non-linearity. The resulting output of the convolutions is then pooled in the
  point dimension (N) with the specified pooling method. Next two fully connected layers (again with optional
  batch norm and non linearity) are process the now two dimensional data. Finally one fully connected layer is
  applied before reshaping the data into the output format: BxKxK, where B is the batch dimension, N is the number
  of points and K is the number of features. The input to the module should have the shape BxKxN.
  
  :param num_features: Number of input features (K).
  :param num_points: Number of input points (N).
  :param embedding_dim: The embedding dimension to use (Paper: 1024).
  :param pooling_func_name: A string in ('max', 'mean', 'sum') specifying the pooling function to use. (Paper:
  'max')
  :param use_batch_norm: Specify whether to use batch_norm (like in original paper).
  :param non_lin: The non-linearity to apply after each fully connected layer.
  :param use_masking: Specify whether to use masking.
  
   
class_docstr_tok: ["Feature","Transform","Net","as","proposed","in","https",":","\/\/arxiv.org\/abs\/1612.00593",".","This","Module","implements","three","convolutional","stacks",",","each","consisting","of","a","1d","Convolution","(","kernel","size","=1",")","followed","by","an","optional","batch","normalization","and","a","specified","non-linearity",".","The","resulting","output","of","the","convolutions","is","then","pooled","in","the","point","dimension","(","N",")","with","the","specified","pooling","method",".","Next","two","fully","connected","layers","(","again","with","optional","batch","norm","and","non","linearity",")","are","process","the","now","two","dimensional","data",".","Finally","one","fully","connected","layer","is","applied","before","reshaping","the","data","into","the","output","format",":","BxKxK",",","where","B","is","the","batch","dimension",",","N","is","the","number","of","points","and","K","is","the","number","of","features",".","The","input","to","the","module","should","have","the","shape","BxKxN",".",":","param","num_features",":","Number","of","input","features","(","K",")",".",":","param","num_points",":","Number","of","input","points","(","N",")",".",":","param","embedding_dim",":","The","embedding","dimension","to","use","(","Paper",":","1024",")",".",":","param","pooling_func_name",":","A","string","in","(","'max","'",",","'mean","'",",","'sum","'",")","specifying","the","pooling","function","to","use",".","(","Paper",":","'max","'",")",":","param","use_batch_norm",":","Specify","whether","to","use","batch_norm","(","like","in","original","paper",")",".",":","param","non_lin",":","The","non-linearity","to","apply","after","each","fully","connected","layer",".",":","param","use_masking",":","Specify","whether","to","use","masking","."]
code: def __init__(
      self,
      num_features: int,
      num_points: int,
      embedding_dim: int,
      pooling_func_name: str,
      use_batch_norm: bool,
      non_lin: Union[str, type(nn.Module)],
      use_masking: bool,
  ):
      super().__init__()
  
      # Init class variables
      self._use_batch_norm = use_batch_norm
      self._pooling_func_name = pooling_func_name
      self._num_features = num_features
      self._embedding_dim = embedding_dim
      self._num_points = num_points
  
      # Init convolutions
      self.conv1 = torch.nn.Conv1d(num_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)
  
      # Set up the pooling operation with masking
      self.use_masking = use_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", "mask_tensor"],
          in_shapes=tensor_in_shape
          if not self.use_masking
          else [tensor_in_shape, (self._num_points,)],
          pooling_func=self._pooling_func_name,
          pooling_dim=-2,
          out_keys="masking_out",
      )
  
      # Init fully connected layers
      self.fc1 = nn.Linear(embedding_dim, embedding_dim // 2)
      self.fc2 = nn.Linear(embedding_dim // 2, embedding_dim // 4)
      self.fc3 = nn.Linear(
          embedding_dim // 4, num_features * num_features
      )
  
      # Init batch norm
      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)
          self.bn4 = nn.BatchNorm1d(embedding_dim // 2)
          self.bn5 = nn.BatchNorm1d(embedding_dim // 4)
  
      # Init non linearity's
      non_lin = Factory(base_type=nn.Module).type_from_name(non_lin)
      self.non_lin_1 = non_lin()
      self.non_lin_2 = non_lin()
      self.non_lin_3 = non_lin()
      self.non_lin_4 = non_lin()
      self.non_lin_5 = non_lin()
  
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 PointNetFeatureTransformNet object from inherited base classes: nn with example: obj = PointNetFeatureTransformNet(num_features, num_points, embedding_dim, pooling_func_name, use_batch_norm, non_lin, use_masking)