| 9 | |
| 10 | |
| 11 | class PointNetAModule(nn.Module): |
| 12 | def __init__(self, in_channels, out_channels, include_coordinates=True): |
| 13 | super().__init__() |
| 14 | if not isinstance(out_channels, (list, tuple)): |
| 15 | out_channels = [[out_channels]] |
| 16 | elif not isinstance(out_channels[0], (list, tuple)): |
| 17 | out_channels = [out_channels] |
| 18 | |
| 19 | mlps = [] |
| 20 | total_out_channels = 0 |
| 21 | for _out_channels in out_channels: |
| 22 | mlps.append( |
| 23 | SharedMLP(in_channels=in_channels + (3 if include_coordinates else 0), |
| 24 | out_channels=_out_channels, dim=1) |
| 25 | ) |
| 26 | total_out_channels += _out_channels[-1] |
| 27 | |
| 28 | self.include_coordinates = include_coordinates |
| 29 | self.out_channels = total_out_channels |
| 30 | self.mlps = nn.ModuleList(mlps) |
| 31 | |
| 32 | def forward(self, inputs): |
| 33 | features, coords = inputs |
| 34 | if self.include_coordinates: |
| 35 | features = torch.cat([features, coords], dim=1) |
| 36 | coords = torch.zeros((coords.size(0), 3, 1), device=coords.device) |
| 37 | if len(self.mlps) > 1: |
| 38 | features_list = [] |
| 39 | for mlp in self.mlps: |
| 40 | features_list.append(mlp(features).max(dim=-1, keepdim=True).values) |
| 41 | return torch.cat(features_list, dim=1), coords |
| 42 | else: |
| 43 | return self.mlps[0](features).max(dim=-1, keepdim=True).values, coords |
| 44 | |
| 45 | def extra_repr(self): |
| 46 | return f'out_channels={self.out_channels}, include_coordinates={self.include_coordinates}' |
| 47 | |
| 48 | |
| 49 | class PointNetSAModule(nn.Module): |
nothing calls this directly
no outgoing calls
no test coverage detected