openpoints 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. openpoints/__init__.py +3 -0
  2. openpoints/cpp/__init__.py +6 -0
  3. openpoints/cpp/chamfer_dist/__init__.py +110 -0
  4. openpoints/cpp/chamfer_dist/setup.py +19 -0
  5. openpoints/cpp/chamfer_dist/test.py +34 -0
  6. openpoints/cpp/emd/__init__.py +3 -0
  7. openpoints/cpp/emd/emd.py +88 -0
  8. openpoints/cpp/emd/setup.py +27 -0
  9. openpoints/cpp/emd/test_emd_loss.py +45 -0
  10. openpoints/cpp/pointnet2_batch/__init__.py +24 -0
  11. openpoints/cpp/pointnet2_batch/setup.py +23 -0
  12. openpoints/cpp/pointops/__init__.py +0 -0
  13. openpoints/cpp/pointops/functions/__init__.py +0 -0
  14. openpoints/cpp/pointops/functions/pointops.py +314 -0
  15. openpoints/cpp/pointops/setup.py +37 -0
  16. openpoints/cpp/pointops/src/__init__.py +0 -0
  17. openpoints/dataset/__init__.py +10 -0
  18. openpoints/dataset/atom3d/__init__.py +1 -0
  19. openpoints/dataset/atom3d/psr.py +38 -0
  20. openpoints/dataset/build.py +98 -0
  21. openpoints/dataset/data_util.py +192 -0
  22. openpoints/dataset/datalist.py +67 -0
  23. openpoints/dataset/dataset_base.py +96 -0
  24. openpoints/dataset/graph_dataset/__init__.py +3 -0
  25. openpoints/dataset/graph_dataset/graph_dataset.py +93 -0
  26. openpoints/dataset/graph_dataset/stack_with_pad.py +91 -0
  27. openpoints/dataset/graph_dataset/structural_dataset.py +73 -0
  28. openpoints/dataset/graph_dataset/svd_encodings_dataset.py +110 -0
  29. openpoints/dataset/grid_sample.py +21 -0
  30. openpoints/dataset/matterport3d/__init__.py +1 -0
  31. openpoints/dataset/matterport3d/category_mapping.tsv +1660 -0
  32. openpoints/dataset/matterport3d/matterport3d.py +210 -0
  33. openpoints/dataset/matterport3d/matterport3d_dataprocessing.py +105 -0
  34. openpoints/dataset/modelnet/__init__.py +3 -0
  35. openpoints/dataset/modelnet/modelnet40_normal_resampled_loader.py +124 -0
  36. openpoints/dataset/modelnet/modelnet40_ply_2048_loader.py +160 -0
  37. openpoints/dataset/molhiv/__init__.py +1 -0
  38. openpoints/dataset/molhiv/data.py +59 -0
  39. openpoints/dataset/molpcba/__init__.py +1 -0
  40. openpoints/dataset/molpcba/data.py +59 -0
  41. openpoints/dataset/parsers/__init__.py +1 -0
  42. openpoints/dataset/parsers/class_map.py +19 -0
  43. openpoints/dataset/parsers/constants.py +1 -0
  44. openpoints/dataset/parsers/parser.py +17 -0
  45. openpoints/dataset/parsers/parser_factory.py +29 -0
  46. openpoints/dataset/parsers/parser_image_folder.py +69 -0
  47. openpoints/dataset/parsers/parser_image_in_tar.py +222 -0
  48. openpoints/dataset/parsers/parser_image_tar.py +72 -0
  49. openpoints/dataset/parsers/parser_tfds.py +297 -0
  50. openpoints/dataset/pcqm4m/__init__.py +1 -0
  51. openpoints/dataset/pcqm4m/data.py +62 -0
  52. openpoints/dataset/pcqm4mv2/__init__.py +1 -0
  53. openpoints/dataset/pcqm4mv2/data.py +87 -0
  54. openpoints/dataset/s3dis/__init__.py +2 -0
  55. openpoints/dataset/s3dis/s3dis.py +156 -0
  56. openpoints/dataset/s3dis/s3dis_block.py +96 -0
  57. openpoints/dataset/s3dis/s3dis_sphere.py +349 -0
  58. openpoints/dataset/scannetv2/__init__.py +1 -0
  59. openpoints/dataset/scannetv2/scannet.py +176 -0
  60. openpoints/dataset/scanobjectnn/__init__.py +3 -0
  61. openpoints/dataset/scanobjectnn/scanobjectnn.py +110 -0
  62. openpoints/dataset/semantic_kitti/__init__.py +1 -0
  63. openpoints/dataset/semantic_kitti/helper_tool.py +286 -0
  64. openpoints/dataset/semantic_kitti/label_mapping.yaml +211 -0
  65. openpoints/dataset/semantic_kitti/semantickitti.py +229 -0
  66. openpoints/dataset/semantic_kitti/utils/meta/anno_paths.txt +272 -0
  67. openpoints/dataset/semantic_kitti/utils/meta/class_names.txt +13 -0
  68. openpoints/dataset/semantic_kitti/utils/semantic-kitti.yaml +211 -0
  69. openpoints/dataset/shapenet/__init__.py +1 -0
  70. openpoints/dataset/shapenet/shapenet55.py +76 -0
  71. openpoints/dataset/shapenet/shapenetpart.py +121 -0
  72. openpoints/dataset/shapenetpart/__init__.py +1 -0
  73. openpoints/dataset/shapenetpart/shapenet55.py +75 -0
  74. openpoints/dataset/shapenetpart/shapenetpart.py +388 -0
  75. openpoints/dataset/vis2d.py +17 -0
  76. openpoints/dataset/vis3d.py +153 -0
  77. openpoints/loss/__init__.py +3 -0
  78. openpoints/loss/build.py +281 -0
  79. openpoints/loss/cross_entropy.py +38 -0
  80. openpoints/loss/distill_loss.py +76 -0
  81. openpoints/models/__init__.py +10 -0
  82. openpoints/models/backbone/Stratified_transformer.py +558 -0
  83. openpoints/models/backbone/__init__.py +11 -0
  84. openpoints/models/backbone/baafnet.py +527 -0
  85. openpoints/models/backbone/ball_dgcnn.py +123 -0
  86. openpoints/models/backbone/curvenet.py +793 -0
  87. openpoints/models/backbone/debug_invvit.py +114 -0
  88. openpoints/models/backbone/deepgcn.py +143 -0
  89. openpoints/models/backbone/dgcnn.py +119 -0
  90. openpoints/models/backbone/graphvit3d.py +134 -0
  91. openpoints/models/backbone/grouppointnet.py +100 -0
  92. openpoints/models/backbone/pct.py +163 -0
  93. openpoints/models/backbone/pointmlp.py +417 -0
  94. openpoints/models/backbone/pointnet.py +199 -0
  95. openpoints/models/backbone/pointnetv2.py +511 -0
  96. openpoints/models/backbone/pointnext.py +663 -0
  97. openpoints/models/backbone/pointnextPyG.py +555 -0
  98. openpoints/models/backbone/pointtransformer.py +293 -0
  99. openpoints/models/backbone/pointvector.py +853 -0
  100. openpoints/models/backbone/pointvit.py +392 -0
  101. openpoints/models/backbone/pointvit_inv.py +942 -0
  102. openpoints/models/backbone/pointvit_inv_old.py +784 -0
  103. openpoints/models/backbone/randlenet.py +318 -0
  104. openpoints/models/backbone/resnet.py +342 -0
  105. openpoints/models/backbone/simpleview.py +153 -0
  106. openpoints/models/backbone/simpleview_util.py +292 -0
  107. openpoints/models/build.py +13 -0
  108. openpoints/models/classification/__init__.py +5 -0
  109. openpoints/models/classification/cls_base.py +136 -0
  110. openpoints/models/classification/point_bert.py +154 -0
  111. openpoints/models/layers/__init__.py +14 -0
  112. openpoints/models/layers/activation.py +57 -0
  113. openpoints/models/layers/attention.py +103 -0
  114. openpoints/models/layers/conv.py +167 -0
  115. openpoints/models/layers/drop.py +164 -0
  116. openpoints/models/layers/graph_conv.py +122 -0
  117. openpoints/models/layers/group.py +415 -0
  118. openpoints/models/layers/group_embed.py +286 -0
  119. openpoints/models/layers/helpers.py +43 -0
  120. openpoints/models/layers/kmeans.py +119 -0
  121. openpoints/models/layers/knn.py +110 -0
  122. openpoints/models/layers/local_aggregation.py +286 -0
  123. openpoints/models/layers/mlp.py +129 -0
  124. openpoints/models/layers/norm.py +106 -0
  125. openpoints/models/layers/padding.py +56 -0
  126. openpoints/models/layers/patch_embed.py +37 -0
  127. openpoints/models/layers/registry.py +168 -0
  128. openpoints/models/layers/subsample.py +185 -0
  129. openpoints/models/layers/upsampling.py +106 -0
  130. openpoints/models/layers/weight_init.py +89 -0
  131. openpoints/models/reconstruction/__init__.py +8 -0
  132. openpoints/models/reconstruction/base_recontruct.py +216 -0
  133. openpoints/models/reconstruction/maskedpoint.py +116 -0
  134. openpoints/models/reconstruction/maskedpointgroup.py +168 -0
  135. openpoints/models/reconstruction/maskedpointvit.py +253 -0
  136. openpoints/models/reconstruction/nodeshuffle.py +11 -0
  137. openpoints/models/registry.py +149 -0
  138. openpoints/models/segmentation/__init__.py +6 -0
  139. openpoints/models/segmentation/base_seg.py +278 -0
  140. openpoints/models/segmentation/vit_seg.py +126 -0
  141. openpoints/optim/__init__.py +15 -0
  142. openpoints/optim/adabelief.py +201 -0
  143. openpoints/optim/adafactor.py +167 -0
  144. openpoints/optim/adahessian.py +156 -0
  145. openpoints/optim/adamp.py +105 -0
  146. openpoints/optim/adamw.py +122 -0
  147. openpoints/optim/lamb.py +192 -0
  148. openpoints/optim/lars.py +135 -0
  149. openpoints/optim/lookahead.py +61 -0
  150. openpoints/optim/madgrad.py +184 -0
  151. openpoints/optim/nadam.py +92 -0
  152. openpoints/optim/nvnovograd.py +120 -0
  153. openpoints/optim/optim_factory.py +306 -0
  154. openpoints/optim/radam.py +89 -0
  155. openpoints/optim/rmsprop_tf.py +139 -0
  156. openpoints/optim/sgdp.py +70 -0
  157. openpoints/scheduler/__init__.py +8 -0
  158. openpoints/scheduler/cosine_lr.py +124 -0
  159. openpoints/scheduler/multistep_lr.py +65 -0
  160. openpoints/scheduler/plateau_lr.py +113 -0
  161. openpoints/scheduler/poly_lr.py +116 -0
  162. openpoints/scheduler/scheduler.py +110 -0
  163. openpoints/scheduler/scheduler_factory.py +118 -0
  164. openpoints/scheduler/step_lr.py +65 -0
  165. openpoints/scheduler/tanh_lr.py +117 -0
  166. openpoints/transforms/__init__.py +7 -0
  167. openpoints/transforms/point_transform_cpu.py +332 -0
  168. openpoints/transforms/point_transformer_gpu.py +764 -0
  169. openpoints/transforms/transforms_factory.py +60 -0
  170. openpoints/utils/__init__.py +8 -0
  171. openpoints/utils/ckpt_util.py +438 -0
  172. openpoints/utils/config.py +113 -0
  173. openpoints/utils/dist_utils.py +54 -0
  174. openpoints/utils/logger.py +170 -0
  175. openpoints/utils/metrics.py +311 -0
  176. openpoints/utils/random.py +16 -0
  177. openpoints/utils/registry.py +294 -0
  178. openpoints/utils/str2bool.py +11 -0
  179. openpoints/utils/wandb.py +88 -0
  180. openpoints-0.1.0.dist-info/METADATA +150 -0
  181. openpoints-0.1.0.dist-info/RECORD +184 -0
  182. openpoints-0.1.0.dist-info/WHEEL +5 -0
  183. openpoints-0.1.0.dist-info/licenses/LICENSE +21 -0
  184. openpoints-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,153 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ from .simpleview_util import PCViews
4
+ from ..build import MODELS
5
+ # from roi_align import CropAndResize # crop_and_resize module
6
+ from openpoints.transforms import build_transforms_from_cfg
7
+
8
+
9
+ class Squeeze(nn.Module):
10
+ def __init__(self):
11
+ super().__init__()
12
+
13
+ def forward(self, inp):
14
+ return inp.squeeze()
15
+
16
+
17
+ class BatchNormPoint(nn.Module):
18
+ def __init__(self, feat_size):
19
+ super().__init__()
20
+ self.feat_size = feat_size
21
+ self.bn = nn.BatchNorm1d(feat_size)
22
+
23
+ def forward(self, x):
24
+ assert len(x.shape) == 3
25
+ s1, s2, s3 = x.shape[0], x.shape[1], x.shape[2]
26
+ assert s3 == self.feat_size
27
+ x = x.view(s1 * s2, self.feat_size)
28
+ x = self.bn(x)
29
+ return x.view(s1, s2, s3)
30
+
31
+
32
+ @MODELS.register_module()
33
+ class MVFC(nn.Module):
34
+ """
35
+ Final FC layers for the MV model
36
+ """
37
+
38
+ def __init__(self, num_views, in_features, out_features, dropout):
39
+ super().__init__()
40
+ self.num_views = num_views
41
+ self.in_features = in_features
42
+ self.model = nn.Sequential(
43
+ BatchNormPoint(in_features),
44
+ # dropout before concatenation so that each view drops features independently
45
+ nn.Dropout(dropout),
46
+ nn.Flatten(),
47
+ nn.Linear(in_features=in_features * self.num_views,
48
+ out_features=in_features),
49
+ nn.BatchNorm1d(in_features),
50
+ nn.ReLU(),
51
+ nn.Dropout(dropout),
52
+ nn.Linear(in_features=in_features, out_features=out_features,
53
+ bias=True))
54
+
55
+ def forward(self, feat):
56
+ feat = feat.view((-1, self.num_views, self.in_features))
57
+ out = self.model(feat)
58
+ return out
59
+
60
+
61
+ @MODELS.register_module()
62
+ class MVModel(nn.Module):
63
+ def __init__(self, task='cls', backbone='resnet18',
64
+ channels=16,
65
+ num_classes=15,
66
+ resolution=128,
67
+ use_img_transform=False,
68
+ **kwargs):
69
+ super().__init__()
70
+ assert task == 'cls'
71
+ self.task = task
72
+ self.num_classes = num_classes
73
+ self.dropout = kwargs.get('dropout', 0.5)
74
+ self.channels = channels
75
+ pc_views = PCViews()
76
+ self.num_views = pc_views.num_views
77
+ self._get_img = pc_views.get_img
78
+
79
+ img_layers, in_features = self.get_img_layers(
80
+ backbone, channels=channels)
81
+ self.img_model = nn.Sequential(*img_layers)
82
+
83
+ self.final_fc = MVFC(
84
+ num_views=self.num_views,
85
+ in_features=in_features,
86
+ out_features=self.num_classes,
87
+ dropout=self.dropout)
88
+ if use_img_transform:
89
+ self.img_transform = build_transforms_from_cfg('img', {'img': ['Zoom']})
90
+ else:
91
+ self.img_transform = None
92
+
93
+ def forward(self, pc):
94
+ """
95
+ :param pc:
96
+ :return:
97
+ """
98
+ if hasattr(pc, 'keys'):
99
+ pc = pc['pos']
100
+ img = self.get_img(pc)
101
+
102
+ if self.training and self.img_transform is not None:
103
+ img = self.img_transform(img, pc.shape[0] * self.num_views)
104
+ feat = self.img_model(img)
105
+ logit = self.final_fc(feat)
106
+ return logit
107
+
108
+ def forward_cls_feat(self, pc):
109
+ return self.forward(pc)
110
+
111
+ def get_img(self, pc):
112
+ img = self._get_img(pc)
113
+ img = img.unsqueeze(3)
114
+ # [num_pc * num_views, 1, RESOLUTION, RESOLUTION]
115
+ img = img.permute(0, 3, 1, 2)
116
+ return img
117
+
118
+ @staticmethod
119
+ def get_img_layers(backbone, channels):
120
+ """
121
+ Return layers for the image model
122
+ """
123
+
124
+ from .resnet import _resnet, BasicBlock
125
+ assert backbone == 'resnet18'
126
+ layers = [2, 2, 2, 2]
127
+ block = BasicBlock
128
+ backbone_mod = _resnet(
129
+ arch=None,
130
+ block=block,
131
+ layers=layers,
132
+ pretrained=False,
133
+ progress=False,
134
+ feature_size=channels,
135
+ zero_init_residual=True)
136
+
137
+ all_layers = [x for x in backbone_mod.children()]
138
+ in_features = all_layers[-1].in_features
139
+
140
+ # all layers except the final fc layer and the initial conv layers
141
+ # WARNING: this is checked only for resnet models
142
+ main_layers = all_layers[4:-1]
143
+ img_layers = [
144
+ nn.Conv2d(1, channels, kernel_size=(3, 3), stride=(1, 1),
145
+ padding=(1, 1), bias=False),
146
+ nn.BatchNorm2d(channels, eps=1e-05, momentum=0.1,
147
+ affine=True, track_running_stats=True),
148
+ nn.ReLU(inplace=True),
149
+ *main_layers,
150
+ Squeeze()
151
+ ]
152
+
153
+ return img_layers, in_features
@@ -0,0 +1,292 @@
1
+ import torch.nn as nn
2
+ import numpy as np
3
+ import torch
4
+
5
+ RESOLUTION = 128
6
+ TRANS = -1.4
7
+
8
+ def euler2mat(angle):
9
+ """Convert euler angles to rotation matrix.
10
+ :param angle: [3] or [b, 3]
11
+ :return
12
+ rotmat: [3] or [b, 3, 3]
13
+ source
14
+ https://github.com/ClementPinard/SfmLearner-Pytorch/blob/master/inverse_warp.py
15
+ """
16
+
17
+ if len(angle.size()) == 1:
18
+ x, y, z = angle[0], angle[1], angle[2]
19
+ _dim = 0
20
+ _view = [3, 3]
21
+ elif len(angle.size()) == 2:
22
+ b, _ = angle.size()
23
+ x, y, z = angle[:, 0], angle[:, 1], angle[:, 2]
24
+ _dim = 1
25
+ _view = [b, 3, 3]
26
+
27
+ else:
28
+ assert False
29
+
30
+ cosz = torch.cos(z)
31
+ sinz = torch.sin(z)
32
+
33
+ # zero = torch.zeros([b], requires_grad=False, device=angle.device)[0]
34
+ # one = torch.ones([b], requires_grad=False, device=angle.device)[0]
35
+ zero = z.detach()*0
36
+ one = zero.detach()+1
37
+ zmat = torch.stack([cosz, -sinz, zero,
38
+ sinz, cosz, zero,
39
+ zero, zero, one], dim=_dim).reshape(_view)
40
+
41
+ cosy = torch.cos(y)
42
+ siny = torch.sin(y)
43
+
44
+ ymat = torch.stack([cosy, zero, siny,
45
+ zero, one, zero,
46
+ -siny, zero, cosy], dim=_dim).reshape(_view)
47
+
48
+ cosx = torch.cos(x)
49
+ sinx = torch.sin(x)
50
+
51
+ xmat = torch.stack([one, zero, zero,
52
+ zero, cosx, -sinx,
53
+ zero, sinx, cosx], dim=_dim).reshape(_view)
54
+
55
+ rot_mat = xmat @ ymat @ zmat
56
+ # print(rot_mat)
57
+ return rot_mat
58
+
59
+
60
+ def distribute(depth, _x, _y, size_x, size_y, image_height, image_width):
61
+ """
62
+ Distributes the depth associated with each point to the discrete coordinates (image_height, image_width) in a region
63
+ of size (size_x, size_y).
64
+ :param depth:
65
+ :param _x:
66
+ :param _y:
67
+ :param size_x:
68
+ :param size_y:
69
+ :param image_height:
70
+ :param image_width:
71
+ :return:
72
+ """
73
+
74
+ assert size_x % 2 == 0 or size_x == 1
75
+ assert size_y % 2 == 0 or size_y == 1
76
+ batch, _ = depth.size()
77
+ epsilon = torch.tensor([1e-12], requires_grad=False, device=depth.device)
78
+ _i = torch.linspace(-size_x / 2, (size_x / 2) - 1, size_x, requires_grad=False, device=depth.device)
79
+ _j = torch.linspace(-size_y / 2, (size_y / 2) - 1, size_y, requires_grad=False, device=depth.device)
80
+
81
+ extended_x = _x.unsqueeze(2).repeat([1, 1, size_x]) + _i # [batch, num_points, size_x]
82
+ extended_y = _y.unsqueeze(2).repeat([1, 1, size_y]) + _j # [batch, num_points, size_y]
83
+
84
+ extended_x = extended_x.unsqueeze(3).repeat([1, 1, 1, size_y]) # [batch, num_points, size_x, size_y]
85
+ extended_y = extended_y.unsqueeze(2).repeat([1, 1, size_x, 1]) # [batch, num_points, size_x, size_y]
86
+
87
+ extended_x.ceil_()
88
+ extended_y.ceil_()
89
+
90
+ value = depth.unsqueeze(2).unsqueeze(3).repeat([1, 1, size_x, size_y]) # [batch, num_points, size_x, size_y]
91
+
92
+ # all points that will be finally used
93
+ masked_points = ((extended_x >= 0)
94
+ * (extended_x <= image_height - 1)
95
+ * (extended_y >= 0)
96
+ * (extended_y <= image_width - 1)
97
+ * (value >= 0))
98
+
99
+ true_extended_x = extended_x
100
+ true_extended_y = extended_y
101
+
102
+ # to prevent error
103
+ extended_x = (extended_x % image_height)
104
+ extended_y = (extended_y % image_width)
105
+
106
+ # [batch, num_points, size_x, size_y]
107
+ distance = torch.abs((extended_x - _x.unsqueeze(2).unsqueeze(3))
108
+ * (extended_y - _y.unsqueeze(2).unsqueeze(3)))
109
+ weight = (masked_points.float()
110
+ * (1 / (value + epsilon))) # [batch, num_points, size_x, size_y]
111
+ weighted_value = value * weight
112
+
113
+ weight = weight.view([batch, -1])
114
+ weighted_value = weighted_value.view([batch, -1])
115
+
116
+ coordinates = (extended_x.view([batch, -1]) * image_width) + extended_y.view(
117
+ [batch, -1])
118
+ coord_max = image_height * image_width
119
+ true_coordinates = (true_extended_x.view([batch, -1]) * image_width) + true_extended_y.view(
120
+ [batch, -1])
121
+ true_coordinates[~masked_points.view([batch, -1])] = coord_max
122
+ weight_scattered = torch.zeros(
123
+ [batch, image_width * image_height],
124
+ device=depth.device).scatter_add(1, coordinates.long(), weight)
125
+
126
+ masked_zero_weight_scattered = (weight_scattered == 0.0)
127
+ weight_scattered += masked_zero_weight_scattered.float()
128
+
129
+ weighed_value_scattered = torch.zeros(
130
+ [batch, image_width * image_height],
131
+ device=depth.device).scatter_add(1, coordinates.long(), weighted_value)
132
+
133
+ return weighed_value_scattered, weight_scattered
134
+
135
+
136
+ def points2depth(points, image_height, image_width, size_x=4, size_y=4):
137
+ """
138
+ :param points: [B, num_points, 3]
139
+ :param image_width:
140
+ :param image_height:
141
+ :param size_x:
142
+ :param size_y:
143
+ :return:
144
+ depth_recovered: [B, image_width, image_height]
145
+ """
146
+
147
+ epsilon = torch.tensor([1e-12], requires_grad=False, device=points.device)
148
+ # epsilon not needed, kept here to ensure exact replication of old version
149
+ coord_x = (points[:, :, 0] / (points[:, :, 2] + epsilon)) * (image_width / image_height) # [batch, num_points]
150
+ coord_y = (points[:, :, 1] / (points[:, :, 2] + epsilon)) # [batch, num_points]
151
+
152
+ batch, total_points, _ = points.size()
153
+ depth = points[:, :, 2] # [batch, num_points]
154
+ # pdb.set_trace()
155
+ _x = ((coord_x + 1) * image_height) / 2
156
+ _y = ((coord_y + 1) * image_width) / 2
157
+
158
+ weighed_value_scattered, weight_scattered = distribute(
159
+ depth=depth,
160
+ _x=_x,
161
+ _y=_y,
162
+ size_x=size_x,
163
+ size_y=size_y,
164
+ image_height=image_height,
165
+ image_width=image_width)
166
+
167
+ depth_recovered = (weighed_value_scattered / weight_scattered).view([
168
+ batch, image_height, image_width
169
+ ])
170
+
171
+ return depth_recovered
172
+
173
+
174
+ # source: https://discuss.pytorch.org/t/batched-index-select/9115/6
175
+ def batched_index_select(inp, dim, index):
176
+ """
177
+ input: B x * x ... x *
178
+ dim: 0 < scalar
179
+ index: B x M
180
+ """
181
+ views = [inp.shape[0]] + \
182
+ [1 if i != dim else -1 for i in range(1, len(inp.shape))]
183
+ expanse = list(inp.shape)
184
+ expanse[0] = -1
185
+ expanse[dim] = -1
186
+ index = index.view(views).expand(expanse)
187
+ return torch.gather(inp, dim, index)
188
+
189
+
190
+ def point_fea_img_fea(point_fea, point_coo, h, w):
191
+ """
192
+ each point_coo is of the form (x*w + h). points not in the canvas are removed
193
+ :param point_fea: [batch_size, num_points, feat_size]
194
+ :param point_coo: [batch_size, num_points]
195
+ :return:
196
+ """
197
+ assert len(point_fea.shape) == 3
198
+ assert len(point_coo.shape) == 2
199
+ assert point_fea.shape[0:2] == point_coo.shape
200
+
201
+ coo_max = ((h - 1) * w) + (w - 1)
202
+ mask_point_coo = (point_coo >= 0) * (point_coo <= coo_max)
203
+ point_coo *= mask_point_coo.float()
204
+ point_fea *= mask_point_coo.float().unsqueeze(-1)
205
+
206
+ bs, _, fs = point_fea.shape
207
+ point_coo = point_coo.unsqueeze(2).repeat([1, 1, fs])
208
+ img_fea = torch.zeros([bs, h * w, fs], device=point_fea.device).scatter_add(1, point_coo.long(), point_fea)
209
+
210
+ return img_fea
211
+
212
+
213
+ def distribute_img_fea_points(img_fea, point_coord):
214
+ """
215
+ :param img_fea: [B, C, H, W]
216
+ :param point_coord: [B, num_points], each coordinate is a scalar value given by (x * W) + y
217
+ :return
218
+ point_fea: [B, num_points, C], for points with coordinates outside the image, we return 0
219
+ """
220
+ B, C, H, W = list(img_fea.size())
221
+ img_fea = img_fea.permute(0, 2, 3, 1).view([B, H*W, C])
222
+
223
+ coord_max = ((H - 1) * W) + (W - 1)
224
+ mask_point_coord = (point_coord >= 0) * (point_coord <= coord_max)
225
+ mask_point_coord = mask_point_coord.float()
226
+ point_coord = mask_point_coord * point_coord
227
+ point_fea = batched_index_select(
228
+ inp=img_fea,
229
+ dim=1,
230
+ index=point_coord.long())
231
+ point_fea = mask_point_coord.unsqueeze(-1) * point_fea
232
+ return point_fea
233
+
234
+
235
+ class PCViews:
236
+ """For creating images from PC based on the view information. Faster as the
237
+ repeated operations are done only once whie initialization.
238
+ """
239
+
240
+ def __init__(self):
241
+ _views = np.asarray([
242
+ [[0 * np.pi / 2, 0, np.pi / 2], [0, 0, TRANS]],
243
+ [[1 * np.pi / 2, 0, np.pi / 2], [0, 0, TRANS]],
244
+ [[2 * np.pi / 2, 0, np.pi / 2], [0, 0, TRANS]],
245
+ [[3 * np.pi / 2, 0, np.pi / 2], [0, 0, TRANS]],
246
+ [[0, -np.pi / 2, np.pi / 2], [0, 0, TRANS]],
247
+ [[0, np.pi / 2, np.pi / 2], [0, 0, TRANS]]])
248
+ self.num_views = 6
249
+ angle = torch.tensor(_views[:, 0, :]).float().cuda()
250
+ self.rot_mat = euler2mat(angle).transpose(1, 2)
251
+ self.translation = torch.tensor(_views[:, 1, :]).float().cuda()
252
+ self.translation = self.translation.unsqueeze(1)
253
+
254
+ def get_img(self, points):
255
+ """Get image based on the prespecified specifications.
256
+
257
+ Args:
258
+ points (torch.tensor): of size [B, _, 3]
259
+ Returns:
260
+ img (torch.tensor): of size [B * self.num_views, RESOLUTION,
261
+ RESOLUTION]
262
+ """
263
+ b, _, _ = points.shape
264
+ v = self.translation.shape[0]
265
+
266
+ _points = self.point_transform(
267
+ points=torch.repeat_interleave(points, v, dim=0),
268
+ rot_mat=self.rot_mat.repeat(b, 1, 1),
269
+ translation=self.translation.repeat(b, 1, 1))
270
+
271
+ img = points2depth(
272
+ points=_points,
273
+ image_height=RESOLUTION,
274
+ image_width=RESOLUTION,
275
+ size_x=1,
276
+ size_y=1,
277
+ )
278
+ return img
279
+
280
+ @staticmethod
281
+ def point_transform(points, rot_mat, translation):
282
+ """
283
+ :param points: [batch, num_points, 3]
284
+ :param rot_mat: [batch, 3]
285
+ :param translation: [batch, 1, 3]
286
+ :return:
287
+ """
288
+ rot_mat = rot_mat.to(points.device)
289
+ translation = translation.to(points.device)
290
+ points = torch.matmul(points, rot_mat)
291
+ points = points - translation
292
+ return points
@@ -0,0 +1,13 @@
1
+ from openpoints.utils import registry
2
+ MODELS = registry.Registry('models')
3
+
4
+
5
+ def build_model_from_cfg(cfg, **kwargs):
6
+ """
7
+ Build a model, defined by `NAME`.
8
+ Args:
9
+ cfg (eDICT):
10
+ Returns:
11
+ Model: a constructed model specified by NAME.
12
+ """
13
+ return MODELS.build(cfg, **kwargs)
@@ -0,0 +1,5 @@
1
+ """
2
+ Author: PointNeXt
3
+
4
+ """
5
+ from .cls_base import BaseCls, ClsHead
@@ -0,0 +1,136 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ import logging
4
+ from typing import List
5
+ from ..layers import create_linearblock
6
+ from ...utils import get_missing_parameters_message, get_unexpected_parameters_message
7
+ from ..build import MODELS, build_model_from_cfg
8
+ from ...loss import build_criterion_from_cfg
9
+ from ...utils import load_checkpoint
10
+
11
+
12
+ @MODELS.register_module()
13
+ class BaseCls(nn.Module):
14
+ def __init__(self,
15
+ encoder_args=None,
16
+ cls_args=None,
17
+ criterion_args=None,
18
+ **kwargs):
19
+ super().__init__()
20
+ self.encoder = build_model_from_cfg(encoder_args)
21
+
22
+ if cls_args is not None:
23
+ in_channels = self.encoder.out_channels if hasattr(self.encoder, 'out_channels') else cls_args.get('in_channels', None)
24
+ cls_args.in_channels = in_channels
25
+ self.prediction = build_model_from_cfg(cls_args)
26
+ else:
27
+ self.prediction = nn.Identity()
28
+ self.criterion = build_criterion_from_cfg(criterion_args) if criterion_args is not None else None
29
+
30
+ def forward(self, data):
31
+ global_feat = self.encoder.forward_cls_feat(data)
32
+ return self.prediction(global_feat)
33
+
34
+ def get_loss(self, pred, gt, inputs=None):
35
+ return self.criterion(pred, gt.long())
36
+
37
+ def get_logits_loss(self, data, gt):
38
+ logits = self.forward(data)
39
+ return logits, self.criterion(logits, gt.long())
40
+
41
+
42
+ @MODELS.register_module()
43
+ class DistillCls(BaseCls):
44
+ def __init__(self,
45
+ encoder_args=None,
46
+ cls_args=None,
47
+ distill_args=None,
48
+ criterion_args=None,
49
+ **kwargs):
50
+ super().__init__(encoder_args, cls_args, criterion_args)
51
+ self.distill = encoder_args.get('distill', True)
52
+ in_channels = self.encoder.distill_channels
53
+ distill_args.distill_head_args.in_channels = in_channels
54
+ self.dist_head = build_model_from_cfg(distill_args.distill_head_args)
55
+ self.dist_model = build_model_from_cfg(distill_args).cuda()
56
+ load_checkpoint(self.dist_model, distill_args.pretrained_path)
57
+ self.dist_model.eval()
58
+
59
+ def forward(self, p0, f0=None):
60
+ if hasattr(p0, 'keys'):
61
+ p0, f0 = p0['pos'], p0['x']
62
+ if self.distill and self.training:
63
+ global_feat, distill_feature = self.encoder.forward_cls_feat(p0, f0)
64
+ return self.prediction(global_feat), self.dist_head(distill_feature)
65
+ else:
66
+ global_feat = self.encoder.forward_cls_feat(p0, f0)
67
+ return self.prediction(global_feat)
68
+
69
+ def get_loss(self, pred, gt, inputs):
70
+ return self.criterion(inputs, pred, gt.long(), self.dist_model)
71
+
72
+ def get_logits_loss(self, data, gt):
73
+ logits, dist_logits = self.forward(data)
74
+ return logits, self.criterion(data, [logits, dist_logits], gt.long(), self.dist_model)
75
+
76
+
77
+ @MODELS.register_module()
78
+ class ClsHead(nn.Module):
79
+ def __init__(self,
80
+ num_classes: int,
81
+ in_channels: int,
82
+ mlps: List[int]=[256],
83
+ norm_args: dict=None,
84
+ act_args: dict={'act': 'relu'},
85
+ dropout: float=0.5,
86
+ global_feat: str=None,
87
+ point_dim: int=2,
88
+ **kwargs
89
+ ):
90
+ """A general classification head. supports global pooling and [CLS] token
91
+ Args:
92
+ num_classes (int): class num
93
+ in_channels (int): input channels size
94
+ mlps (List[int], optional): channel sizes for hidden layers. Defaults to [256].
95
+ norm_args (dict, optional): dict of configuration for normalization. Defaults to None.
96
+ act_args (_type_, optional): dict of configuration for activation. Defaults to {'act': 'relu'}.
97
+ dropout (float, optional): use dropout when larger than 0. Defaults to 0.5.
98
+ cls_feat (str, optional): preprocessing input features to obtain global feature.
99
+ $\eg$ cls_feat='max,avg' means use the concatenateion of maxpooled and avgpooled features.
100
+ Defaults to None, which means the input feautre is the global feature
101
+ Returns:
102
+ logits: (B, num_classes, N)
103
+ """
104
+ super().__init__()
105
+ if kwargs:
106
+ logging.warning(f"kwargs: {kwargs} are not used in {__class__.__name__}")
107
+ self.global_feat = global_feat.split(',') if global_feat is not None else None
108
+ self.point_dim = point_dim
109
+ in_channels = len(self.global_feat) * in_channels if global_feat is not None else in_channels
110
+ if mlps is not None:
111
+ mlps = [in_channels] + mlps + [num_classes]
112
+ else:
113
+ mlps = [in_channels, num_classes]
114
+
115
+ heads = []
116
+ for i in range(len(mlps) - 2):
117
+ heads.append(create_linearblock(mlps[i], mlps[i + 1],
118
+ norm_args=norm_args,
119
+ act_args=act_args))
120
+ if dropout:
121
+ heads.append(nn.Dropout(dropout))
122
+ heads.append(create_linearblock(mlps[-2], mlps[-1], act_args=None))
123
+ self.head = nn.Sequential(*heads)
124
+
125
+
126
+ def forward(self, end_points):
127
+ if self.global_feat is not None:
128
+ global_feats = []
129
+ for preprocess in self.global_feat:
130
+ if 'max' in preprocess:
131
+ global_feats.append(torch.max(end_points, dim=self.point_dim, keepdim=False)[0])
132
+ elif preprocess in ['avg', 'mean']:
133
+ global_feats.append(torch.mean(end_points, dim=self.point_dim, keepdim=False))
134
+ end_points = torch.cat(global_feats, dim=1)
135
+ logits = self.head(end_points)
136
+ return logits