docstr: Votes for centres using a PN++ like architecture
  Returns
  -------
  data:
      - pos: position of the vote (centre of the box)
      - x: feature of the vote (original feature + processed feature)
      - seed_pos: position of the original point
docstr_tok: ["Votes","for","centres","using","a","PN++","like","architecture","Returns","--","--","--","-","data",":","-","pos",":","position","of","the","vote","(","centre","of","the","box",")","-","x",":","feature","of","the","vote","(","original","feature","+","processed","feature",")","-","seed_pos",":","position","of","the","original","point"]
code: def forward(self, data):
      """Votes for centres using a PN++ like architecture
      Returns
      -------
      data:
          - pos: position of the vote (centre of the box)
          - x: feature of the vote (original feature + processed feature)
          - seed_pos: position of the original point
      """
      if 3 < data.pos.dim() and data.pos.dim() <= 1:
          raise Exception(
              "data.pos doesn t have the correct dimension. Should be either 2 or 3"
          )
  
      if self._conv_type == "DENSE":
          batch_size = data.pos.shape[0]
          num_points = data.pos.shape[1]
          num_votes = num_points * self.vote_factor
          x = F.relu(self.bn1(self.conv1(data.x)))
          x = F.relu(self.bn2(self.conv2(x)))
          x = self.conv3(
              x
          )  # (batch_size, (3+out_dim)*vote_factor, num_seed)
  
          x = x.transpose(2, 1).view(
              batch_size, num_points, self.vote_factor, 3 + self.out_dim
          )
          offset = x[:, :, :, 0:3]
          vote_pos = data.pos.unsqueeze(2) + offset.contiguous()
          vote_pos = vote_pos.contiguous().view(
              batch_size, num_votes, 3
          )
  
          res_x = x[
              :, :, :, 3:
          ]  # (batch_size, num_seed, vote_factor, out_dim)
          vote_x = (
              data.x.transpose(2, 1).unsqueeze(2).contiguous()
              + res_x.contiguous()
          )
          vote_x = vote_x.contiguous().view(
              batch_size, num_votes, self.out_dim
          )
          vote_x = vote_x.transpose(2, 1).contiguous()
          data_out = Data(pos=vote_pos, x=vote_x, seed_pos=data.pos)
      else:
          x = F.relu(self.bn1(self.conv1(data.x)))
          x = F.relu(self.bn2(self.conv2(x)))
          x = self.conv3(x)
          offset = x[:, 0:3]
          vote_pos = data.pos + offset
          res_x = x[:, 3:]
          vote_x = data.x + res_x
          data_out = Data(
              pos=vote_pos,
              x=vote_x,
              seed_pos=data.pos,
              batch=data.batch,
          )
      return data_out
  
imports: import torch
  import torch.nn
  import torch.nn.functional
  from torch_geometric.data import Data
label_desc: Use image node_id 2 for calling the VotingModule obj's underlying member method code with example usage: obj.forward(data) and returns: data_out