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","."]
docstr: implementation of :class:`~maze.perception.blocks.shape_normalization.ShapeNormalizationBlock` interface
          
docstr_tok: ["implementation","of",":","class",":","`","~maze.perception.blocks.shape_normalization.ShapeNormalizationBlock","`","interface"]
code: def normalized_forward(
      self, block_input: Dict[str, torch.Tensor]
  ) -> Dict[str, torch.Tensor]:
      """implementation of :class:`~maze.perception.blocks.shape_normalization.ShapeNormalizationBlock` interface"""
  
      # check input tensor
      input_tensor = block_input[self.in_keys[0]]
      mask_tensor = (
          None
          if not self._use_masking
          else block_input[self.in_keys[1]]
      )
      assert input_tensor.ndim == self.in_num_dims[0]
      assert input_tensor.shape[-1] == self._num_in_features, (
          f"failed for obs {self.in_keys[0]} because "
          f"{input_tensor.shape[-1]} != {self._num_in_features}"
      )
      # forward pass
      # input: (BB, NN, KK)
      input_tensor = input_tensor.transpose(2, 1)
      # input_tensor: (BB, KK, NN)
      input_transformation_matrices = self.input_transform(
          input_tensor, mask_tensor
      )
      # input_transformation_matrices: (BB, KK, KK)
  
      out = torch.bmm(input_transformation_matrices, input_tensor)
      # out: (BB, KK, NN)
  
      feature_out = self.non_lin_1(self.bn1(self.conv1(out)))
      # out: (BB, embedding_dim // 16, NN)
  
      if self._use_feature_transform:
          feature_transformation_matrices = self.feature_transform(
              feature_out, mask_tensor
          )
          # feature_transformation_matrices: (BB, embedding_dim // 16,  embedding_dim // 16)
          feature_out = torch.bmm(
              feature_transformation_matrices, feature_out
          )
          # out: (BB, embedding_dim // 16, NN)
  
      out = self.non_lin_2(self.bn2(self.conv2(feature_out)))
      # out: (BB, embedding_dim // 8, NN)
      out = self.bn3(self.conv3(out))
      # out: (BB, embedding_dim, NN)
  
      masking_input = {"in_tensor": out.transpose(2, 1)}
      if self._use_masking:
          masking_input[self.in_keys[1]] = mask_tensor
  
      output_tensor = self.pooling_block(masking_input)["masking_out"]
      # output_tensor: (BB, embedding_dim)
  
      # check output tensor
      assert output_tensor.ndim == self.out_num_dims[0]
      assert output_tensor.shape[-1] == self._embedding_dim
  
      res = {self.out_keys[0]: output_tensor}
      if self._return_features:
          res[self.out_keys[1]] = torch.transpose(
              feature_out, dim0=-1, dim1=-2
          )
  
      return res
  
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 2 for calling the PointNetFeatureBlock obj's underlying member method code with example usage: obj.normalized_forward(block_input) and returns: res