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,297 @@
1
+ """ Dataset parser interface that wraps TFDS datasets
2
+
3
+ Wraps many (most?) TFDS image-classification datasets
4
+ from https://github.com/tensorflow/datasets
5
+ https://www.tensorflow.org/datasets/catalog/overview#image_classification
6
+
7
+ Hacked together by / Copyright 2020 Ross Wightman
8
+ """
9
+ import math
10
+ import torch
11
+ import torch.distributed as dist
12
+ from PIL import Image
13
+
14
+ try:
15
+ import tensorflow as tf
16
+ tf.config.set_visible_devices([], 'GPU') # Hands off my GPU! (or pip install tensorflow-cpu)
17
+ import tensorflow_datasets as tfds
18
+ try:
19
+ tfds.even_splits('', 1, drop_remainder=False) # non-buggy even_splits has drop_remainder arg
20
+ has_buggy_even_splits = False
21
+ except TypeError:
22
+ print("Warning: This version of tfds doesn't have the latest even_splits impl. "
23
+ "Please update or use tfds-nightly for better fine-grained split behaviour.")
24
+ has_buggy_even_splits = True
25
+ except ImportError as e:
26
+ print(e)
27
+ print("Please install tensorflow_datasets package `pip install tensorflow-datasets`.")
28
+ exit(1)
29
+ from .parser import Parser
30
+
31
+
32
+ MAX_TP_SIZE = 8 # maximum TF threadpool size, only doing jpeg decodes and queuing activities
33
+ SHUFFLE_SIZE = 8192 # examples to shuffle in DS queue
34
+ PREFETCH_SIZE = 2048 # examples to prefetch
35
+
36
+
37
+ def even_split_indices(split, n, num_examples):
38
+ partitions = [round(i * num_examples / n) for i in range(n + 1)]
39
+ return [f"{split}[{partitions[i]}:{partitions[i + 1]}]" for i in range(n)]
40
+
41
+
42
+ def get_class_labels(info):
43
+ if 'label' not in info.features:
44
+ return {}
45
+ class_label = info.features['label']
46
+ class_to_idx = {n: class_label.str2int(n) for n in class_label.names}
47
+ return class_to_idx
48
+
49
+
50
+ class ParserTfds(Parser):
51
+ """ Wrap Tensorflow Datasets for use in PyTorch
52
+
53
+ There several things to be aware of:
54
+ * To prevent excessive examples being dropped per epoch w/ distributed training or multiplicity of
55
+ dataloader workers, the train iterator wraps to avoid returning partial batches that trigger drop_last
56
+ https://github.com/pytorch/pytorch/issues/33413
57
+ * With PyTorch IterableDatasets, each worker in each replica operates in isolation, the final batch
58
+ from each worker could be a different size. For training this is worked around by option above, for
59
+ validation extra examples are inserted iff distributed mode is enabled so that the batches being reduced
60
+ across replicas are of same size. This will slightly alter the results, distributed validation will not be
61
+ 100% correct. This is similar to common handling in DistributedSampler for normal Datasets but a bit worse
62
+ since there are up to N * J extra examples with IterableDatasets.
63
+ * The sharding (splitting of dataset into TFRecord) files imposes limitations on the number of
64
+ replicas and dataloader workers you can use. For really small datasets that only contain a few shards
65
+ you may have to train non-distributed w/ 1-2 dataloader workers. This is likely not a huge concern as the
66
+ benefit of distributed training or fast dataloading should be much less for small datasets.
67
+ * This wrapper is currently configured to return individual, decompressed image examples from the TFDS
68
+ dataset. The augmentation (transforms) and batching is still done in PyTorch. It would be possible
69
+ to specify TF augmentation fn and return augmented batches w/ some modifications to other downstream
70
+ components.
71
+
72
+ """
73
+
74
+ def __init__(
75
+ self,
76
+ root,
77
+ name,
78
+ split='train',
79
+ is_training=False,
80
+ batch_size=None,
81
+ download=False,
82
+ repeats=0,
83
+ seed=42,
84
+ input_name='image',
85
+ input_image='RGB',
86
+ target_name='label',
87
+ target_image='',
88
+ prefetch_size=None,
89
+ shuffle_size=None,
90
+ max_threadpool_size=None
91
+ ):
92
+ """ Tensorflow-datasets Wrapper
93
+
94
+ Args:
95
+ root: root data dir (ie your TFDS_DATA_DIR. not dataset specific sub-dir)
96
+ name: tfds dataset name (eg `imagenet2012`)
97
+ split: tfds dataset split (can use all TFDS split strings eg `train[:10%]`)
98
+ is_training: training mode, shuffle enabled, dataset len rounded by batch_size
99
+ batch_size: batch_size to use to unsure total examples % batch_size == 0 in training across all dis nodes
100
+ download: download and build TFDS dataset if set, otherwise must use tfds CLI
101
+ repeats: iterate through (repeat) the dataset this many times per iteration (once if 0 or 1)
102
+ seed: common seed for shard shuffle across all distributed/worker instances
103
+ input_name: name of Feature to return as data (input)
104
+ input_image: image mode if input is an image (currently PIL mode string)
105
+ target_name: name of Feature to return as target (label)
106
+ target_image: image mode if target is an image (currently PIL mode string)
107
+ prefetch_size: override default tf.data prefetch buffer size
108
+ shuffle_size: override default tf.data shuffle buffer size
109
+ max_threadpool_size: override default threadpool size for tf.data
110
+ """
111
+ super().__init__()
112
+ self.root = root
113
+ self.split = split
114
+ self.is_training = is_training
115
+ if self.is_training:
116
+ assert batch_size is not None, \
117
+ "Must specify batch_size in training mode for reasonable behaviour w/ TFDS wrapper"
118
+ self.batch_size = batch_size
119
+ self.repeats = repeats
120
+ self.common_seed = seed # a seed that's fixed across all worker / distributed instances
121
+
122
+ # performance settings
123
+ self.prefetch_size = prefetch_size or PREFETCH_SIZE
124
+ self.shuffle_size = shuffle_size or SHUFFLE_SIZE
125
+ self.max_threadpool_size = max_threadpool_size or MAX_TP_SIZE
126
+
127
+ # TFDS builder and split information
128
+ self.input_name = input_name # FIXME support tuples / lists of inputs and targets and full range of Feature
129
+ self.input_image = input_image
130
+ self.target_name = target_name
131
+ self.target_image = target_image
132
+ self.builder = tfds.builder(name, data_dir=root)
133
+ # NOTE: the tfds command line app can be used download & prepare datasets if you don't enable download flag
134
+ if download:
135
+ self.builder.download_and_prepare()
136
+ self.class_to_idx = get_class_labels(self.builder.info) if self.target_name == 'label' else {}
137
+ self.split_info = self.builder.info.splits[split]
138
+ self.num_examples = self.split_info.num_examples
139
+
140
+ # Distributed world state
141
+ self.dist_rank = 0
142
+ self.dist_num_replicas = 1
143
+ if dist.is_available() and dist.is_initialized() and dist.get_world_size() > 1:
144
+ self.dist_rank = dist.get_rank()
145
+ self.dist_num_replicas = dist.get_world_size()
146
+
147
+ # Attributes that are updated in _lazy_init, including the tf.data pipeline itself
148
+ self.global_num_workers = 1
149
+ self.worker_info = None
150
+ self.worker_seed = 0 # seed unique to each work instance
151
+ self.subsplit = None # set when data is distributed across workers using sub-splits
152
+ self.ds = None # initialized lazily on each dataloader worker process
153
+
154
+ def _lazy_init(self):
155
+ """ Lazily initialize the dataset.
156
+
157
+ This is necessary to init the Tensorflow dataset pipeline in the (dataloader) process that
158
+ will be using the dataset instance. The __init__ method is called on the main process,
159
+ this will be called in a dataloader worker process.
160
+
161
+ NOTE: There will be problems if you try to re-use this dataset across different loader/worker
162
+ instances once it has been initialized. Do not call any dataset methods that can call _lazy_init
163
+ before it is passed to dataloader.
164
+ """
165
+ worker_info = torch.utils.data.get_worker_info()
166
+
167
+ # setup input context to split dataset across distributed processes
168
+ num_workers = 1
169
+ global_worker_id = 0
170
+ if worker_info is not None:
171
+ self.worker_info = worker_info
172
+ self.worker_seed = worker_info.seed
173
+ num_workers = worker_info.num_workers
174
+ self.global_num_workers = self.dist_num_replicas * num_workers
175
+ global_worker_id = self.dist_rank * num_workers + worker_info.id
176
+
177
+ """ Data sharding
178
+ InputContext will assign subset of underlying TFRecord files to each 'pipeline' if used.
179
+ My understanding is that using split, the underling TFRecord files will shuffle (shuffle_files=True)
180
+ between the splits each iteration, but that understanding could be wrong.
181
+
182
+ I am currently using a mix of InputContext shard assignment and fine-grained sub-splits for distributing
183
+ the data across workers. For training InputContext is used to assign shards to nodes unless num_shards
184
+ in dataset < total number of workers. Otherwise sub-split API is used for datasets without enough shards or
185
+ for validation where we can't drop examples and need to avoid minimize uneven splits to avoid padding.
186
+ """
187
+ should_subsplit = self.global_num_workers > 1 and (
188
+ self.split_info.num_shards < self.global_num_workers or not self.is_training)
189
+ if should_subsplit:
190
+ # split the dataset w/o using sharding for more even examples / worker, can result in less optimal
191
+ # read patterns for distributed training (overlap across shards) so better to use InputContext there
192
+ if has_buggy_even_splits:
193
+ # my even_split workaround doesn't work on subsplits, upgrade tfds!
194
+ if not isinstance(self.split_info, tfds.core.splits.SubSplitInfo):
195
+ subsplits = even_split_indices(self.split, self.global_num_workers, self.num_examples)
196
+ self.subsplit = subsplits[global_worker_id]
197
+ else:
198
+ subsplits = tfds.even_splits(self.split, self.global_num_workers)
199
+ self.subsplit = subsplits[global_worker_id]
200
+
201
+ input_context = None
202
+ if self.global_num_workers > 1 and self.subsplit is None:
203
+ # set input context to divide shards among distributed replicas
204
+ input_context = tf.distribute.InputContext(
205
+ num_input_pipelines=self.global_num_workers,
206
+ input_pipeline_id=global_worker_id,
207
+ num_replicas_in_sync=self.dist_num_replicas # FIXME does this arg have any impact?
208
+ )
209
+ read_config = tfds.ReadConfig(
210
+ shuffle_seed=self.common_seed,
211
+ shuffle_reshuffle_each_iteration=True,
212
+ input_context=input_context)
213
+ ds = self.builder.as_dataset(
214
+ split=self.subsplit or self.split, shuffle_files=self.is_training, read_config=read_config)
215
+ # avoid overloading threading w/ combo of TF ds threads + PyTorch workers
216
+ options = tf.data.Options()
217
+ thread_member = 'threading' if hasattr(options, 'threading') else 'experimental_threading'
218
+ getattr(options, thread_member).private_threadpool_size = max(1, self.max_threadpool_size // num_workers)
219
+ getattr(options, thread_member).max_intra_op_parallelism = 1
220
+ ds = ds.with_options(options)
221
+ if self.is_training or self.repeats > 1:
222
+ # to prevent excessive drop_last batch behaviour w/ IterableDatasets
223
+ # see warnings at https://pytorch.org/docs/stable/data.html#multi-process-data-loading
224
+ ds = ds.repeat() # allow wrap around and break iteration manually
225
+ if self.is_training:
226
+ ds = ds.shuffle(min(self.num_examples, self.shuffle_size) // self.global_num_workers, seed=self.worker_seed)
227
+ ds = ds.prefetch(min(self.num_examples // self.global_num_workers, self.prefetch_size))
228
+ self.ds = tfds.as_numpy(ds)
229
+
230
+ def __iter__(self):
231
+ if self.ds is None:
232
+ self._lazy_init()
233
+
234
+ # Compute a rounded up sample count that is used to:
235
+ # 1. make batches even cross workers & replicas in distributed validation.
236
+ # This adds extra examples and will slightly alter validation results.
237
+ # 2. determine loop ending condition in training w/ repeat enabled so that only full batch_size
238
+ # batches are produced (underlying tfds iter wraps around)
239
+ target_example_count = math.ceil(max(1, self.repeats) * self.num_examples / self.global_num_workers)
240
+ if self.is_training:
241
+ # round up to nearest batch_size per worker-replica
242
+ target_example_count = math.ceil(target_example_count / self.batch_size) * self.batch_size
243
+
244
+ # Iterate until exhausted or sample count hits target when training (ds.repeat enabled)
245
+ example_count = 0
246
+ for example in self.ds:
247
+ input_data = example[self.input_name]
248
+ if self.input_image:
249
+ input_data = Image.fromarray(input_data, mode=self.input_image)
250
+ target_data = example[self.target_name]
251
+ if self.target_image:
252
+ target_data = Image.fromarray(target_data, mode=self.target_image)
253
+ yield input_data, target_data
254
+ example_count += 1
255
+ if self.is_training and example_count >= target_example_count:
256
+ # Need to break out of loop when repeat() is enabled for training w/ oversampling
257
+ # this results in extra examples per epoch but seems more desirable than dropping
258
+ # up to N*J batches per epoch (where N = num distributed processes, and J = num worker processes)
259
+ break
260
+
261
+ # Pad across distributed nodes (make counts equal by adding examples)
262
+ if not self.is_training and self.dist_num_replicas > 1 and self.subsplit is not None and \
263
+ 0 < example_count < target_example_count:
264
+ # Validation batch padding only done for distributed training where results are reduced across nodes.
265
+ # For single process case, it won't matter if workers return different batch sizes.
266
+ # If using input_context or % based splits, sample count can vary significantly across workers and this
267
+ # approach should not be used (hence disabled if self.subsplit isn't set).
268
+ while example_count < target_example_count:
269
+ yield input_data, target_data # yield prev sample again
270
+ example_count += 1
271
+
272
+ def __len__(self):
273
+ # this is just an estimate and does not factor in extra examples added to pad batches based on
274
+ # complete worker & replica info (not available until init in dataloader).
275
+ return math.ceil(max(1, self.repeats) * self.num_examples / self.dist_num_replicas)
276
+
277
+ def _filename(self, index, basename=False, absolute=False):
278
+ assert False, "Not supported" # no random access to examples
279
+
280
+ def filenames(self, basename=False, absolute=False):
281
+ """ Return all filenames in dataset, overrides base"""
282
+ if self.ds is None:
283
+ self._lazy_init()
284
+ names = []
285
+ for sample in self.ds:
286
+ if len(names) > self.num_examples:
287
+ break # safety for ds.repeat() case
288
+ if 'file_name' in sample:
289
+ name = sample['file_name']
290
+ elif 'filename' in sample:
291
+ name = sample['filename']
292
+ elif 'id' in sample:
293
+ name = sample['id']
294
+ else:
295
+ assert False, "No supported name field present"
296
+ names.append(name)
297
+ return names
@@ -0,0 +1 @@
1
+ from .data import *
@@ -0,0 +1,62 @@
1
+ import numpy as np
2
+ import torch
3
+ from ..dataset_base import DatasetBase
4
+ from ..graph_dataset import GraphDataset
5
+ from ..graph_dataset import SVDEncodingsGraphDataset
6
+ from ..graph_dataset import StructuralDataset
7
+
8
+ class PCQM4MDataset(DatasetBase):
9
+ def __init__(self,
10
+ dataset_path ,
11
+ dataset_name = 'PCQM4M',
12
+ **kwargs
13
+ ):
14
+ super().__init__(dataset_name = dataset_name,
15
+ **kwargs)
16
+ self.dataset_path = dataset_path
17
+
18
+ @property
19
+ def dataset(self):
20
+ try:
21
+ return self._dataset
22
+ except AttributeError:
23
+ from ogb.lsc import PCQM4MDataset
24
+ from ogb.utils import smiles2graph
25
+ self._smiles2graph = smiles2graph
26
+ self._dataset = PCQM4MDataset(root = self.dataset_path, only_smiles=True)
27
+ return self._dataset
28
+
29
+ @property
30
+ def record_tokens(self):
31
+ try:
32
+ return self._record_tokens
33
+ except AttributeError:
34
+ split = {'training':'train',
35
+ 'validation':'valid',
36
+ 'test':'test'}[self.split]
37
+ self._record_tokens = self.dataset.get_idx_split()[split]
38
+ return self._record_tokens
39
+
40
+ def read_record(self, token):
41
+ smiles, target = self.dataset[token]
42
+ graph = self._smiles2graph(smiles)
43
+ graph['num_nodes'] = np.array(graph['num_nodes'], dtype=np.int16)
44
+ graph['edges'] = graph.pop('edge_index').T.astype(np.int16)
45
+ graph['edge_features'] = graph.pop('edge_feat').astype(np.int16)
46
+ graph['node_features'] = graph.pop('node_feat').astype(np.int16)
47
+ graph['target'] = np.array(target, np.float32)
48
+ return graph
49
+
50
+
51
+
52
+ class PCQM4MGraphDataset(GraphDataset,PCQM4MDataset):
53
+ pass
54
+
55
+ class PCQM4MSVDGraphDataset(SVDEncodingsGraphDataset,PCQM4MDataset):
56
+ pass
57
+
58
+ class PCQM4MStructuralGraphDataset(StructuralDataset,PCQM4MGraphDataset):
59
+ pass
60
+
61
+ class PCQM4MStructuralSVDGraphDataset(StructuralDataset,PCQM4MSVDGraphDataset):
62
+ pass
@@ -0,0 +1 @@
1
+ from .data import *
@@ -0,0 +1,87 @@
1
+ """
2
+ https://github.com/shamim-hussain/egt_pytorch
3
+ """
4
+
5
+ import numpy as np
6
+ from ..dataset_base import DatasetBase
7
+ from ..graph_dataset import GraphDataset
8
+ from ..graph_dataset import SVDEncodingsGraphDataset
9
+ from ..graph_dataset import StructuralDataset
10
+ from ..build import DATASETS
11
+
12
+
13
+ @DATASETS.register_module()
14
+ class PCQM4Mv2Dataset(DatasetBase):
15
+ def __init__(self,
16
+ dataset_path,
17
+ dataset_name='PCQM4MV2',
18
+ **kwargs
19
+ ):
20
+ super().__init__(dataset_name=dataset_name,
21
+ **kwargs)
22
+ self.dataset_path = dataset_path
23
+
24
+ @property
25
+ def dataset(self):
26
+ try:
27
+ return self._dataset
28
+ except AttributeError:
29
+ from ogb.lsc import PCQM4Mv2Dataset
30
+ # smiles: simplified molecular-input line-entry system (SMILES). sequence representation of molecules
31
+ # The molecules are provided as SMILES strings (sequence representation of molecules)
32
+ # i = 1234
33
+ # print(dataset[i]) # ('CC(NCC[C@H]([C@@H]1CCC(=CC1)C)C)C', 6.811009678015001)
34
+
35
+ # The second option provides a molecular graph object constructed from the SMILES string.
36
+ # After preprocessing, the file size will be around 8GB.
37
+ # # get i-th molecule and its target value (nan for test data)
38
+ # i = 1234
39
+ # print(dataset[i]) # (graph_obj, 6.811009678015001)
40
+
41
+ # details: https://ogb.stanford.edu/docs/lsc/pcqm4mv2/
42
+ from ogb.utils import smiles2graph
43
+ self._smiles2graph = smiles2graph
44
+ self._dataset = PCQM4Mv2Dataset(root=self.dataset_path, only_smiles=True)
45
+ return self._dataset
46
+
47
+ @property
48
+ def record_tokens(self):
49
+ try:
50
+ return self._record_tokens
51
+ except AttributeError:
52
+ split = {'training': 'train',
53
+ 'validation': 'valid',
54
+ 'test': 'test-dev',
55
+ 'challenge': 'test-challenge'}[self.split]
56
+ self._record_tokens = self.dataset.get_idx_split()[split]
57
+ return self._record_tokens
58
+
59
+ def read_record(self, token):
60
+ smiles, target = self.dataset[token]
61
+ graph = self._smiles2graph(smiles)
62
+ graph['num_nodes'] = np.array(graph['num_nodes'], dtype=np.int16)
63
+ graph['edges'] = graph.pop('edge_index').T.astype(np.int16)
64
+ graph['edge_features'] = graph.pop('edge_feat').astype(np.int16)
65
+ graph['node_features'] = graph.pop('node_feat').astype(np.int16)
66
+ graph['target'] = np.array(target, np.float32)
67
+ return graph
68
+
69
+
70
+ @DATASETS.register_module()
71
+ class PCQM4Mv2GraphDataset(GraphDataset, PCQM4Mv2Dataset):
72
+ pass
73
+
74
+
75
+ @DATASETS.register_module()
76
+ class PCQM4Mv2SVDGraphDataset(SVDEncodingsGraphDataset, PCQM4Mv2Dataset):
77
+ pass
78
+
79
+
80
+ @DATASETS.register_module()
81
+ class PCQM4Mv2StructuralGraphDataset(StructuralDataset, PCQM4Mv2GraphDataset):
82
+ pass
83
+
84
+
85
+ @DATASETS.register_module()
86
+ class PCQM4Mv2StructuralSVDGraphDataset(StructuralDataset, PCQM4Mv2SVDGraphDataset):
87
+ pass
@@ -0,0 +1,2 @@
1
+ from .s3dis_sphere import S3DISSphere
2
+ from .s3dis import S3DIS
@@ -0,0 +1,156 @@
1
+ import os
2
+ import pickle
3
+ import logging
4
+ import numpy as np
5
+ from tqdm import tqdm
6
+ import torch
7
+ from torch.utils.data import Dataset
8
+ from ..data_util import crop_pc, voxelize
9
+ from ..build import DATASETS
10
+
11
+
12
+ @DATASETS.register_module()
13
+ class S3DIS(Dataset):
14
+ classes = ['ceiling',
15
+ 'floor',
16
+ 'wall',
17
+ 'beam',
18
+ 'column',
19
+ 'window',
20
+ 'door',
21
+ 'chair',
22
+ 'table',
23
+ 'bookcase',
24
+ 'sofa',
25
+ 'board',
26
+ 'clutter']
27
+ num_classes = 13
28
+ num_per_class = np.array([3370714, 2856755, 4919229, 318158, 375640, 478001, 974733,
29
+ 650464, 791496, 88727, 1284130, 229758, 2272837], dtype=np.int32)
30
+ class2color = {'ceiling': [0, 255, 0],
31
+ 'floor': [0, 0, 255],
32
+ 'wall': [0, 255, 255],
33
+ 'beam': [255, 255, 0],
34
+ 'column': [255, 0, 255],
35
+ 'window': [100, 100, 255],
36
+ 'door': [200, 200, 100],
37
+ 'table': [170, 120, 200],
38
+ 'chair': [255, 0, 0],
39
+ 'sofa': [200, 100, 100],
40
+ 'bookcase': [10, 200, 100],
41
+ 'board': [200, 200, 200],
42
+ 'clutter': [50, 50, 50]}
43
+ cmap = [*class2color.values()]
44
+ gravity_dim = 2
45
+ """S3DIS dataset, loading the subsampled entire room as input without block/sphere subsampling.
46
+ number of points per room in average, median, and std: (794855.5, 1005913.0147058824, 939501.4733064277)
47
+ Args:
48
+ data_root (str, optional): Defaults to 'data/S3DIS/s3disfull'.
49
+ test_area (int, optional): Defaults to 5.
50
+ voxel_size (float, optional): the voxel size for donwampling. Defaults to 0.04.
51
+ voxel_max (_type_, optional): subsample the max number of point per point cloud. Set None to use all points. Defaults to None.
52
+ split (str, optional): Defaults to 'train'.
53
+ transform (_type_, optional): Defaults to None.
54
+ loop (int, optional): split loops for each epoch. Defaults to 1.
55
+ presample (bool, optional): wheter to downsample each point cloud before training. Set to False to downsample on-the-fly. Defaults to False.
56
+ variable (bool, optional): where to use the original number of points. The number of point per point cloud is variable. Defaults to False.
57
+ """
58
+ def __init__(self,
59
+ data_root: str = 'data/S3DIS/s3disfull',
60
+ test_area: int = 5,
61
+ voxel_size: float = 0.04,
62
+ voxel_max=None,
63
+ split: str = 'train',
64
+ transform=None,
65
+ loop: int = 1,
66
+ presample: bool = False,
67
+ variable: bool = False,
68
+ shuffle: bool = True,
69
+ ):
70
+
71
+ super().__init__()
72
+ self.split, self.voxel_size, self.transform, self.voxel_max, self.loop = \
73
+ split, voxel_size, transform, voxel_max, loop
74
+ self.presample = presample
75
+ self.variable = variable
76
+ self.shuffle = shuffle
77
+
78
+ raw_root = os.path.join(data_root, 'raw')
79
+ self.raw_root = raw_root
80
+ data_list = sorted(os.listdir(raw_root))
81
+ data_list = [item[:-4] for item in data_list if 'Area_' in item]
82
+ if split == 'train':
83
+ self.data_list = [
84
+ item for item in data_list if not 'Area_{}'.format(test_area) in item]
85
+ else:
86
+ self.data_list = [
87
+ item for item in data_list if 'Area_{}'.format(test_area) in item]
88
+
89
+ processed_root = os.path.join(data_root, 'processed')
90
+ filename = os.path.join(
91
+ processed_root, f's3dis_{split}_area{test_area}_{voxel_size:.3f}_{str(voxel_max)}.pkl')
92
+ if presample and not os.path.exists(filename):
93
+ np.random.seed(0)
94
+ self.data = []
95
+ for item in tqdm(self.data_list, desc=f'Loading S3DISFull {split} split on Test Area {test_area}'):
96
+ data_path = os.path.join(raw_root, item + '.npy')
97
+ cdata = np.load(data_path).astype(np.float32)
98
+ cdata[:, :3] -= np.min(cdata[:, :3], 0)
99
+ if voxel_size:
100
+ coord, feat, label = cdata[:,0:3], cdata[:, 3:6], cdata[:, 6:7]
101
+ uniq_idx = voxelize(coord, voxel_size)
102
+ coord, feat, label = coord[uniq_idx], feat[uniq_idx], label[uniq_idx]
103
+ cdata = np.hstack((coord, feat, label))
104
+ self.data.append(cdata)
105
+ npoints = np.array([len(data) for data in self.data])
106
+ logging.info('split: %s, median npoints %.1f, avg num points %.1f, std %.1f' % (
107
+ self.split, np.median(npoints), np.average(npoints), np.std(npoints)))
108
+ os.makedirs(processed_root, exist_ok=True)
109
+ with open(filename, 'wb') as f:
110
+ pickle.dump(self.data, f)
111
+ print(f"{filename} saved successfully")
112
+ elif presample:
113
+ with open(filename, 'rb') as f:
114
+ self.data = pickle.load(f)
115
+ print(f"{filename} load successfully")
116
+ self.data_idx = np.arange(len(self.data_list))
117
+ assert len(self.data_idx) > 0
118
+ logging.info(f"\nTotally {len(self.data_idx)} samples in {split} set")
119
+
120
+ def __getitem__(self, idx):
121
+ data_idx = self.data_idx[idx % len(self.data_idx)]
122
+ if self.presample:
123
+ coord, feat, label = np.split(self.data[data_idx], [3, 6], axis=1)
124
+ else:
125
+ data_path = os.path.join(
126
+ self.raw_root, self.data_list[data_idx] + '.npy')
127
+ cdata = np.load(data_path).astype(np.float32)
128
+ cdata[:, :3] -= np.min(cdata[:, :3], 0)
129
+ coord, feat, label = cdata[:, :3], cdata[:, 3:6], cdata[:, 6:7]
130
+ coord, feat, label = crop_pc(
131
+ coord, feat, label, self.split, self.voxel_size, self.voxel_max,
132
+ downsample=not self.presample, variable=self.variable, shuffle=self.shuffle)
133
+ # TODO: do we need to -np.min in cropped data?
134
+ label = label.squeeze(-1).astype(np.long)
135
+ data = {'pos': coord, 'x': feat, 'y': label}
136
+ # pre-process.
137
+ if self.transform is not None:
138
+ data = self.transform(data)
139
+
140
+ if 'heights' not in data.keys():
141
+ data['heights'] = torch.from_numpy(coord[:, self.gravity_dim:self.gravity_dim+1].astype(np.float32))
142
+ return data
143
+
144
+ def __len__(self):
145
+ return len(self.data_idx) * self.loop
146
+ # return 1 # debug
147
+
148
+
149
+ """debug
150
+ from openpoints.dataset import vis_multi_points
151
+ import copy
152
+ old_data = copy.deepcopy(data)
153
+ if self.transform is not None:
154
+ data = self.transform(data)
155
+ vis_multi_points([old_data['pos'][:, :3], data['pos'][:, :3].numpy()], colors=[old_data['x'][:, :3]/255.,data['x'][:, :3].numpy()])
156
+ """