class_docstr: PointNet2 with multi-scale grouping
  descriptors network for registration that uses feature propogation layers
  
  Parameters
  ----------
  num_classes: int
      Number of semantics classes to predict over -- size of softmax classifier that run for each point
  input_channels: int = 6
      Number of input channels in the feature descriptor for each point.  If the point cloud is Nx9, this
      value should be 6 as in an Nx9 point cloud, 3 of the channels are xyz, and 6 are feature descriptors
  use_xyz: bool = True
      Whether or not to use the xyz position of a point as a feature
code: def apply_nn(self, input):
      last_feature = self.model(input).x
      output = (
          self.FC_layer(last_feature)
          .transpose(1, 2)
          .contiguous()
          .view((-1, self.out_channels))
      )
      if self.normalize_feature:
          return output / (
              torch.norm(output, p=2, dim=1, keepdim=True) + 1e-5
          )
      else:
          return output
  
imports: import torch
  import torch.nn.functional
  from torch.nn import Linear
  from torch.nn import Sequential
  from torch_geometric.data import Data
  import logging
  from torch_points3d.core.losses import *
  from torch_points3d.modules.pointnet2 import *
  from torch_points3d.core.common_modules import MLP
  from torch_points3d.models.base_architectures import BackboneBasedModel
  from torch_points3d.models.base_architectures import UnetBasedModel
  from torch_points3d.core.common_modules.dense_modules import Conv1D
  from torch_points3d.core.common_modules.base_modules import Seq
  from torch_points3d.models.registration.base import FragmentBaseModel
label_desc: Use image node_id 3 for calling the FragmentPointNet2_D obj's underlying member method code with example usage: obj.apply_nn(input) and returns: unknown, output