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,286 @@
1
+ # Patch embedding for 2D/3D data
2
+ # Reference:
3
+ import math
4
+ import torch
5
+ from torch import nn as nn
6
+ import torch.nn.functional as F
7
+ from .subsample import furthest_point_sample, random_sample
8
+ from .group import KNNGroup, QueryAndGroup, create_grouper, get_aggregation_feautres
9
+ from .conv import create_convblock1d, create_convblock2d, create_linearblock, create_norm, create_act
10
+ from .local_aggregation import CHANNEL_MAP
11
+ from ..build import MODELS
12
+
13
+
14
+ class SubsampleGroup(nn.Module):
15
+ """ Point cloud to subsampled groups
16
+ """
17
+
18
+ def __init__(self,
19
+ num_groups=256, group_size=32,
20
+ subsample='fps', # random, FPS
21
+ group='ballquery',
22
+ radius=0.1,
23
+ **kwargs
24
+ ):
25
+ super().__init__()
26
+ self.num_groups = num_groups
27
+ self.group_size = group_size
28
+
29
+ self.subsample = subsample
30
+ self.group = group
31
+
32
+ if 'ball' in self.group.lower() or 'query' in self.group.lower():
33
+ self.grouper = QueryAndGroup(radius, self.group_size)
34
+ elif 'knn' in self.group.lower():
35
+ self.grouper = KNNGroup(self.group_size)
36
+ else:
37
+ raise NotImplementedError(f'{self.group.lower()} is not implemented. Only support ballquery, knn')
38
+
39
+ def forward(self, p, x=None):
40
+ if 'fps' in self.subsample.lower() or 'furthest' in self.subsample.lower() or 'farthest' in self.subsample.lower():
41
+ idx = furthest_point_sample(p, self.num_groups).to(torch.int64)
42
+ elif 'random' in self.subsample.lower() or 'rs' in self.subsample.lower():
43
+ idx = random_sample(p, self.num_groups)
44
+ else:
45
+ raise NotImplementedError(f'{self.subsample.lower()} is not implemented. Only support fps, random')
46
+ center_p = torch.gather(p, 1,
47
+ idx.unsqueeze(-1).expand(-1, -1, 3)) # downsampled point cloud, [B, npoint, 3]
48
+ if x is not None:
49
+ B, C, N = x.shape[:3]
50
+ center_x = torch.gather(x, 2, idx.unsqueeze(1).expand(-1, C, -1)).unsqueeze(-1)
51
+ grouped_p, fj = self.grouper(center_p, p, x)
52
+ return grouped_p, center_p, fj, center_x
53
+ else:
54
+ grouped_p, _ = self.grouper(center_p, p)
55
+ return grouped_p, center_p
56
+
57
+
58
+ @MODELS.register_module()
59
+ class PointPatchEmbed(nn.Module):
60
+ """ Point cloud to Group Embedding using GCN
61
+ Patch Embedding for 3d data (point cloud)
62
+ A convolution based approach to patchifying a point cloud w/ embedding projection.
63
+ """
64
+
65
+ def __init__(self,
66
+ sample_ratio=0.0625, group_size=32,
67
+ in_channels=3,
68
+ layers=4,
69
+ embed_dim=256,
70
+ channels=None,
71
+ subsample='fps', # random, FPS
72
+ group='ballquery',
73
+ normalize_dp=False,
74
+ radius=0.1,
75
+ feature_type='dp_df',
76
+ relative_xyz=True,
77
+ norm_args={'norm': 'bn1d'},
78
+ act_args={'act': 'relu'},
79
+ conv_args={'order': 'conv-norm-act'},
80
+ reduction='max',
81
+ **kwargs
82
+ ):
83
+ super().__init__()
84
+ self.sample_ratio = sample_ratio
85
+ self.group_size = group_size
86
+
87
+ self.feature_type = feature_type
88
+ # subsample layer and group layer
89
+ if subsample.lower() == 'fps':
90
+ self.sample_fn = furthest_point_sample
91
+ elif 'random' in subsample.lower():
92
+ self.sample_fn = random_sample
93
+
94
+ # TODO: make this embedding progressively
95
+ self.group = group.lower()
96
+ if 'ball' in self.group or 'query' in self.group:
97
+ self.grouper = QueryAndGroup(nsample=self.group_size,
98
+ relative_xyz=relative_xyz, normalize_dp=normalize_dp,
99
+ radius=radius)
100
+ elif 'knn' in self.group.lower():
101
+ self.grouper = KNNGroup(self.group_size, relative_xyz=relative_xyz, normalize_dp=normalize_dp)
102
+ else:
103
+ raise NotImplementedError(f'{self.group.lower()} is not implemented. Only support ballquery, knn')
104
+
105
+ # # convolutions
106
+ if channels is None:
107
+ channels = [CHANNEL_MAP[feature_type](in_channels)] + [embed_dim] * (layers // 2) + [embed_dim * 2] * (
108
+ layers // 2 - 1) + [embed_dim]
109
+ else:
110
+ channels = [CHANNEL_MAP[feature_type](in_channels)] + channels + [embed_dim]
111
+ layers = len(channels) -1
112
+ conv1 = []
113
+ for i in range(layers // 2):
114
+ conv1.append(create_convblock2d(channels[i], channels[i + 1],
115
+ norm_args=norm_args if i!=(layers//2-1) else None,
116
+ act_args=act_args if i!=(layers//2-1) else None,
117
+ **conv_args))
118
+ self.conv1 = nn.Sequential(*conv1)
119
+
120
+ channels[layers // 2] *= 2
121
+ conv2 = []
122
+ for i in range(layers // 2, layers):
123
+ conv2.append(create_convblock2d(channels[i], channels[i + 1],
124
+ norm_args=norm_args if i!=(layers-1) else None,
125
+ act_args=act_args if i!=(layers-1) else None,
126
+ **conv_args
127
+ ))
128
+ self.conv2 = nn.Sequential(*conv2)
129
+
130
+ # reduction layer
131
+ if reduction in ['mean', 'avg', 'meanpool', 'avgpool']:
132
+ self.pool = lambda x: torch.mean(x, dim=-1, keepdim=True)
133
+ else:
134
+ self.pool = lambda x: torch.max(x, dim=-1, keepdim=True)[0]
135
+ self.out_channels = channels[-1]
136
+ self.channel_list = [in_channels, embed_dim]
137
+
138
+ def forward(self, p, x=None):
139
+ # downsample
140
+ B, N, _ = p.shape[:3]
141
+ idx = self.sample_fn(p, int(N * self.sample_ratio)).long()
142
+ center_p = torch.gather(p, 1, idx.unsqueeze(-1).expand(-1, -1, 3))
143
+
144
+ # query neighbors.
145
+ dp, fj = self.grouper(center_p, p, x)
146
+
147
+ """visualization
148
+ from openpoints.dataset.vis3d import vis_multi_points
149
+ new_p = (dp.permute(0, 2, 3, 1) + center_p.unsqueeze(2)).view(B, -1, 3)
150
+ vis_multi_points([p[0].cpu().numpy(), new_p[0].cpu().numpy(), center_p[0].cpu().numpy()])
151
+ """
152
+
153
+ # concat neighborhood x
154
+ # TODO: using a local aggregation layer
155
+ if self.feature_type == 'dp':
156
+ fj = dp
157
+ elif self.feature_type == 'dp_fj':
158
+ fj = torch.cat([dp, fj], dim=1)
159
+ elif self.feature_type == 'dp_df':
160
+ center_x = torch.gather(x, 2, idx.unsqueeze(1).expand(-1, x.shape[1], -1))
161
+ fj = torch.cat([dp, fj - center_x.unsqueeze(-1)], dim=1)
162
+ elif self.feature_type == 'df':
163
+ center_x = torch.gather(x, 2, idx.unsqueeze(1).expand(-1, x.shape[1], -1))
164
+ fj = fj - center_x.unsqueeze(-1)
165
+ fj = self.conv1(fj)
166
+
167
+ fj = torch.cat(
168
+ [self.pool(fj).expand(-1, -1, -1, self.group_size),
169
+ fj],
170
+ dim=1)
171
+ out_f = self.pool(self.conv2(fj)).squeeze(-1)
172
+ return [p, center_p], [x, out_f]
173
+
174
+
175
+ @MODELS.register_module()
176
+ class P3Embed(nn.Module):
177
+ """
178
+ Progressive Point Patch Embedding for 3d data (point cloud)
179
+ A convolution based approach to patchifying a point cloud w/ embedding projection.
180
+ """
181
+
182
+ def __init__(self,
183
+ sample_ratio=0.0625,
184
+ scale=4,
185
+ group_size=32,
186
+ in_channels=3,
187
+ layers=4,
188
+ embed_dim=256,
189
+ subsample='fps', # random, FPS
190
+ group='ballquery',
191
+ normalize_dp=False,
192
+ radius=0.1,
193
+ feature_type='dp_df',
194
+ relative_xyz=True,
195
+ norm_args={'norm': 'bn1d'},
196
+ act_args={'act': 'relu'},
197
+ conv_args={'order': 'conv-norm-act'},
198
+ reduction='max',
199
+ **kwargs
200
+ ):
201
+ super().__init__()
202
+ self.sample_ratio = sample_ratio
203
+ self.group_size = group_size
204
+
205
+ self.feature_type = feature_type
206
+ # subsample layer and group layer
207
+ if subsample.lower() == 'fps':
208
+ self.sample_fn = furthest_point_sample
209
+ elif 'random' in subsample.lower():
210
+ self.sample_fn = random_sample
211
+
212
+ self.group = group.lower()
213
+ if 'ball' in self.group or 'query' in self.group:
214
+ self.grouper = QueryAndGroup(nsample=self.group_size,
215
+ relative_xyz=relative_xyz, normalize_dp=normalize_dp,
216
+ radius=radius)
217
+ elif 'knn' in self.group.lower():
218
+ self.grouper = KNNGroup(self.group_size, relative_xyz=relative_xyz, normalize_dp=normalize_dp)
219
+ else:
220
+ raise NotImplementedError(f'{self.group.lower()} is not implemented. Only support ballquery, knn')
221
+
222
+ # stages
223
+ stages = int(math.log(1/sample_ratio, scale))
224
+ embed_dim = int(embed_dim // 2 ** (stages-1))
225
+ self.convs = nn.ModuleList()
226
+ self.channel_list = [in_channels]
227
+ for _ in range(int(stages)):
228
+ # convolutions
229
+ channels = [CHANNEL_MAP[feature_type](in_channels)] + [embed_dim] * (layers // 2) + [embed_dim * 2] * (
230
+ layers // 2 - 1) + [embed_dim]
231
+ conv1 = []
232
+ for i in range(layers // 2):
233
+ conv1.append(create_convblock2d(channels[i], channels[i + 1],
234
+ norm_args=norm_args if i!=(layers//2-1) else None,
235
+ act_args=act_args if i!=(layers//2-1) else None,
236
+ **conv_args))
237
+ conv1 = nn.Sequential(*conv1)
238
+
239
+ channels[layers // 2] *= 2
240
+ conv2 = []
241
+ for i in range(layers // 2, layers):
242
+ conv2.append(create_convblock2d(channels[i], channels[i + 1],
243
+ norm_args=norm_args,
244
+ act_args=act_args,
245
+ **conv_args
246
+ ))
247
+ conv2 = nn.Sequential(*conv2)
248
+ self.convs.append(nn.ModuleList([conv1, conv2]))
249
+
250
+ self.channel_list.append(embed_dim)
251
+ in_channels = embed_dim
252
+ embed_dim *= 2
253
+
254
+ # reduction layer
255
+ if reduction in ['mean', 'avg', 'meanpool', 'avgpool']:
256
+ self.pool = lambda x: torch.mean(x, dim=-1, keepdim=True)
257
+ else:
258
+ self.pool = lambda x: torch.max(x, dim=-1, keepdim=True)[0]
259
+ self.out_channels = channels[-1]
260
+
261
+ def forward(self, p, f=None):
262
+ B, N, _ = p.shape[:3]
263
+ out_p, out_f = [p], [f]
264
+ for convs in self.convs:
265
+ # Progressive downsampling
266
+ cur_p, cur_f = out_p[-1], out_f[-1]
267
+ idx = self.sample_fn(cur_p, int(N //4)).long()
268
+ N = N // 4
269
+ center_p = torch.gather(cur_p, 1, idx.unsqueeze(-1).expand(-1, -1, 3))
270
+ center_f = torch.gather(cur_f, 2, idx.unsqueeze(1).expand(-1, cur_f.shape[1], -1))
271
+
272
+ # query neighbors.
273
+ dp, fj = self.grouper(center_p, cur_p, cur_f)
274
+ fj = get_aggregation_feautres(center_p, dp, center_f, fj, self.feature_type)
275
+
276
+ # graph convolutions
277
+ fj = convs[0](fj)
278
+ fj = torch.cat(
279
+ [self.pool(fj).expand(-1, -1, -1, self.group_size),
280
+ fj],
281
+ dim=1)
282
+
283
+ # output
284
+ out_f.append(self.pool(convs[1](fj)).squeeze(-1))
285
+ out_p.append(center_p)
286
+ return out_p, out_f
@@ -0,0 +1,43 @@
1
+ """ Layer/Module Helpers
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+ from itertools import repeat
6
+ import collections.abc
7
+ from torch import nn
8
+
9
+
10
+ # From PyTorch internals
11
+ def _ntuple(n):
12
+ def parse(x):
13
+ if isinstance(x, collections.abc.Iterable):
14
+ return x
15
+ return tuple(repeat(x, n))
16
+ return parse
17
+
18
+
19
+ to_1tuple = _ntuple(1)
20
+ to_2tuple = _ntuple(2)
21
+ to_3tuple = _ntuple(3)
22
+ to_4tuple = _ntuple(4)
23
+ to_ntuple = _ntuple
24
+
25
+
26
+ def make_divisible(v, divisor=8, min_value=None, round_limit=.9):
27
+ min_value = min_value or divisor
28
+ new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
29
+ # Make sure that round down does not go down by more than 10%.
30
+ if new_v < round_limit * v:
31
+ new_v += divisor
32
+ return new_v
33
+
34
+
35
+
36
+ class MultipleSequential(nn.Sequential):
37
+ def forward(self, *inputs):
38
+ for module in self._modules.values():
39
+ if type(inputs) == tuple:
40
+ inputs = module(*inputs)
41
+ else:
42
+ inputs = module(inputs)
43
+ return inputs
@@ -0,0 +1,119 @@
1
+ import torch
2
+ from torch import nn
3
+ from fast_pytorch_kmeans import KMeans, MultiKMeans
4
+ from torch_scatter import scatter
5
+ from .local_aggregation import CHANNEL_MAP
6
+
7
+
8
+ class KMeansEmbed(nn.Module):
9
+ """ Point cloud to subsampled groups
10
+ """
11
+
12
+ def __init__(self,
13
+ in_chans=3,
14
+ num_groups=256,
15
+ encoder_dim=256,
16
+ feature_type='dp',
17
+ **kwargs
18
+ ):
19
+ super().__init__()
20
+
21
+ self.num_groups = num_groups
22
+
23
+ self.kmeans = MultiKMeans(n_clusters=num_groups, n_kmeans=32, mode='euclidean', verbose=0)
24
+
25
+ channels = CHANNEL_MAP[feature_type](in_chans)
26
+ self.feature_type = feature_type
27
+ self.conv1 = nn.Sequential(
28
+ nn.Linear(channels, 128), # TODO: here, can be better, edgeconv.
29
+ nn.LayerNorm(128),
30
+ nn.ReLU(inplace=True),
31
+ nn.Linear(128, 256)
32
+ )
33
+ self.conv2 = nn.Sequential(
34
+ nn.Linear(512, 512),
35
+ nn.LayerNorm(512),
36
+ nn.ReLU(inplace=True),
37
+ nn.Linear(512, encoder_dim)
38
+ )
39
+
40
+ def forward(self, xyz, features=None):
41
+ B, N, _ = xyz.shape
42
+ self.kmeans.centroids = None # re-init kmeans
43
+ self.kmeans.n_kmeans = xyz.shape[0]
44
+ labels = self.kmeans.fit_predict(xyz) # B,N
45
+
46
+ # TODO: BUG, sometimes the value is even smaller than the number of centroids!!
47
+ centroids = self.kmeans.centroids # B, K, 3
48
+ idx = labels.unsqueeze(-1)
49
+
50
+ # p_j = xyz
51
+ p_i = torch.gather(centroids, 1, labels.unsqueeze(-1).expand(-1, -1, 3)) # B, N, 3
52
+ relative_xyz = xyz - p_i # p_j-p_i, B, N, 3
53
+
54
+ if self.feature_type == 'dp':
55
+ neighborhood_features = relative_xyz
56
+ elif self.feature_type == 'pj_dp':
57
+ neighborhood_features = torch.cat([xyz, relative_xyz], -1)
58
+ elif self.feature_type == 'pi_dp':
59
+ neighborhood_features = torch.cat([p_i, relative_xyz], -1)
60
+
61
+ neighborhood_features = self.conv1(neighborhood_features) # B, N, C
62
+ pooled_feat = scatter(neighborhood_features, idx, dim=1, reduce='max') # B, K, C
63
+ reapted_feat = torch.gather(pooled_feat, 1, idx.expand(-1, -1, pooled_feat.shape[-1]))
64
+ neighborhood_features = torch.cat([reapted_feat, neighborhood_features], dim=-1)
65
+ out_features = scatter(self.conv2(neighborhood_features), idx, dim=1, reduce='max')
66
+ return centroids, out_features, p_i, labels
67
+
68
+
69
+ if __name__ == "__main__":
70
+ import torch
71
+ import os, sys
72
+ sys.path.insert(0, os.path.join(os.path.abspath(__file__), "../../../../"))
73
+ from openpoints.dataset import ModelNet, vis_points, vis_multi_points
74
+ from openpoints.models.layers import fps
75
+
76
+ B, C, N = 8, 3, 8196
77
+ device = 'cuda'
78
+
79
+ dataset = ModelNet("data/ModelNet40",
80
+ N, 40, split='test')
81
+ test_datalodaer = torch.utils.data.DataLoader(dataset, batch_size=B, num_workers=1
82
+ )
83
+ data = iter(test_datalodaer).next()[0]
84
+ points = data['pos'].to(device)
85
+
86
+ points = fps(points, N)
87
+ print(points.shape)
88
+ # debug one batch
89
+ K = 12
90
+ print(points.shape, points.device)
91
+
92
+ #
93
+ # kmeans_group = KMeansGroup(K).to(device)
94
+ # kmeans_group(points)
95
+
96
+ kmeans = KMeans(n_clusters=K, mode='euclidean', verbose=1)
97
+ labels = kmeans.fit_predict(points[0])
98
+ print(labels.shape)
99
+ # 0.5207s for 10000 points, too slow!
100
+ # vis_points(points[0], labels=labels)
101
+ center_points = kmeans.centroids
102
+ print(center_points.shape)
103
+ # vis_multi_points([points.cpu().numpy(), center_points])
104
+ vis_points(points[0], labels=labels)
105
+
106
+ # B, N, 3
107
+ # B, N, 1 (label index)
108
+
109
+ # debug 8 batch
110
+ # K = 8
111
+ # print(points.shape, points.device)
112
+ # kmeans = MultiKMeans(n_clusters=K, n_kmeans=B,
113
+ # mode='euclidean', verbose=1)
114
+ # labels = kmeans.fit_predict(points)
115
+ # print(labels.shape)
116
+ # # 0.5207s for 10000 points, too slow!
117
+ # # vis_multi_points(points.cpu().numpy()[:4], labels=labels.cpu().numpy()[:4])
118
+ # vis_points(points[0], labels=labels[0])
119
+ # vis_points(points[1], labels=labels[1])
@@ -0,0 +1,110 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ # from knn_cuda import KNN as KNNCUDA
4
+
5
+
6
+ @torch.no_grad()
7
+ def knn_point(k, query, support=None):
8
+ """Get the distances and indices to a fixed number of neighbors
9
+ Args:
10
+ support ([tensor]): [B, N, C]
11
+ query ([tensor]): [B, M, C]
12
+
13
+ Returns:
14
+ [int]: neighbor idx. [B, M, K]
15
+ """
16
+ if support is None:
17
+ support = query
18
+ dist = torch.cdist(query, support)
19
+ k_dist = dist.topk(k=k, dim=-1, largest=False, sorted=True)
20
+ return k_dist.values, k_dist.indices
21
+
22
+
23
+ class KNN(nn.Module):
24
+ """Get the distances and indices to a fixed number of neighbors
25
+
26
+ Reference: https://gist.github.com/ModarTensai/60fe0d0e3536adc28778448419908f47
27
+
28
+ Args:
29
+ neighbors: number of neighbors to consider
30
+ p_norm: distances are computed based on L_p norm
31
+ farthest: whether to get the farthest or the nearest neighbors
32
+ ordered: distance sorted (descending if `farthest`)
33
+
34
+ Returns:
35
+ (distances, indices) both of shape [B, N, `num_neighbors`]
36
+ """
37
+
38
+ def __init__(self, neighbors,
39
+ farthest=False,
40
+ sorted=True,
41
+ **kwargs):
42
+ super(KNN, self).__init__()
43
+ self.neighbors = neighbors
44
+ self.farthest = farthest
45
+ self.sorted = sorted
46
+
47
+ @torch.no_grad()
48
+ def forward(self, query, support=None):
49
+ """
50
+ Args:
51
+ support ([tensor]): [B, N, C]
52
+ query ([tensor]): [B, M, C]
53
+
54
+ Returns:
55
+ [int]: neighbor idx. [B, M, K]
56
+ """
57
+ if support is None:
58
+ support = query
59
+ dist = torch.cdist(query, support)
60
+ k_dist = dist.topk(k=self.neighbors, dim=-1, largest=self.farthest, sorted=self.sorted)
61
+ return k_dist.values, k_dist.indices.int()
62
+
63
+
64
+ # dilated knn
65
+ class DenseDilated(nn.Module):
66
+ """
67
+ Find dilated neighbor from neighbor list
68
+ index: (B, npoint, nsample)
69
+ """
70
+
71
+ def __init__(self, k=9, dilation=1, stochastic=False, epsilon=0.0):
72
+ super(DenseDilated, self).__init__()
73
+ self.dilation = dilation
74
+ self.stochastic = stochastic
75
+ self.epsilon = epsilon
76
+ self.k = k
77
+
78
+ def forward(self, edge_index):
79
+ if self.stochastic:
80
+ if torch.rand(1) < self.epsilon and self.training:
81
+ num = self.k * self.dilation
82
+ randnum = torch.randperm(num)[:self.k]
83
+ edge_index = edge_index[:, :, randnum]
84
+ else:
85
+ edge_index = edge_index[:, :, ::self.dilation]
86
+ else:
87
+ edge_index = edge_index[:, :, ::self.dilation]
88
+ return edge_index.contiguous()
89
+
90
+
91
+ class DilatedKNN(nn.Module):
92
+ """
93
+ Find the neighbors' indices based on dilated knn
94
+ """
95
+
96
+ def __init__(self, k=9, dilation=1, stochastic=False, epsilon=0.0):
97
+ super(DilatedKNN, self).__init__()
98
+ self.dilation = dilation
99
+ self.stochastic = stochastic
100
+ self.epsilon = epsilon
101
+ self.k = k
102
+ self._dilated = DenseDilated(k, dilation, stochastic, epsilon)
103
+ # self.knn = KNNCUDA(k * self.dilation, transpose_mode=True)
104
+ self.knn = KNN(k * self.dilation, transpose_mode=True)
105
+
106
+ def forward(self, query):
107
+ _, idx = self.knn(query, query)
108
+ return self._dilated(idx)
109
+
110
+