class_docstr: Upsampling module from PointNet++
  Arguments:
      k [int] -- number of nearest neighboors used for the interpolation
      up_conv_nn [List[int]] -- list of feature sizes for the uplconv mlp
code: def forward(self, data, precomputed=None, **kwargs):
      data, data_skip = data
      batch_out = data_skip.clone()
      x_skip = data_skip.x
  
      has_innermost = len(data.x) == data.batch.max() + 1
  
      if precomputed and not has_innermost:
          if not hasattr(data, "up_idx"):
              setattr(batch_out, "up_idx", 0)
          else:
              setattr(batch_out, "up_idx", data.up_idx)
  
          pre_data = precomputed[batch_out.up_idx]
          batch_out.up_idx = batch_out.up_idx + 1
      else:
          pre_data = None
  
      if has_innermost:
          x = torch.gather(
              data.x,
              0,
              data_skip.batch.unsqueeze(-1).repeat(
                  (1, data.x.shape[-1])
              ),
          )
      else:
          x = self.upsample_op(data, data_skip, precomputed=pre_data)
  
      if x_skip is not None:
          x = torch.cat([x, x_skip], dim=1)
  
      if hasattr(self, "nn"):
          batch_out.x = self.nn(x)
      else:
          batch_out.x = x
      return batch_out
  
imports: from typing import *
  import torch
  from torch.nn import Linear, ReLU, LeakyReLU, BatchNorm1d, Dropout
  from torch_geometric.nn import knn_interpolate, fps, radius, global_max_pool, global_mean_pool, knn
  from torch_geometric.data import Batch
  from torch_points3d.core.spatial_ops import *
  from .base_conv import BaseConvolution
  from torch_points3d.core.common_modules.base_modules import BaseModule
  from torch_points3d.core.common_modules import MLP
label_desc: Use image node_id 2 for calling the FPModule_PD obj's underlying member method code with example usage: obj.forward(data, precomputed) and returns: batch_out