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,170 @@
1
+ import functools
2
+ import logging
3
+ import os
4
+ import os.path as osp
5
+ import sys
6
+ from termcolor import colored
7
+
8
+ import time
9
+ import shortuuid
10
+ import pathlib
11
+ import shutil
12
+
13
+
14
+ class _ColorfulFormatter(logging.Formatter):
15
+ def __init__(self, *args, **kwargs):
16
+ self._root_name = kwargs.pop("root_name") + "."
17
+ self._abbrev_name = kwargs.pop("abbrev_name", "")
18
+ if len(self._abbrev_name):
19
+ self._abbrev_name = self._abbrev_name + "."
20
+ super(_ColorfulFormatter, self).__init__(*args, **kwargs)
21
+
22
+ def formatMessage(self, record):
23
+ record.name = record.name.replace(self._root_name, self._abbrev_name)
24
+ log = super(_ColorfulFormatter, self).formatMessage(record)
25
+ if record.levelno == logging.WARNING:
26
+ prefix = colored("WARNING", "red", attrs=["blink"])
27
+ elif record.levelno == logging.ERROR or record.levelno == logging.CRITICAL:
28
+ prefix = colored("ERROR", "red", attrs=["blink", "underline"])
29
+ else:
30
+ return log
31
+ return prefix + " " + log
32
+
33
+
34
+ # so that calling setup_logger multiple times won't add many handlers
35
+ @functools.lru_cache()
36
+ def setup_logger_dist(output=None,
37
+ distributed_rank=0,
38
+ *,
39
+ color=True,
40
+ name="moco",
41
+ abbrev_name=None):
42
+ """
43
+ Initialize the detectron2 logger and set its verbosity level to "INFO".
44
+ Args:
45
+ output (str): a file name or a directory to save log. If None, will not save log file.
46
+ If ends with ".txt" or ".log", assumed to be a file name.
47
+ Otherwise, logs will be saved to `output/log.txt`.
48
+ name (str): the root module name of this logger
49
+ Returns:
50
+ logging.Logger: a logger
51
+ """
52
+ logger = logging.getLogger(name)
53
+ logger.setLevel(logging.DEBUG)
54
+ logger.propagate = False
55
+
56
+ if abbrev_name is None:
57
+ abbrev_name = name
58
+
59
+ plain_formatter = logging.Formatter(
60
+ "[%(asctime)s] %(name)s %(levelname)s: %(message)s",
61
+ datefmt="%m/%d %H:%M:%S")
62
+ # stdout logging: master only
63
+ if distributed_rank == 0:
64
+ ch = logging.StreamHandler(stream=sys.stdout)
65
+ ch.setLevel(logging.DEBUG)
66
+ if color:
67
+ formatter = _ColorfulFormatter(
68
+ colored("[%(asctime)s %(name)s]: ", "green") + "%(message)s",
69
+ datefmt="%m/%d %H:%M:%S",
70
+ root_name=name,
71
+ abbrev_name=str(abbrev_name),
72
+ )
73
+ else:
74
+ formatter = plain_formatter
75
+ ch.setFormatter(formatter)
76
+ logger.addHandler(ch)
77
+
78
+ # file logging: all workers
79
+ if output is not None:
80
+ if output.endswith(".txt") or output.endswith(".log"):
81
+ filename = output
82
+ else:
83
+ filename = os.path.join(output, "log.txt")
84
+ if distributed_rank > 0:
85
+ filename = filename + f".rank{distributed_rank}"
86
+ os.makedirs(os.path.dirname(filename), exist_ok=True)
87
+
88
+ fh = logging.StreamHandler(_cached_log_stream(filename))
89
+ fh.setLevel(logging.DEBUG)
90
+ fh.setFormatter(plain_formatter)
91
+ logger.addHandler(fh)
92
+ logging.root = logger # main logger.
93
+ return logger
94
+
95
+
96
+ # cache the opened file object, so that different calls to `setup_logger`
97
+ # with the same file name can safely write to the same file.
98
+ @functools.lru_cache(maxsize=None)
99
+ def _cached_log_stream(filename):
100
+ return open(filename, "a")
101
+
102
+
103
+ # ================ experiment folder ==================
104
+ def generate_exp_directory(cfg,
105
+ exp_name=None,
106
+ expid=None,
107
+ run_name=None,
108
+ additional_id=None):
109
+ """Function to create checkpoint folder.
110
+ Args:
111
+ cfg: configuration dict
112
+ cfg.root_dir: the root dir for saving log files.
113
+ exp_name: exp_name or tags for saving and generating the exp_name
114
+ expid: id for the current run
115
+ run_name: the name for the current run. auto generated if None
116
+ Returns:
117
+ the exp_name, jobname, and folders into cfg
118
+ """
119
+
120
+ if run_name is None:
121
+ if expid is None:
122
+ expid = time.strftime('%Y%m%d-%H%M%S-') + str(shortuuid.uuid())
123
+ # expid = time.strftime('%Y%m%d-%H%M%S')
124
+ if additional_id is not None:
125
+ expid += '-' + str(additional_id)
126
+ if isinstance(exp_name, list):
127
+ exp_name = '-'.join(exp_name)
128
+ run_name = '-'.join([exp_name, expid])
129
+ cfg.run_name = run_name
130
+ cfg.run_dir = os.path.join(cfg.root_dir, cfg.run_name)
131
+ cfg.exp_dir = cfg.run_dir
132
+ cfg.log_dir = cfg.run_dir
133
+ cfg.ckpt_dir = os.path.join(cfg.run_dir, 'checkpoint')
134
+ cfg.log_path = os.path.join(cfg.run_dir, cfg.run_name + '.log')
135
+
136
+ if cfg.get('rank', 0) == 0:
137
+ pathlib.Path(cfg.ckpt_dir).mkdir(parents=True, exist_ok=True)
138
+
139
+
140
+ def resume_exp_directory(cfg, pretrained_path=None):
141
+ """Function to resume the exp folder from the checkpoint folder.
142
+ Args:
143
+ cfg
144
+ pretrained_path: the path to the pretrained model
145
+ Returns:
146
+ the exp_name, jobname, and folders into cfg
147
+ """
148
+ pretrained_path = pretrained_path or cfg.get('pretrained_path', None) or cfg.get('pretrained_path', None)
149
+ if os.path.basename(os.path.dirname(pretrained_path)) == 'checkpoint':
150
+ cfg.run_dir = os.path.dirname(os.path.dirname(cfg.pretrained_path))
151
+ cfg.log_dir = cfg.run_dir
152
+ cfg.run_name = os.path.basename(cfg.run_dir)
153
+ cfg.ckpt_dir = os.path.join(cfg.run_dir, 'checkpoint')
154
+ cfg.code_dir = os.path.join(cfg.run_dir, 'code')
155
+ # we further config the name by datetime
156
+ cfg.log_path = os.path.join(
157
+ cfg.run_dir, cfg.run_name + time.strftime('%Y%m%d-%H%M%S-') +
158
+ str(shortuuid.uuid()) + '.log')
159
+ else:
160
+ expid = time.strftime('%Y%m%d-%H%M%S-') + str(shortuuid.uuid())
161
+ cfg.run_name = '_'.join([os.path.basename(pretrained_path), expid])
162
+ cfg.run_dir = os.path.join(cfg.root_dir, cfg.run_name)
163
+ cfg.log_dir = cfg.run_dir
164
+ cfg.ckpt_dir = os.path.join(cfg.run_dir, 'checkpoint')
165
+ cfg.code_dir = os.path.join(cfg.run_dir, 'code')
166
+ cfg.log_path = os.path.join(cfg.run_dir, cfg.run_name + '.log')
167
+
168
+ if cfg.get('rank', 0) == 0:
169
+ os.makedirs(cfg.run_dir, exist_ok=True)
170
+ cfg.wandb.tags = ['resume']
@@ -0,0 +1,311 @@
1
+ from math import log10
2
+ import numpy as np
3
+ import torch
4
+ from sklearn.metrics import confusion_matrix
5
+ import logging
6
+
7
+
8
+ def PSNR(mse, peak=1.):
9
+ return 10 * log10((peak ** 2) / mse)
10
+
11
+
12
+ class SegMetric:
13
+ def __init__(self, values=0.):
14
+ assert isinstance(values, dict)
15
+ self.miou = values.miou
16
+ self.oa = values.get('oa', None)
17
+ self.miou = values.miou
18
+ self.miou = values.miou
19
+
20
+
21
+ def better_than(self, other):
22
+ if self.acc > other.acc:
23
+ return True
24
+ else:
25
+ return False
26
+
27
+ def state_dict(self):
28
+ _dict = dict()
29
+ _dict['acc'] = self.acc
30
+ return _dict
31
+
32
+
33
+ class AverageMeter(object):
34
+ """Computes and stores the average and current value"""
35
+ def __init__(self):
36
+ self.reset()
37
+
38
+ def reset(self):
39
+ self.val = 0
40
+ self.avg = 0
41
+ self.sum = 0
42
+ self.count = 0
43
+
44
+ def update(self, val, n=1):
45
+ self.val = val
46
+ self.sum += val * n
47
+ self.count += n
48
+ self.avg = self.sum / self.count
49
+
50
+
51
+ class ConfusionMatrix:
52
+ """Accumulate a confusion matrix for a classification task.
53
+ ignore_index only supports index <0, or > num_classes
54
+ """
55
+
56
+ def __init__(self, num_classes, ignore_index=None):
57
+ self.value = 0
58
+ self.num_classes = num_classes
59
+ self.virtual_num_classes = num_classes + 1 if ignore_index is not None else num_classes
60
+ self.ignore_index = ignore_index
61
+
62
+ @torch.no_grad()
63
+ def update(self, pred, true):
64
+ """Update the confusion matrix with the given predictions."""
65
+ true = true.flatten()
66
+ pred = pred.flatten()
67
+ if self.ignore_index is not None:
68
+ if (true == self.ignore_index).sum() > 0:
69
+ pred[true == self.ignore_index] = self.virtual_num_classes -1
70
+ true[true == self.ignore_index] = self.virtual_num_classes -1
71
+ unique_mapping = true.flatten() * self.virtual_num_classes + pred.flatten()
72
+ bins = torch.bincount(unique_mapping, minlength=self.virtual_num_classes**2)
73
+ self.value += bins.view(self.virtual_num_classes, self.virtual_num_classes)[:self.num_classes, :self.num_classes]
74
+
75
+ def reset(self):
76
+ """Reset all accumulated values."""
77
+ self.value = 0
78
+
79
+ @property
80
+ def tp(self):
81
+ """Get the true positive samples per-class."""
82
+ return self.value.diag()
83
+
84
+ @property
85
+ def actual(self):
86
+ """Get the false negative samples per-class."""
87
+ return self.value.sum(dim=1)
88
+
89
+ @property
90
+ def predicted(self):
91
+ """Get the false negative samples per-class."""
92
+ return self.value.sum(dim=0)
93
+
94
+ @property
95
+ def fn(self):
96
+ """Get the false negative samples per-class."""
97
+ return self.actual - self.tp
98
+
99
+ @property
100
+ def fp(self):
101
+ """Get the false positive samples per-class."""
102
+ return self.predicted - self.tp
103
+
104
+ @property
105
+ def tn(self):
106
+ """Get the true negative samples per-class."""
107
+ actual = self.actual
108
+ predicted = self.predicted
109
+ return actual.sum() + self.tp - (actual + predicted)
110
+
111
+ @property
112
+ def count(self): # a.k.a. actual positive class
113
+ """Get the number of samples per-class."""
114
+ # return self.tp + self.fn
115
+ return self.value.sum(dim=1)
116
+
117
+ @property
118
+ def frequency(self):
119
+ """Get the per-class frequency."""
120
+ # we avoid dividing by zero using: max(denomenator, 1)
121
+ # return self.count / self.total.clamp(min=1)
122
+ count = self.value.sum(dim=1)
123
+ return count / count.sum().clamp(min=1)
124
+
125
+ @property
126
+ def total(self):
127
+ """Get the total number of samples."""
128
+ return self.value.sum()
129
+
130
+ @property
131
+ def overall_accuray(self):
132
+ return self.tp.sum() / self.total
133
+
134
+ @property
135
+ def union(self):
136
+ return self.value.sum(dim=0) + self.value.sum(dim=1) - self.value.diag()
137
+
138
+ def all_acc(self):
139
+ return self.cal_acc(self.tp, self.count)
140
+
141
+ @staticmethod
142
+ def cal_acc(tp, count):
143
+ acc_per_cls = tp / count.clamp(min=1) * 100
144
+ over_all_acc = tp.sum() / count.sum() * 100
145
+ macc = torch.mean(acc_per_cls) # class accuracy
146
+ return macc.item(), over_all_acc.item(), acc_per_cls.cpu().numpy()
147
+
148
+ @staticmethod
149
+ def print_acc(accs):
150
+ out = '\n Class ' + ' Acc '
151
+ for i, values in enumerate(accs):
152
+ out += '\n' + str(i).rjust(8) + f'{values.item():.2f}'.rjust(8)
153
+ out += '\n' + '-' * 20
154
+ out += '\n' + ' Mean ' + f'{torch.mean(accs).item():.2f}'.rjust(8)
155
+ logging.info(out)
156
+
157
+ def all_metrics(self):
158
+ tp, fp, fn = self.tp, self.fp, self.fn,
159
+
160
+ iou_per_cls = tp / (tp + fp + fn).clamp(min=1) * 100
161
+ acc_per_cls = tp / self.count.clamp(min=1) * 100
162
+ over_all_acc = tp.sum() / self.total * 100
163
+
164
+ miou = torch.mean(iou_per_cls)
165
+ macc = torch.mean(acc_per_cls) # class accuracy
166
+ return miou.item(), macc.item(), over_all_acc.item(), iou_per_cls.cpu().numpy(), acc_per_cls.cpu().numpy()
167
+
168
+
169
+ def get_mious(tp, union, count):
170
+ iou_per_cls = (tp + 1e-10) / (union + 1e-10) * 100
171
+ acc_per_cls = (tp + 1e-10) / (count + 1e-10) * 100
172
+ over_all_acc = tp.sum() / count.sum() * 100
173
+
174
+ miou = torch.mean(iou_per_cls)
175
+ macc = torch.mean(acc_per_cls) # class accuracy
176
+ return miou.item(), macc.item(), over_all_acc.item(), iou_per_cls.cpu().numpy(), acc_per_cls.cpu().numpy()
177
+
178
+
179
+ def partnet_metrics(num_classes, num_parts, objects, preds, targets):
180
+ """
181
+
182
+ Args:
183
+ num_classes:
184
+ num_parts:
185
+ objects: [int]
186
+ preds:[(num_parts,num_points)]
187
+ targets: [(num_points)]
188
+
189
+ Returns:
190
+
191
+ """
192
+ shape_iou_tot = [0.0] * num_classes
193
+ shape_iou_cnt = [0] * num_classes
194
+ part_intersect = [np.zeros((num_parts[o_l]), dtype=np.float32) for o_l in range(num_classes)]
195
+ part_union = [np.zeros((num_parts[o_l]), dtype=np.float32) + 1e-6 for o_l in range(num_classes)]
196
+
197
+ for obj, cur_pred, cur_gt in zip(objects, preds, targets):
198
+ cur_num_parts = num_parts[obj]
199
+ cur_pred = np.argmax(cur_pred[1:, :], axis=0) + 1
200
+ cur_pred[cur_gt == 0] = 0
201
+ cur_shape_iou_tot = 0.0
202
+ cur_shape_iou_cnt = 0
203
+ for j in range(1, cur_num_parts):
204
+ cur_gt_mask = (cur_gt == j)
205
+ cur_pred_mask = (cur_pred == j)
206
+
207
+ has_gt = (np.sum(cur_gt_mask) > 0)
208
+ has_pred = (np.sum(cur_pred_mask) > 0)
209
+
210
+ if has_gt or has_pred:
211
+ intersect = np.sum(cur_gt_mask & cur_pred_mask)
212
+ union = np.sum(cur_gt_mask | cur_pred_mask)
213
+ iou = intersect / union
214
+
215
+ cur_shape_iou_tot += iou
216
+ cur_shape_iou_cnt += 1
217
+
218
+ part_intersect[obj][j] += intersect
219
+ part_union[obj][j] += union
220
+ if cur_shape_iou_cnt > 0:
221
+ cur_shape_miou = cur_shape_iou_tot / cur_shape_iou_cnt
222
+ shape_iou_tot[obj] += cur_shape_miou
223
+ shape_iou_cnt[obj] += 1
224
+
225
+ msIoU = [shape_iou_tot[o_l] / shape_iou_cnt[o_l] for o_l in range(num_classes)]
226
+ part_iou = [np.divide(part_intersect[o_l][1:], part_union[o_l][1:]) for o_l in range(num_classes)]
227
+ mpIoU = [np.mean(part_iou[o_l]) for o_l in range(num_classes)]
228
+
229
+ # Print instance mean
230
+ mmsIoU = np.mean(np.array(msIoU))
231
+ mmpIoU = np.mean(mpIoU)
232
+
233
+ return msIoU, mpIoU, mmsIoU, mmpIoU
234
+
235
+
236
+ def IoU_from_confusions(confusions):
237
+ """
238
+ Computes IoU from confusion matrices.
239
+ :param confusions: ([..., n_c, n_c] np.int32). Can be any dimension, the confusion matrices should be described by
240
+ the last axes. n_c = number of classes
241
+ :param ignore_unclassified: (bool). True if the the first class should be ignored in the results
242
+ :return: ([..., n_c] np.float32) IoU score
243
+ """
244
+
245
+ # Compute TP, FP, FN. This assume that the second to last axis counts the truths (like the first axis of a
246
+ # confusion matrix), and that the last axis counts the predictions (like the second axis of a confusion matrix)
247
+ TP = np.diagonal(confusions, axis1=-2, axis2=-1)
248
+ TP_plus_FN = np.sum(confusions, axis=-1)
249
+ TP_plus_FP = np.sum(confusions, axis=-2)
250
+
251
+ # Compute IoU
252
+ IoU = TP / (TP_plus_FP + TP_plus_FN - TP + 1e-6)
253
+
254
+ # Compute miou with only the actual classes
255
+ mask = TP_plus_FN < 1e-3
256
+ counts = np.sum(1 - mask, axis=-1, keepdims=True)
257
+ miou = np.sum(IoU, axis=-1, keepdims=True) / (counts + 1e-6)
258
+
259
+ # If class is absent, place miou in place of 0 IoU to get the actual mean later
260
+ IoU += mask * miou
261
+
262
+ return IoU
263
+
264
+
265
+ def shapenetpart_metrics(num_classes, num_parts, objects, preds, targets, masks):
266
+ """
267
+ Args:
268
+ num_classes:
269
+ num_parts:
270
+ objects: [int]
271
+ preds:[(num_parts,num_points)]
272
+ targets: [(num_points)]
273
+ masks: [(num_points)]
274
+ """
275
+ total_correct = 0.0
276
+ total_seen = 0.0
277
+ Confs = []
278
+ for obj, cur_pred, cur_gt, cur_mask in zip(objects, preds, targets, masks):
279
+ obj = int(obj)
280
+ cur_num_parts = num_parts[obj]
281
+ cur_pred = np.argmax(cur_pred, axis=0)
282
+ cur_pred = cur_pred[cur_mask]
283
+ cur_gt = cur_gt[cur_mask]
284
+ correct = np.sum(cur_pred == cur_gt)
285
+ total_correct += correct
286
+ total_seen += cur_pred.shape[0]
287
+ parts = [j for j in range(cur_num_parts)]
288
+ Confs += [confusion_matrix(cur_gt, cur_pred, labels=parts)]
289
+
290
+ Confs = np.array(Confs)
291
+ obj_mious = []
292
+ objects = np.asarray(objects)
293
+ for l in range(num_classes):
294
+ obj_inds = np.where(objects == l)[0]
295
+ obj_confs = np.stack(Confs[obj_inds])
296
+ obj_IoUs = IoU_from_confusions(obj_confs)
297
+ obj_mious += [np.mean(obj_IoUs, axis=-1)]
298
+
299
+ objs_average = [np.mean(mious) for mious in obj_mious]
300
+ instance_average = np.mean(np.hstack(obj_mious))
301
+ class_average = np.mean(objs_average)
302
+ acc = total_correct / total_seen
303
+
304
+ print('Objs | Inst | Air Bag Cap Car Cha Ear Gui Kni Lam Lap Mot Mug Pis Roc Ska Tab')
305
+ print('-----|------|--------------------------------------------------------------------------------')
306
+
307
+ s = '{:4.1f} | {:4.1f} | '.format(100 * class_average, 100 * instance_average)
308
+ for Amiou in objs_average:
309
+ s += '{:4.1f} '.format(100 * Amiou)
310
+ print(s + '\n')
311
+ return acc, objs_average, class_average, instance_average
@@ -0,0 +1,16 @@
1
+ import numpy as np
2
+ import random
3
+ import torch
4
+
5
+
6
+ def set_random_seed(seed=0, deterministic=False):
7
+ random.seed(seed)
8
+ np.random.seed(seed)
9
+ torch.manual_seed(seed)
10
+ torch.cuda.manual_seed(seed)
11
+ torch.cuda.manual_seed_all(seed)
12
+ torch.backends.cudnn.benchmark = True
13
+
14
+ if deterministic:
15
+ torch.backends.cudnn.deterministic = True
16
+ torch.backends.cudnn.benchmark = False