class_docstr: The Feature Propagation Layer
class_docstr_tok: ["The","Feature","Propagation","Layer"]
docstr: Adapted from https://github.com/yanx27/Pointnet_Pointnet2_pytorch
      Input:
          x1: input points position data, [B, N, C]
          x2: sampled input points position data, [B, S, C]
          feat1: input points data, [B, N, D]
          feat2: input points data, [B, S, D]
      Return:
          new_feat: upsampled points data, [B, D', N]
docstr_tok: ["Adapted","from","https",":","\/\/github.com\/yanx27\/Pointnet_Pointnet2_pytorch","Input",":","x1",":","input","points","position","data",",","[","B",",","N",",","C","]","x2",":","sampled","input","points","position","data",",","[","B",",","S",",","C","]","feat1",":","input","points","data",",","[","B",",","N",",","D","]","feat2",":","input","points","data",",","[","B",",","S",",","D","]","Return",":","new_feat",":","upsampled","points","data",",","[","B",",","D","'",",","N","]"]
code: def forward(self, x1, x2, feat1, feat2):
      """
      Adapted from https://github.com/yanx27/Pointnet_Pointnet2_pytorch
          Input:
              x1: input points position data, [B, N, C]
              x2: sampled input points position data, [B, S, C]
              feat1: input points data, [B, N, D]
              feat2: input points data, [B, S, D]
          Return:
              new_feat: upsampled points data, [B, D', N]
      """
      B, N, C = x1.shape
      _, S, _ = x2.shape
  
      if S == 1:
          interpolated_feat = feat2.repeat(1, N, 1)
      else:
          dists = square_distance(x1, x2)
          dists, idx = dists.sort(dim=-1)
          dists, idx = dists[:, :, :3], idx[:, :, :3]  # [B, N, 3]
  
          dist_recip = 1.0 / (dists + 1e-8)
          norm = torch.sum(dist_recip, dim=2, keepdim=True)
          weight = dist_recip / norm
          interpolated_feat = torch.sum(
              index_points(feat2, idx) * weight.view(B, N, 3, 1), dim=2
          )
  
      if feat1 is not None:
          new_feat = torch.cat([feat1, interpolated_feat], dim=-1)
      else:
          new_feat = interpolated_feat
  
      new_feat = new_feat.permute(0, 2, 1)  # [B, D, S]
      for i, conv in enumerate(self.convs):
          bn = self.bns[i]
          new_feat = F.relu(bn(conv(new_feat)))
      return new_feat
  
imports: import dgl
  import dgl.function
  import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  from dgl.geometry import farthest_point_sampler
  from torch.autograd import Variable
label_desc: Use image node_id 2 for calling the PointNet2FP obj's underlying member method code with example usage: obj.forward(x1, x2, feat1, feat2) and returns: new_feat