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,192 @@
1
+ from curses import keyname
2
+ import numpy as np
3
+ import torch
4
+ import os
5
+ import os.path as osp
6
+ import ssl
7
+ import sys
8
+ import urllib
9
+ import h5py
10
+ from typing import Optional
11
+
12
+
13
+ class IO:
14
+ @classmethod
15
+ def get(cls, file_path):
16
+ _, file_extension = os.path.splitext(file_path)
17
+
18
+ if file_extension in ['.npy']:
19
+ return cls._read_npy(file_path)
20
+ elif file_extension in ['.pcd']:
21
+ return cls._read_pcd(file_path)
22
+ elif file_extension in ['.h5']:
23
+ return cls._read_h5(file_path)
24
+ elif file_extension in ['.txt']:
25
+ return cls._read_txt(file_path)
26
+ else:
27
+ raise Exception('Unsupported file extension: %s' % file_extension)
28
+
29
+ # References: https://github.com/numpy/numpy/blob/master/numpy/lib/format.py
30
+ @classmethod
31
+ def _read_npy(cls, file_path):
32
+ return np.load(file_path)
33
+ # # References: https://github.com/dimatura/pypcd/blob/master/pypcd/pypcd.py#L275
34
+ # # Support PCD files without compression ONLY!
35
+ # @classmethod
36
+ # def _read_pcd(cls, file_path):
37
+ # pc = open3d.io.read_point_cloud(file_path)
38
+ # ptcloud = np.array(pc.points)
39
+ # return ptcloud
40
+
41
+ @classmethod
42
+ def _read_txt(cls, file_path):
43
+ return np.loadtxt(file_path)
44
+
45
+ @classmethod
46
+ def _read_h5(cls, file_path):
47
+ f = h5py.File(file_path, 'r')
48
+ return f['data'][()]
49
+
50
+
51
+ # download
52
+ def download_url(url: str, folder: str, log: bool = True,
53
+ filename: Optional[str] = None):
54
+ r"""Downloads the content of an URL to a specific folder.
55
+ Borrowed from https://github.com/pyg-team/pytorch_geometric/blob/master/torch_geometric/data/download.py
56
+ Args:
57
+ url (string): The url.
58
+ folder (string): The folder.
59
+ log (bool, optional): If :obj:`False`, will not print anything to the
60
+ console. (default: :obj:`True`)
61
+ """
62
+
63
+ if filename is None:
64
+ filename = url.rpartition('/')[2]
65
+ filename = filename if filename[0] == '?' else filename.split('?')[0]
66
+
67
+ path = osp.join(folder, filename)
68
+
69
+ if osp.exists(path): # pragma: no cover
70
+ if log:
71
+ print(f'Using existing file {filename}', file=sys.stderr)
72
+ return path
73
+
74
+ if log:
75
+ print(f'Downloading {url}', file=sys.stderr)
76
+
77
+ os.makedirs(folder, exist_ok=True)
78
+ context = ssl._create_unverified_context()
79
+ data = urllib.request.urlopen(url, context=context)
80
+
81
+ with open(path, 'wb') as f:
82
+ # workaround for https://bugs.python.org/issue42853
83
+ while True:
84
+ chunk = data.read(10 * 1024 * 1024)
85
+ if not chunk:
86
+ break
87
+ f.write(chunk)
88
+
89
+ return path
90
+
91
+
92
+ def fnv_hash_vec(arr):
93
+ """
94
+ FNV64-1A
95
+ """
96
+ assert arr.ndim == 2
97
+ arr = arr.copy()
98
+ arr -= arr.min(0)
99
+ arr = arr.astype(np.uint64, copy=False)
100
+ hashed_arr = np.uint64(14695981039346656037) * \
101
+ np.ones(arr.shape[0], dtype=np.uint64)
102
+ for j in range(arr.shape[1]):
103
+ hashed_arr *= np.uint64(1099511628211)
104
+ hashed_arr = np.bitwise_xor(hashed_arr, arr[:, j])
105
+ return hashed_arr
106
+
107
+
108
+ def ravel_hash_vec(arr):
109
+ """
110
+ Ravel the coordinates after subtracting the min coordinates.
111
+ """
112
+ assert arr.ndim == 2
113
+ arr = arr.copy()
114
+ arr -= arr.min(0)
115
+ arr = arr.astype(np.uint64, copy=False)
116
+ arr_max = arr.max(0).astype(np.uint64) + 1
117
+
118
+ keys = np.zeros(arr.shape[0], dtype=np.uint64)
119
+ # Fortran style indexing
120
+ for j in range(arr.shape[1] - 1):
121
+ keys += arr[:, j]
122
+ keys *= arr_max[j + 1]
123
+ keys += arr[:, -1]
124
+ return keys
125
+
126
+
127
+ def voxelize(coord, voxel_size=0.05, hash_type='fnv', mode=0):
128
+ discrete_coord = np.floor(coord / np.array(voxel_size))
129
+ if hash_type == 'ravel':
130
+ key = ravel_hash_vec(discrete_coord)
131
+ else:
132
+ key = fnv_hash_vec(discrete_coord)
133
+
134
+ idx_sort = np.argsort(key)
135
+ key_sort = key[idx_sort]
136
+ _, voxel_idx, count = np.unique(key_sort, return_counts=True, return_inverse=True)
137
+ if mode == 0: # train mode
138
+ idx_select = np.cumsum(np.insert(count, 0, 0)[
139
+ 0:-1]) + np.random.randint(0, count.max(), count.size) % count
140
+ idx_unique = idx_sort[idx_select]
141
+ return idx_unique
142
+ else: # val mode
143
+ return idx_sort, voxel_idx, count
144
+
145
+
146
+ def crop_pc(coord, feat, label, split='train',
147
+ voxel_size=0.04, voxel_max=None,
148
+ downsample=True, variable=True, shuffle=True):
149
+ if voxel_size and downsample:
150
+ # Is this shifting a must? I borrow it from Stratified Transformer and Point Transformer.
151
+ coord -= coord.min(0)
152
+ uniq_idx = voxelize(coord, voxel_size)
153
+ coord, feat, label = coord[uniq_idx], feat[uniq_idx] if feat is not None else None, label[uniq_idx] if label is not None else None
154
+ if voxel_max is not None:
155
+ crop_idx = None
156
+ N = len(label) # the number of points
157
+ if N >= voxel_max:
158
+ init_idx = np.random.randint(N) if 'train' in split else N // 2
159
+ crop_idx = np.argsort(
160
+ np.sum(np.square(coord - coord[init_idx]), 1))[:voxel_max]
161
+ elif not variable:
162
+ # fill more points for non-variable case (batched data)
163
+ cur_num_points = N
164
+ query_inds = np.arange(cur_num_points)
165
+ padding_choice = np.random.choice(
166
+ cur_num_points, voxel_max - cur_num_points)
167
+ crop_idx = np.hstack([query_inds, query_inds[padding_choice]])
168
+ crop_idx = np.arange(coord.shape[0]) if crop_idx is None else crop_idx
169
+ if shuffle:
170
+ shuffle_choice = np.random.permutation(np.arange(len(crop_idx)))
171
+ crop_idx = crop_idx[shuffle_choice]
172
+ coord, feat, label = coord[crop_idx], feat[crop_idx] if feat is not None else None, label[crop_idx] if label is not None else None
173
+ coord -= coord.min(0)
174
+ return coord.astype(np.float32), feat.astype(np.float32) if feat is not None else None , label.astype(np.long) if label is not None else None
175
+
176
+
177
+ def get_features_by_keys(data, keys='pos,x'):
178
+ key_list = keys.split(',')
179
+ if len(key_list) == 1:
180
+ return data[keys].transpose(1,2).contiguous()
181
+ else:
182
+ return torch.cat([data[key] for key in keys.split(',')], -1).transpose(1,2).contiguous()
183
+
184
+
185
+ def get_class_weights(num_per_class, normalize=False):
186
+ weight = num_per_class / float(sum(num_per_class))
187
+ ce_label_weight = 1 / (weight + 0.02)
188
+
189
+ if normalize:
190
+ ce_label_weight = (ce_label_weight *
191
+ len(ce_label_weight)) / ce_label_weight.sum()
192
+ return torch.from_numpy(ce_label_weight.astype(np.float32))
@@ -0,0 +1,67 @@
1
+
2
+ import torch
3
+ from torch.utils.data import dataset
4
+ from tqdm import tqdm
5
+ from pathlib import Path
6
+ import numpy as np
7
+
8
+
9
+ class DataList(dataset.Dataset):
10
+ def __init__(self,
11
+ dataset_name,
12
+ split,
13
+ data_list,
14
+ **kwargs):
15
+ super().__init__(**kwargs)
16
+ self.dataset_name = dataset_name
17
+ self.data_list = data_list
18
+ self.split = split
19
+
20
+ def load_data(self, data_path):
21
+ if 's3dis' in self.dataset_name:
22
+ data = np.load(data_path) # xyzrgbl, N*7
23
+ coord, feat, label = data[:, :3], data[:, 3:6], data[:, 6]
24
+ feat = np.clip(feat / 255., 0, 1).astype(np.float32)
25
+ elif 'scannet' in self.dataset_name:
26
+ data = torch.load(data_path) # xyzrgbl, N*7
27
+ if self.split != 'test':
28
+ coord, feat, label = data[0], data[1], data[2]
29
+ else:
30
+ coord, feat, label = data[0], data[1], None
31
+ feat = np.clip((feat + 1) / 2., 0, 1).astype(np.float32)
32
+ elif 'semantickitti' in self.dataset_name:
33
+ points = self.load_pc_kitti(pc_path)
34
+ labels = self.load_label_kitti(label_path, self.remap_lut_read)
35
+
36
+ coord -= coord.min(0)
37
+
38
+ idx_points = []
39
+ voxel_size = cfg.dataset.common.get('voxel_size', None)
40
+ if voxel_size is not None:
41
+ idx_sort, count = voxelize(coord, voxel_size, mode=1)
42
+ for i in range(count.max()):
43
+ idx_select = np.cumsum(np.insert(count, 0, 0)[0:-1]) + i % count
44
+ idx_part = idx_sort[idx_select]
45
+ np.random.shuffle(idx_part)
46
+ idx_points.append(idx_part)
47
+ else:
48
+ idx_points.append(np.arange(label.shape[0]))
49
+ return coord, feat, label, idx_points
50
+
51
+
52
+
53
+ def __len__(self):
54
+ return len(self.record_tokens)
55
+
56
+ def __getitem__(self, index):
57
+ token = self.record_tokens[index]
58
+ try:
59
+ return self._records[token]
60
+ except AttributeError:
61
+ record = self.read_record(token)
62
+ self._records = {token:record}
63
+ return record
64
+ except KeyError:
65
+ record = self.read_record(token)
66
+ self._records[token] = record
67
+ return record
@@ -0,0 +1,96 @@
1
+
2
+ import torch
3
+ from torch.utils.data import dataset
4
+ from tqdm import tqdm
5
+ from pathlib import Path
6
+
7
+
8
+ class DatasetBase(dataset.Dataset):
9
+ def __init__(self,
10
+ dataset_name, split,
11
+ cache_dir = None,
12
+ load_cache_if_exists=True,
13
+ **kwargs):
14
+ super().__init__(**kwargs)
15
+ self.dataset_name = dataset_name
16
+ self.split = split
17
+ self.cache_dir = cache_dir
18
+
19
+ self.is_cached = False
20
+ if load_cache_if_exists:
21
+ self.cache(verbose=0, must_exist=True)
22
+
23
+ @property
24
+ def record_tokens(self):
25
+ raise NotImplementedError
26
+
27
+ def read_record(self, token):
28
+ raise NotImplementedError
29
+
30
+ def __len__(self):
31
+ return len(self.record_tokens)
32
+
33
+ def __getitem__(self, index):
34
+ token = self.record_tokens[index]
35
+ try:
36
+ return self._records[token]
37
+ except AttributeError:
38
+ record = self.read_record(token)
39
+ self._records = {token:record}
40
+ return record
41
+ except KeyError:
42
+ record = self.read_record(token)
43
+ self._records[token] = record
44
+ return record
45
+
46
+ def read_all_records(self, verbose=1):
47
+ self._records = {}
48
+ if verbose:
49
+ print(f'Reading all {self.split} records...', flush=True)
50
+ for token in tqdm(self.record_tokens):
51
+ self._records[token] = self.read_record(token)
52
+ else:
53
+ for token in self.record_tokens:
54
+ self._records[token] = self.read_record(token)
55
+
56
+ def get_cache_path(self, path=None):
57
+ if path is None: path = self.cache_dir
58
+ base_path = (Path(path)/self.dataset_name)/self.split
59
+ base_path.mkdir(parents=True, exist_ok=True)
60
+ return base_path
61
+
62
+ def cache_load_and_save(self, base_path, op, verbose):
63
+ tokens_path = base_path/'tokens.pt'
64
+ records_path = base_path/'records.pt'
65
+
66
+ if op == 'load':
67
+ self._record_tokens = torch.load(str(tokens_path))
68
+ self._records = torch.load(str(records_path))
69
+ elif op == 'save':
70
+ if tokens_path.exists() and records_path.exists() \
71
+ and hasattr(self, '_record_tokens') and hasattr(self, '_records'):
72
+ return
73
+ self.read_all_records(verbose=verbose)
74
+ torch.save(self.record_tokens, str(tokens_path))
75
+ torch.save(self._records, str(records_path))
76
+ else:
77
+ raise ValueError(f'Unknown operation: {op}')
78
+
79
+ def cache(self, path=None, verbose=1, must_exist=False):
80
+ if self.is_cached: return
81
+
82
+ base_path = self.get_cache_path(path)
83
+ try:
84
+ if verbose: print(f'Trying to load {self.split} cache from disk...', flush=True)
85
+ self.cache_load_and_save(base_path, 'load', verbose)
86
+ if verbose: print(f'Loaded {self.split} cache from disk.', flush=True)
87
+ except FileNotFoundError:
88
+ if must_exist: return
89
+
90
+ if verbose: print(f'{self.split} cache does not exist! Cacheing...', flush=True)
91
+ self.cache_load_and_save(base_path, 'save', verbose)
92
+ if verbose: print(f'Saved {self.split} cache to disk.', flush=True)
93
+
94
+ self.is_cached = True
95
+
96
+
@@ -0,0 +1,3 @@
1
+ from .graph_dataset import GraphDataset, graphdata_collate
2
+ from .svd_encodings_dataset import SVDEncodingsGraphDataset
3
+ from .structural_dataset import StructuralDataset
@@ -0,0 +1,93 @@
1
+
2
+ import torch
3
+ import numpy as np
4
+
5
+ from ..dataset_base import DatasetBase
6
+
7
+ from .stack_with_pad import stack_with_pad
8
+ from collections import defaultdict
9
+ from numba.typed import List
10
+
11
+
12
+ class GraphDataset(DatasetBase):
13
+ def __init__(self,
14
+ num_nodes_key = 'num_nodes',
15
+ edges_key = 'edges',
16
+ node_features_key = 'node_features',
17
+ edge_features_key = 'edge_features',
18
+ node_mask_key = 'node_mask',
19
+ targets_key = 'target',
20
+ include_node_mask = True,
21
+ **kwargs):
22
+ super().__init__(**kwargs)
23
+ self.num_nodes_key = num_nodes_key
24
+ self.edges_key = edges_key
25
+ self.node_features_key = node_features_key
26
+ self.edge_features_key = edge_features_key
27
+ self.node_mask_key = node_mask_key
28
+ self.targets_key = targets_key
29
+ self.include_node_mask = include_node_mask
30
+
31
+ def __getitem__(self, index):
32
+ item = super().__getitem__(index)
33
+ if self.include_node_mask:
34
+ item = item.copy()
35
+ item[self.node_mask_key] = np.ones((item[self.num_nodes_key],), dtype=np.uint8)
36
+ return item
37
+
38
+ def _calculate_max_nodes(self):
39
+ self._max_nodes = self[0][self.num_nodes_key]
40
+ self._max_nodes_index = 0
41
+ for i in range(1, super().__len__()):
42
+ graph = super().__getitem__(i)
43
+ cur_nodes = graph[self.num_nodes_key]
44
+ if cur_nodes > self._max_nodes:
45
+ self._max_nodes = cur_nodes
46
+ self._max_nodes_index = i
47
+
48
+ @property
49
+ def max_nodes(self):
50
+ try:
51
+ return self._max_nodes
52
+ except AttributeError:
53
+ self._calculate_max_nodes()
54
+ return self._max_nodes
55
+
56
+ @property
57
+ def max_nodes_index(self):
58
+ try:
59
+ return self._max_nodes_index
60
+ except AttributeError:
61
+ self._calculate_max_nodes()
62
+ return self._max_nodes_index
63
+
64
+ def cache_load_and_save(self, base_path, op, verbose):
65
+ super().cache_load_and_save(base_path, op, verbose)
66
+ max_nodes_path = base_path/'max_nodes_data.pt'
67
+
68
+ if op == 'load':
69
+ max_nodes_data = torch.load(str(max_nodes_path))
70
+ self._max_nodes = max_nodes_data['max_nodes']
71
+ self._max_nodes_index = max_nodes_data['max_nodes_index']
72
+ elif op == 'save':
73
+ if verbose: print(f'Calculating {self.split} max nodes...',flush=True)
74
+ max_nodes_data = {'max_nodes': self.max_nodes,
75
+ 'max_nodes_index': self.max_nodes_index}
76
+ torch.save(max_nodes_data, str(max_nodes_path))
77
+ else:
78
+ raise ValueError(f'Unknown operation: {op}')
79
+
80
+ def max_batch(self, batch_size, collate_fn):
81
+ return collate_fn([self.__getitem__(self.max_nodes_index)] * batch_size)
82
+
83
+
84
+
85
+ def graphdata_collate(batch):
86
+ batch_data = defaultdict(List)
87
+ for elem in batch:
88
+ for k,v in elem.items():
89
+ batch_data[k].append(v)
90
+
91
+ out = {k:torch.from_numpy(stack_with_pad(dat))
92
+ for k, dat in batch_data.items()}
93
+ return out
@@ -0,0 +1,91 @@
1
+ import numpy as np
2
+ import numba as nb
3
+
4
+
5
+ @nb.njit
6
+ def stack_with_pad_4d(inputs):
7
+ num_elem = len(inputs)
8
+ ms_0, ms_1, ms_2, ms_3 = inputs[0].shape
9
+
10
+ for i in range(1,num_elem):
11
+ is_0, is_1, is_2, is_3 = inputs[i].shape
12
+ ms_0 = max(is_0, ms_0)
13
+ ms_1 = max(is_1, ms_1)
14
+ ms_2 = max(is_2, ms_2)
15
+ ms_3 = max(is_3, ms_3)
16
+
17
+ stacked_shape = (num_elem,ms_0,ms_1,ms_2,ms_3)
18
+ stacked = np.zeros(stacked_shape, dtype=inputs[0].dtype)
19
+
20
+ for i, elem in enumerate(inputs):
21
+ stacked[i][:elem.shape[0],:elem.shape[1],:elem.shape[2],:elem.shape[3]] = elem
22
+ return stacked
23
+
24
+ @nb.njit
25
+ def stack_with_pad_3d(inputs):
26
+ num_elem = len(inputs)
27
+ ms_0, ms_1, ms_2 = inputs[0].shape
28
+
29
+ for i in range(1,num_elem):
30
+ is_0, is_1, is_2 = inputs[i].shape
31
+ ms_0 = max(is_0, ms_0)
32
+ ms_1 = max(is_1, ms_1)
33
+ ms_2 = max(is_2, ms_2)
34
+
35
+ stacked_shape = (num_elem,ms_0,ms_1,ms_2)
36
+ stacked = np.zeros(stacked_shape, dtype=inputs[0].dtype)
37
+
38
+ for i, elem in enumerate(inputs):
39
+ stacked[i][:elem.shape[0],:elem.shape[1],:elem.shape[2]] = elem
40
+ return stacked
41
+
42
+ @nb.njit
43
+ def stack_with_pad_2d(inputs):
44
+ num_elem = len(inputs)
45
+ ms_0, ms_1 = inputs[0].shape
46
+
47
+ for i in range(1,num_elem):
48
+ is_0, is_1 = inputs[i].shape
49
+ ms_0 = max(is_0, ms_0)
50
+ ms_1 = max(is_1, ms_1)
51
+
52
+ stacked_shape = (num_elem,ms_0,ms_1)
53
+ stacked = np.zeros(stacked_shape, dtype=inputs[0].dtype)
54
+
55
+ for i, elem in enumerate(inputs):
56
+ stacked[i][:elem.shape[0],:elem.shape[1]] = elem
57
+ return stacked
58
+
59
+ @nb.njit
60
+ def stack_with_pad_1d(inputs):
61
+ num_elem = len(inputs)
62
+ ms_0 = inputs[0].shape[0]
63
+
64
+ for i in range(1,num_elem):
65
+ is_0 = inputs[i].shape[0]
66
+ ms_0 = max(is_0, ms_0)
67
+
68
+ stacked_shape = (num_elem,ms_0)
69
+ stacked = np.zeros(stacked_shape, dtype=inputs[0].dtype)
70
+
71
+ for i, elem in enumerate(inputs):
72
+ stacked[i][:elem.shape[0]] = elem
73
+ return stacked
74
+
75
+
76
+ def stack_with_pad(inputs):
77
+ shape_rank = np.ndim(inputs[0])
78
+ if shape_rank == 0:
79
+ return np.stack(inputs)
80
+ if shape_rank == 1:
81
+ return stack_with_pad_1d(inputs)
82
+ elif shape_rank == 2:
83
+ return stack_with_pad_2d(inputs)
84
+ elif shape_rank == 3:
85
+ return stack_with_pad_3d(inputs)
86
+ elif shape_rank == 4:
87
+ return stack_with_pad_4d(inputs)
88
+ else:
89
+ raise ValueError('Only support up to 4D tensor')
90
+
91
+
@@ -0,0 +1,73 @@
1
+ import numpy as np
2
+ import numba as nb
3
+
4
+ from .graph_dataset import GraphDataset
5
+
6
+ NODE_FEATURES_OFFSET = 128
7
+ EDGE_FEATURES_OFFSET = 8
8
+
9
+ @nb.njit
10
+ def floyd_warshall(A):
11
+ n = A.shape[0]
12
+ D = np.zeros((n,n), dtype=np.int16)
13
+
14
+ for i in range(n):
15
+ for j in range(n):
16
+ if i == j:
17
+ pass
18
+ elif A[i,j] == 0:
19
+ D[i,j] = 510
20
+ else:
21
+ D[i,j] = 1
22
+
23
+ for k in range(n):
24
+ for i in range(n):
25
+ for j in range(n):
26
+ old_dist = D[i,j]
27
+ new_dist = D[i,k] + D[k,j]
28
+ if new_dist < old_dist:
29
+ D[i,j] = new_dist
30
+ return D
31
+
32
+ @nb.njit
33
+ def preprocess_data(num_nodes, edges, node_feats, edge_feats):
34
+ node_feats = node_feats + np.arange(1,node_feats.shape[-1]*NODE_FEATURES_OFFSET+1,
35
+ NODE_FEATURES_OFFSET,dtype=np.int16)
36
+ edge_feats = edge_feats + np.arange(1,edge_feats.shape[-1]*EDGE_FEATURES_OFFSET+1,
37
+ EDGE_FEATURES_OFFSET,dtype=np.int16)
38
+
39
+ A = np.zeros((num_nodes,num_nodes),dtype=np.int16)
40
+ E = np.zeros((num_nodes,num_nodes,edge_feats.shape[-1]),dtype=np.int16)
41
+ for k in range(edges.shape[0]):
42
+ i,j = edges[k,0], edges[k,1]
43
+ A[i,j] = 1
44
+ E[i,j] = edge_feats[k]
45
+
46
+ D = floyd_warshall(A)
47
+ return node_feats, D, E
48
+
49
+
50
+ class StructuralDataset(GraphDataset):
51
+ def __init__(self,
52
+ distance_matrix_key = 'distance_matrix',
53
+ feature_matrix_key = 'feature_matrix',
54
+ **kwargs):
55
+ super().__init__(**kwargs)
56
+ self.distance_matrix_key = distance_matrix_key
57
+ self.feature_matrix_key = feature_matrix_key
58
+
59
+ def __getitem__(self, index):
60
+ item = super().__getitem__(index)
61
+
62
+ num_nodes = int(item[self.num_nodes_key])
63
+ edges = item.pop(self.edges_key)
64
+ node_feats = item.pop(self.node_features_key)
65
+ edge_feats = item.pop(self.edge_features_key)
66
+
67
+ node_feats, dist_mat, edge_feats_mat = preprocess_data(num_nodes, edges, node_feats, edge_feats)
68
+ item[self.node_features_key] = node_feats
69
+ item[self.distance_matrix_key] = dist_mat
70
+ item[self.feature_matrix_key] = edge_feats_mat
71
+
72
+ return item
73
+