class_docstr: Multiscale convolution down (also supports single scale). Convolution kernel is shared accross the scales
  
  Arguments:
      sampler  -- Strategy for sampling the input clouds
      neighbour_finder -- Multiscale strategy for finding neighbours
class_docstr_tok: ["Multiscale","convolution","down","(","also","supports","single","scale",")",".","Convolution","kernel","is","shared","accross","the","scales","Arguments",":","sampler","--","Strategy","for","sampling","the","input","clouds","neighbour_finder","--","Multiscale","strategy","for","finding","neighbours"]
code: def forward(self, data, **kwargs):
      batch_obj = Batch()
      x, pos, batch = data.x, data.pos, data.batch
      idx = self.sampler(pos, batch)
      batch_obj.idx = idx
  
      ms_x = []
      for scale_idx in range(self.neighbour_finder.num_scales):
          row, col = self.neighbour_finder(
              pos,
              pos[idx],
              batch_x=batch,
              batch_y=batch[idx],
              scale_idx=scale_idx,
          )
          edge_index = torch.stack([col, row], dim=0)
  
          ms_x.append(self.conv(x, (pos, pos[idx]), edge_index, batch))
  
      batch_obj.x = torch.cat(ms_x, -1)
      batch_obj.pos = pos[idx]
      batch_obj.batch = batch[idx]
      copy_from_to(data, batch_obj)
      return batch_obj
  
imports: from abc import abstractmethod
  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.base_conv.base_conv import *
  from torch_points3d.core.common_modules import *
  from torch_points3d.core.spatial_ops import *
label_desc: Use image node_id 3 for calling the BaseMSConvolutionDown obj's underlying member method code with example usage: obj.forward(data) and returns: batch_obj