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.
- openpoints/__init__.py +3 -0
- openpoints/cpp/__init__.py +6 -0
- openpoints/cpp/chamfer_dist/__init__.py +110 -0
- openpoints/cpp/chamfer_dist/setup.py +19 -0
- openpoints/cpp/chamfer_dist/test.py +34 -0
- openpoints/cpp/emd/__init__.py +3 -0
- openpoints/cpp/emd/emd.py +88 -0
- openpoints/cpp/emd/setup.py +27 -0
- openpoints/cpp/emd/test_emd_loss.py +45 -0
- openpoints/cpp/pointnet2_batch/__init__.py +24 -0
- openpoints/cpp/pointnet2_batch/setup.py +23 -0
- openpoints/cpp/pointops/__init__.py +0 -0
- openpoints/cpp/pointops/functions/__init__.py +0 -0
- openpoints/cpp/pointops/functions/pointops.py +314 -0
- openpoints/cpp/pointops/setup.py +37 -0
- openpoints/cpp/pointops/src/__init__.py +0 -0
- openpoints/dataset/__init__.py +10 -0
- openpoints/dataset/atom3d/__init__.py +1 -0
- openpoints/dataset/atom3d/psr.py +38 -0
- openpoints/dataset/build.py +98 -0
- openpoints/dataset/data_util.py +192 -0
- openpoints/dataset/datalist.py +67 -0
- openpoints/dataset/dataset_base.py +96 -0
- openpoints/dataset/graph_dataset/__init__.py +3 -0
- openpoints/dataset/graph_dataset/graph_dataset.py +93 -0
- openpoints/dataset/graph_dataset/stack_with_pad.py +91 -0
- openpoints/dataset/graph_dataset/structural_dataset.py +73 -0
- openpoints/dataset/graph_dataset/svd_encodings_dataset.py +110 -0
- openpoints/dataset/grid_sample.py +21 -0
- openpoints/dataset/matterport3d/__init__.py +1 -0
- openpoints/dataset/matterport3d/category_mapping.tsv +1660 -0
- openpoints/dataset/matterport3d/matterport3d.py +210 -0
- openpoints/dataset/matterport3d/matterport3d_dataprocessing.py +105 -0
- openpoints/dataset/modelnet/__init__.py +3 -0
- openpoints/dataset/modelnet/modelnet40_normal_resampled_loader.py +124 -0
- openpoints/dataset/modelnet/modelnet40_ply_2048_loader.py +160 -0
- openpoints/dataset/molhiv/__init__.py +1 -0
- openpoints/dataset/molhiv/data.py +59 -0
- openpoints/dataset/molpcba/__init__.py +1 -0
- openpoints/dataset/molpcba/data.py +59 -0
- openpoints/dataset/parsers/__init__.py +1 -0
- openpoints/dataset/parsers/class_map.py +19 -0
- openpoints/dataset/parsers/constants.py +1 -0
- openpoints/dataset/parsers/parser.py +17 -0
- openpoints/dataset/parsers/parser_factory.py +29 -0
- openpoints/dataset/parsers/parser_image_folder.py +69 -0
- openpoints/dataset/parsers/parser_image_in_tar.py +222 -0
- openpoints/dataset/parsers/parser_image_tar.py +72 -0
- openpoints/dataset/parsers/parser_tfds.py +297 -0
- openpoints/dataset/pcqm4m/__init__.py +1 -0
- openpoints/dataset/pcqm4m/data.py +62 -0
- openpoints/dataset/pcqm4mv2/__init__.py +1 -0
- openpoints/dataset/pcqm4mv2/data.py +87 -0
- openpoints/dataset/s3dis/__init__.py +2 -0
- openpoints/dataset/s3dis/s3dis.py +156 -0
- openpoints/dataset/s3dis/s3dis_block.py +96 -0
- openpoints/dataset/s3dis/s3dis_sphere.py +349 -0
- openpoints/dataset/scannetv2/__init__.py +1 -0
- openpoints/dataset/scannetv2/scannet.py +176 -0
- openpoints/dataset/scanobjectnn/__init__.py +3 -0
- openpoints/dataset/scanobjectnn/scanobjectnn.py +110 -0
- openpoints/dataset/semantic_kitti/__init__.py +1 -0
- openpoints/dataset/semantic_kitti/helper_tool.py +286 -0
- openpoints/dataset/semantic_kitti/label_mapping.yaml +211 -0
- openpoints/dataset/semantic_kitti/semantickitti.py +229 -0
- openpoints/dataset/semantic_kitti/utils/meta/anno_paths.txt +272 -0
- openpoints/dataset/semantic_kitti/utils/meta/class_names.txt +13 -0
- openpoints/dataset/semantic_kitti/utils/semantic-kitti.yaml +211 -0
- openpoints/dataset/shapenet/__init__.py +1 -0
- openpoints/dataset/shapenet/shapenet55.py +76 -0
- openpoints/dataset/shapenet/shapenetpart.py +121 -0
- openpoints/dataset/shapenetpart/__init__.py +1 -0
- openpoints/dataset/shapenetpart/shapenet55.py +75 -0
- openpoints/dataset/shapenetpart/shapenetpart.py +388 -0
- openpoints/dataset/vis2d.py +17 -0
- openpoints/dataset/vis3d.py +153 -0
- openpoints/loss/__init__.py +3 -0
- openpoints/loss/build.py +281 -0
- openpoints/loss/cross_entropy.py +38 -0
- openpoints/loss/distill_loss.py +76 -0
- openpoints/models/__init__.py +10 -0
- openpoints/models/backbone/Stratified_transformer.py +558 -0
- openpoints/models/backbone/__init__.py +11 -0
- openpoints/models/backbone/baafnet.py +527 -0
- openpoints/models/backbone/ball_dgcnn.py +123 -0
- openpoints/models/backbone/curvenet.py +793 -0
- openpoints/models/backbone/debug_invvit.py +114 -0
- openpoints/models/backbone/deepgcn.py +143 -0
- openpoints/models/backbone/dgcnn.py +119 -0
- openpoints/models/backbone/graphvit3d.py +134 -0
- openpoints/models/backbone/grouppointnet.py +100 -0
- openpoints/models/backbone/pct.py +163 -0
- openpoints/models/backbone/pointmlp.py +417 -0
- openpoints/models/backbone/pointnet.py +199 -0
- openpoints/models/backbone/pointnetv2.py +511 -0
- openpoints/models/backbone/pointnext.py +663 -0
- openpoints/models/backbone/pointnextPyG.py +555 -0
- openpoints/models/backbone/pointtransformer.py +293 -0
- openpoints/models/backbone/pointvector.py +853 -0
- openpoints/models/backbone/pointvit.py +392 -0
- openpoints/models/backbone/pointvit_inv.py +942 -0
- openpoints/models/backbone/pointvit_inv_old.py +784 -0
- openpoints/models/backbone/randlenet.py +318 -0
- openpoints/models/backbone/resnet.py +342 -0
- openpoints/models/backbone/simpleview.py +153 -0
- openpoints/models/backbone/simpleview_util.py +292 -0
- openpoints/models/build.py +13 -0
- openpoints/models/classification/__init__.py +5 -0
- openpoints/models/classification/cls_base.py +136 -0
- openpoints/models/classification/point_bert.py +154 -0
- openpoints/models/layers/__init__.py +14 -0
- openpoints/models/layers/activation.py +57 -0
- openpoints/models/layers/attention.py +103 -0
- openpoints/models/layers/conv.py +167 -0
- openpoints/models/layers/drop.py +164 -0
- openpoints/models/layers/graph_conv.py +122 -0
- openpoints/models/layers/group.py +415 -0
- openpoints/models/layers/group_embed.py +286 -0
- openpoints/models/layers/helpers.py +43 -0
- openpoints/models/layers/kmeans.py +119 -0
- openpoints/models/layers/knn.py +110 -0
- openpoints/models/layers/local_aggregation.py +286 -0
- openpoints/models/layers/mlp.py +129 -0
- openpoints/models/layers/norm.py +106 -0
- openpoints/models/layers/padding.py +56 -0
- openpoints/models/layers/patch_embed.py +37 -0
- openpoints/models/layers/registry.py +168 -0
- openpoints/models/layers/subsample.py +185 -0
- openpoints/models/layers/upsampling.py +106 -0
- openpoints/models/layers/weight_init.py +89 -0
- openpoints/models/reconstruction/__init__.py +8 -0
- openpoints/models/reconstruction/base_recontruct.py +216 -0
- openpoints/models/reconstruction/maskedpoint.py +116 -0
- openpoints/models/reconstruction/maskedpointgroup.py +168 -0
- openpoints/models/reconstruction/maskedpointvit.py +253 -0
- openpoints/models/reconstruction/nodeshuffle.py +11 -0
- openpoints/models/registry.py +149 -0
- openpoints/models/segmentation/__init__.py +6 -0
- openpoints/models/segmentation/base_seg.py +278 -0
- openpoints/models/segmentation/vit_seg.py +126 -0
- openpoints/optim/__init__.py +15 -0
- openpoints/optim/adabelief.py +201 -0
- openpoints/optim/adafactor.py +167 -0
- openpoints/optim/adahessian.py +156 -0
- openpoints/optim/adamp.py +105 -0
- openpoints/optim/adamw.py +122 -0
- openpoints/optim/lamb.py +192 -0
- openpoints/optim/lars.py +135 -0
- openpoints/optim/lookahead.py +61 -0
- openpoints/optim/madgrad.py +184 -0
- openpoints/optim/nadam.py +92 -0
- openpoints/optim/nvnovograd.py +120 -0
- openpoints/optim/optim_factory.py +306 -0
- openpoints/optim/radam.py +89 -0
- openpoints/optim/rmsprop_tf.py +139 -0
- openpoints/optim/sgdp.py +70 -0
- openpoints/scheduler/__init__.py +8 -0
- openpoints/scheduler/cosine_lr.py +124 -0
- openpoints/scheduler/multistep_lr.py +65 -0
- openpoints/scheduler/plateau_lr.py +113 -0
- openpoints/scheduler/poly_lr.py +116 -0
- openpoints/scheduler/scheduler.py +110 -0
- openpoints/scheduler/scheduler_factory.py +118 -0
- openpoints/scheduler/step_lr.py +65 -0
- openpoints/scheduler/tanh_lr.py +117 -0
- openpoints/transforms/__init__.py +7 -0
- openpoints/transforms/point_transform_cpu.py +332 -0
- openpoints/transforms/point_transformer_gpu.py +764 -0
- openpoints/transforms/transforms_factory.py +60 -0
- openpoints/utils/__init__.py +8 -0
- openpoints/utils/ckpt_util.py +438 -0
- openpoints/utils/config.py +113 -0
- openpoints/utils/dist_utils.py +54 -0
- openpoints/utils/logger.py +170 -0
- openpoints/utils/metrics.py +311 -0
- openpoints/utils/random.py +16 -0
- openpoints/utils/registry.py +294 -0
- openpoints/utils/str2bool.py +11 -0
- openpoints/utils/wandb.py +88 -0
- openpoints-0.1.0.dist-info/METADATA +150 -0
- openpoints-0.1.0.dist-info/RECORD +184 -0
- openpoints-0.1.0.dist-info/WHEEL +5 -0
- openpoints-0.1.0.dist-info/licenses/LICENSE +21 -0
- openpoints-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
""" Maksed PointViT in PyTorch
|
|
2
|
+
Copyright 2022@PointNeXt team
|
|
3
|
+
"""
|
|
4
|
+
import logging
|
|
5
|
+
import torch
|
|
6
|
+
import torch.nn as nn
|
|
7
|
+
from openpoints.models.layers import create_norm
|
|
8
|
+
from openpoints.models.layers.attention import Block
|
|
9
|
+
from openpoints.models.build import MODELS
|
|
10
|
+
from openpoints.cpp.chamfer_dist import ChamferDistanceL1
|
|
11
|
+
from ..backbone import PointViT
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@MODELS.register_module()
|
|
15
|
+
class MaskedPointViT(nn.Module):
|
|
16
|
+
""" Vision Transformer for 3D
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self,
|
|
20
|
+
in_channels=6, num_classes=40,
|
|
21
|
+
embed_dim=384,
|
|
22
|
+
depth=12,
|
|
23
|
+
num_heads=6, mlp_ratio=4., qkv_bias=False,
|
|
24
|
+
decoder_embed_dim=192, decoder_depth=4, decoder_num_heads=16,
|
|
25
|
+
embed_args={'NAME': 'PointPatchEmbed',
|
|
26
|
+
'sample_ratio': 0.0625,
|
|
27
|
+
'group_size': 32,
|
|
28
|
+
'subsample': 'fps',
|
|
29
|
+
'group': 'knn',
|
|
30
|
+
'feature_type': 'dp'},
|
|
31
|
+
norm_args={'norm': 'ln', 'eps': 1.0e-6},
|
|
32
|
+
act_args={'act': 'gelu'},
|
|
33
|
+
posembed_norm_args=None, add_pos_each_block=True,
|
|
34
|
+
mask_ratio=0.75,
|
|
35
|
+
**kwargs
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Args:
|
|
39
|
+
num_group (int, tuple): number of patches (groups in 3d)
|
|
40
|
+
group_size (int, tuple): the size (# points) of each group
|
|
41
|
+
in_chans (int): number of input channels
|
|
42
|
+
num_classes (int): number of classes for classification head
|
|
43
|
+
embed_dim (int): embedding dimension
|
|
44
|
+
depth (int): depth of transformer
|
|
45
|
+
num_heads (int): number of attention heads
|
|
46
|
+
mlp_ratio (int): ratio of mlp hidden dim to embedding dim
|
|
47
|
+
qkv_bias (bool): enable bias for qkv if True
|
|
48
|
+
representation_size (Optional[int]): enable and set representation layer (pre-logits) to this value if set
|
|
49
|
+
distilled (bool): model includes a distillation token and head as in DeiT models
|
|
50
|
+
drop_rate (float): dropout rate
|
|
51
|
+
attn_drop_rate (float): attention dropout rate
|
|
52
|
+
drop_path_rate (float): stochastic depth rate
|
|
53
|
+
embed_layer (nn.Module): patch embedding layer
|
|
54
|
+
norm_layer: (nn.Module): normalization layer
|
|
55
|
+
weight_init: (str): weight init scheme
|
|
56
|
+
"""
|
|
57
|
+
super().__init__()
|
|
58
|
+
if kwargs:
|
|
59
|
+
logging.warning(f"kwargs: {kwargs} are not used in {__class__.__name__}")
|
|
60
|
+
self.mask_ratio = mask_ratio
|
|
61
|
+
self.num_classes = num_classes
|
|
62
|
+
self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models
|
|
63
|
+
self.add_pos_each_block = add_pos_each_block
|
|
64
|
+
|
|
65
|
+
# MAE encoder
|
|
66
|
+
# ------------------------------------------------------------------
|
|
67
|
+
self.encoder = PointViT(
|
|
68
|
+
in_channels, num_classes,
|
|
69
|
+
embed_dim, depth,
|
|
70
|
+
num_heads, mlp_ratio, qkv_bias,
|
|
71
|
+
embed_args=embed_args, norm_args=norm_args, act_args=act_args,
|
|
72
|
+
posembed_norm_args=posembed_norm_args,
|
|
73
|
+
add_pos_each_block=add_pos_each_block)
|
|
74
|
+
|
|
75
|
+
# ------------------------------------------------------------------
|
|
76
|
+
# MAE decoder
|
|
77
|
+
self.decoder_embed = nn.Linear(embed_dim, decoder_embed_dim, bias=True)
|
|
78
|
+
self.mask_token = nn.Parameter(torch.randn(1, 1, decoder_embed_dim))
|
|
79
|
+
self.decoder_cls_pos = nn.Parameter(torch.randn(1, 1, decoder_embed_dim))
|
|
80
|
+
self.decoder_pos_embed = nn.Sequential(
|
|
81
|
+
nn.Linear(3, 128),
|
|
82
|
+
nn.GELU(),
|
|
83
|
+
nn.Linear(128, decoder_embed_dim)
|
|
84
|
+
)
|
|
85
|
+
self.decoder_blocks = nn.ModuleList([
|
|
86
|
+
Block(
|
|
87
|
+
dim=decoder_embed_dim, num_heads=decoder_num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias,
|
|
88
|
+
norm_args=norm_args, act_args=act_args
|
|
89
|
+
)
|
|
90
|
+
for _ in range(decoder_depth)])
|
|
91
|
+
self.decoder_norm = create_norm(norm_args, decoder_embed_dim)
|
|
92
|
+
|
|
93
|
+
self.decoder_pred = nn.Linear(decoder_embed_dim, embed_args.group_size * 3, bias=True) # decoder to patch
|
|
94
|
+
self.initialize_weights()
|
|
95
|
+
self.build_loss_func()
|
|
96
|
+
|
|
97
|
+
def initialize_weights(self):
|
|
98
|
+
# initialization
|
|
99
|
+
torch.nn.init.normal_(self.encoder.cls_token, std=.02)
|
|
100
|
+
torch.nn.init.normal_(self.encoder.cls_pos, std=.02)
|
|
101
|
+
torch.nn.init.normal_(self.decoder_cls_pos, std=.02)
|
|
102
|
+
torch.nn.init.normal_(self.mask_token, std=.02)
|
|
103
|
+
|
|
104
|
+
# initialize nn.Linear and nn.LayerNorm
|
|
105
|
+
self.apply(self._init_weights)
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def _init_weights(m):
|
|
109
|
+
if isinstance(m, nn.Linear):
|
|
110
|
+
torch.nn.init.xavier_uniform_(m.weight)
|
|
111
|
+
if isinstance(m, nn.Linear) and m.bias is not None:
|
|
112
|
+
nn.init.constant_(m.bias, 0)
|
|
113
|
+
elif isinstance(m, (nn.LayerNorm, nn.GroupNorm, nn.BatchNorm2d, nn.BatchNorm1d)):
|
|
114
|
+
nn.init.constant_(m.bias, 0)
|
|
115
|
+
nn.init.constant_(m.weight, 1.0)
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def random_masking(x, pos_embed, mask_ratio):
|
|
119
|
+
"""
|
|
120
|
+
Perform per-sample random masking by per-sample shuffling.
|
|
121
|
+
Per-sample shuffling is done by argsort random noise.
|
|
122
|
+
x: [N, L, D], sequence
|
|
123
|
+
"""
|
|
124
|
+
N, L, D = x.shape # batch, length, dim
|
|
125
|
+
len_keep = int(L * (1 - mask_ratio))
|
|
126
|
+
|
|
127
|
+
noise = torch.rand(N, L, device=x.device) # noise in [0, 1]
|
|
128
|
+
|
|
129
|
+
# sort noise for each sample
|
|
130
|
+
ids_shuffle = torch.argsort(noise, dim=1) # ascend: small is keep, large is remove
|
|
131
|
+
ids_restore = torch.argsort(ids_shuffle, dim=1)
|
|
132
|
+
|
|
133
|
+
# keep the first subset
|
|
134
|
+
ids_keep = ids_shuffle[:, :len_keep]
|
|
135
|
+
x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D))
|
|
136
|
+
pos_embed_masked = torch.gather(pos_embed, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D))
|
|
137
|
+
# generate the binary mask: 0 is keep, 1 is remove
|
|
138
|
+
mask = torch.ones([N, L], device=x.device)
|
|
139
|
+
mask[:, :len_keep] = 0
|
|
140
|
+
# unshuffle to get the binary mask
|
|
141
|
+
mask = torch.gather(mask, dim=1, index=ids_restore)
|
|
142
|
+
|
|
143
|
+
return x_masked, pos_embed_masked, mask, ids_restore, ids_keep
|
|
144
|
+
|
|
145
|
+
def build_loss_func(self, smoothing=False):
|
|
146
|
+
self.criterion = ChamferDistanceL1()
|
|
147
|
+
|
|
148
|
+
# Facebook.
|
|
149
|
+
def forward_encoder(self, center_xyz, features, mask_ratio):
|
|
150
|
+
pos_embed = self.encoder.pos_embed(center_xyz)
|
|
151
|
+
# masking: length -> length * mask_ratio. Here, pos_embed has been shuffled!!!
|
|
152
|
+
features, pos_embed, mask, ids_restore, idx_keep = self.random_masking(features, pos_embed, mask_ratio)
|
|
153
|
+
|
|
154
|
+
"""DEBUG. visualization code for masking.
|
|
155
|
+
from openpoints.dataset import vis_multi_points
|
|
156
|
+
xyz_keep = torch.gather(center_xyz, 1, idx_keep.unsqueeze(-1).expand(-1, -1, 3))
|
|
157
|
+
vis_multi_points((center_xyz[0].cpu().numpy(), xyz_keep[0].cpu().numpy()))
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
# append cls token after masking
|
|
161
|
+
pos_embed = torch.cat((self.encoder.cls_pos.expand(features.shape[0], -1, -1), pos_embed), dim=1)
|
|
162
|
+
cls_token = self.encoder.cls_token.expand(features.shape[0], -1, -1)
|
|
163
|
+
features = torch.cat((cls_token, features), dim=1)
|
|
164
|
+
|
|
165
|
+
if self.encoder.add_pos_each_block:
|
|
166
|
+
for block in self.encoder.blocks:
|
|
167
|
+
features = block(features + pos_embed)
|
|
168
|
+
else:
|
|
169
|
+
features = self.pos_drop(features + pos_embed)
|
|
170
|
+
for block in self.encoder.blocks:
|
|
171
|
+
features = block(features)
|
|
172
|
+
|
|
173
|
+
features = self.encoder.norm(features)
|
|
174
|
+
return features, mask, ids_restore, idx_keep
|
|
175
|
+
|
|
176
|
+
def forward_decoder(self, features, center_xyz, ids_restore):
|
|
177
|
+
# embed tokens
|
|
178
|
+
features = self.decoder_embed(features)
|
|
179
|
+
B, L, C = features.shape # batch size, length, channels
|
|
180
|
+
|
|
181
|
+
# in the decoder part. we know the positional encoding of groups
|
|
182
|
+
decoder_pos_embed = torch.cat(
|
|
183
|
+
(self.decoder_cls_pos.expand(B, -1, -1), self.decoder_pos_embed(center_xyz)), dim=1)
|
|
184
|
+
|
|
185
|
+
# append mask tokens to sequence
|
|
186
|
+
# use mask tokens to fill the masked features. this is why missing part should be 1 not 0.
|
|
187
|
+
mask_tokens = self.mask_token.repeat(B, ids_restore.shape[1] + 1 - features.shape[1], 1)
|
|
188
|
+
x_ = torch.cat([features[:, 1:, :], mask_tokens], dim=1) # no cls token
|
|
189
|
+
x_ = torch.gather(x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, C)) # unshuffle
|
|
190
|
+
features = torch.cat([features[:, :1, :], x_], dim=1) # append cls token
|
|
191
|
+
|
|
192
|
+
if self.add_pos_each_block:
|
|
193
|
+
for block in self.decoder_blocks:
|
|
194
|
+
features = block(features + decoder_pos_embed)
|
|
195
|
+
else:
|
|
196
|
+
features = self.pos_drop(features + decoder_pos_embed)
|
|
197
|
+
for block in self.decoder_blocks:
|
|
198
|
+
features = block(features)
|
|
199
|
+
|
|
200
|
+
features = self.decoder_norm(features)
|
|
201
|
+
# predictor projection
|
|
202
|
+
features = self.decoder_pred(features)
|
|
203
|
+
# remove cls token
|
|
204
|
+
features = features[:, 1:, :]
|
|
205
|
+
return features
|
|
206
|
+
|
|
207
|
+
def forward_loss(self, xyz, grouped_xyz, pred, mask, idx_keep):
|
|
208
|
+
"""
|
|
209
|
+
# chamfer distance. two options
|
|
210
|
+
1. chamfer distance on the merged point clouds.
|
|
211
|
+
2. chamfer distance per local patch
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
xyz: the original points [B, N, 3]
|
|
215
|
+
grouped_xyz: the points after grouping. [B, 3, L, K]
|
|
216
|
+
pred: [B, L, K*3]
|
|
217
|
+
mask: [B, L], 0 is keep, 1 is remove,
|
|
218
|
+
idx_keep: [B, L]
|
|
219
|
+
"""
|
|
220
|
+
# option 2, per patch chamfer distance.
|
|
221
|
+
B, C, L, K = grouped_xyz.shape
|
|
222
|
+
# consider (B, L) as batchs, chamfer distance per patch
|
|
223
|
+
|
|
224
|
+
# idx_keep = idx_keep.unsqueeze(-1).expand(-1, -1, K)
|
|
225
|
+
# pred = torch.gather(pred, 1, idx_keep) # B,
|
|
226
|
+
# grouped_xyz = torch.gather(grouped_xyz, 2, idx_keep.unsqueeze(1).expand(-1, C, -1, -1))
|
|
227
|
+
|
|
228
|
+
grouped_xyz = grouped_xyz.permute(0, 2, 3, 1).reshape(-1, K, C)
|
|
229
|
+
pred = pred.reshape(-1, K, C)
|
|
230
|
+
loss = self.criterion(pred, grouped_xyz)
|
|
231
|
+
|
|
232
|
+
# mask = mask.unsqueeze(-1)
|
|
233
|
+
# grouped_xyz = torch.mul(grouped_xyz.permute(0, 2, 3, 1), mask.unsqueeze(-1)).reshape(-1, K, C)
|
|
234
|
+
# pred = torch.mul(pred, mask).reshape(-1, K, C)
|
|
235
|
+
# loss = self.criterion(pred, grouped_xyz)/ mask.sum()
|
|
236
|
+
return loss
|
|
237
|
+
|
|
238
|
+
def forward(self, xyz, features=None):
|
|
239
|
+
center_xyz, features, grouped_xyz, grouped_features = self.encoder.patch_embed(xyz, features)
|
|
240
|
+
latent, mask, ids_restore, idx_keep = self.forward_encoder(center_xyz, features, self.mask_ratio)
|
|
241
|
+
pred = self.forward_decoder(latent, center_xyz, ids_restore) # [N, L, p*p*3]
|
|
242
|
+
|
|
243
|
+
"""visualize pred. TODO: add to Tensorboard
|
|
244
|
+
from openpoints.dataset import vis_multi_points
|
|
245
|
+
B, C, L, K = grouped_xyz.shape
|
|
246
|
+
input_group_pts = grouped_xyz.clone().permute(0, 2, 3, 1).reshape(B, -1, C).detach().cpu().numpy()
|
|
247
|
+
# input_group_pts = grouped_xyz.clone().permute(0, 2, 3, 1).reshape(B, -1, C).detach().cpu().numpy()
|
|
248
|
+
pred_group_pts = pred.clone().reshape(B, -1, C).detach().cpu().numpy()
|
|
249
|
+
vis_multi_points((xyz[0].cpu().numpy(), center_xyz[0].detach().cpu().numpy(), input_group_pts[0], pred_group_pts[0]))
|
|
250
|
+
"""
|
|
251
|
+
loss = self.forward_loss(xyz, grouped_xyz, pred, mask, idx_keep)
|
|
252
|
+
return loss, pred
|
|
253
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
""" Model Registry
|
|
2
|
+
Hacked together by / Copyright 2020 Ross Wightman
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import re
|
|
7
|
+
import fnmatch
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
from copy import deepcopy
|
|
10
|
+
|
|
11
|
+
__all__ = ['list_models', 'is_model', 'model_entrypoint', 'list_modules', 'is_model_in_modules',
|
|
12
|
+
'is_model_default_key', 'has_model_default_key', 'get_model_default_value', 'is_model_pretrained']
|
|
13
|
+
|
|
14
|
+
_module_to_models = defaultdict(set) # dict of sets to check membership of model in module
|
|
15
|
+
_model_to_module = {} # mapping of model names to module names
|
|
16
|
+
_model_entrypoints = {} # mapping of model names to entrypoint fns
|
|
17
|
+
_model_has_pretrained = set() # set of model names that have pretrained weight url present
|
|
18
|
+
_model_default_cfgs = dict() # central repo for model default_cfgs
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_model(fn):
|
|
22
|
+
# lookup containing module
|
|
23
|
+
mod = sys.modules[fn.__module__]
|
|
24
|
+
module_name_split = fn.__module__.split('.')
|
|
25
|
+
module_name = module_name_split[-1] if len(module_name_split) else ''
|
|
26
|
+
|
|
27
|
+
# add model to __all__ in module
|
|
28
|
+
model_name = fn.__name__
|
|
29
|
+
if hasattr(mod, '__all__'):
|
|
30
|
+
mod.__all__.append(model_name)
|
|
31
|
+
else:
|
|
32
|
+
mod.__all__ = [model_name]
|
|
33
|
+
|
|
34
|
+
# add entries to registry dict/sets
|
|
35
|
+
_model_entrypoints[model_name] = fn
|
|
36
|
+
_model_to_module[model_name] = module_name
|
|
37
|
+
_module_to_models[module_name].add(model_name)
|
|
38
|
+
has_pretrained = False # check if model has a pretrained url to allow filtering on this
|
|
39
|
+
if hasattr(mod, 'default_cfgs') and model_name in mod.default_cfgs:
|
|
40
|
+
# this will catch all models that have entrypoint matching cfg key, but miss any aliasing
|
|
41
|
+
# entrypoints or non-matching combos
|
|
42
|
+
has_pretrained = 'url' in mod.default_cfgs[model_name] and 'http' in mod.default_cfgs[model_name]['url']
|
|
43
|
+
_model_default_cfgs[model_name] = deepcopy(mod.default_cfgs[model_name])
|
|
44
|
+
if has_pretrained:
|
|
45
|
+
_model_has_pretrained.add(model_name)
|
|
46
|
+
return fn
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _natural_key(string_):
|
|
50
|
+
return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_.lower())]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def list_models(filter='', module='', pretrained=False, exclude_filters='', name_matches_cfg=False):
|
|
54
|
+
""" Return list of available model names, sorted alphabetically
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
filter (str) - Wildcard filter string that works with fnmatch
|
|
58
|
+
module (str) - Limit model selection to a specific sub-module (ie 'gen_efficientnet')
|
|
59
|
+
pretrained (bool) - Include only models with pretrained weights if True
|
|
60
|
+
exclude_filters (str or list[str]) - Wildcard filters to exclude models after including them with filter
|
|
61
|
+
name_matches_cfg (bool) - Include only models w/ model_name matching default_cfg name (excludes some aliases)
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
model_list('gluon_resnet*') -- returns all models starting with 'gluon_resnet'
|
|
65
|
+
model_list('*resnext*, 'resnet') -- returns all models with 'resnext' in 'resnet' module
|
|
66
|
+
"""
|
|
67
|
+
if module:
|
|
68
|
+
all_models = list(_module_to_models[module])
|
|
69
|
+
else:
|
|
70
|
+
all_models = _model_entrypoints.keys()
|
|
71
|
+
if filter:
|
|
72
|
+
models = []
|
|
73
|
+
include_filters = filter if isinstance(filter, (tuple, list)) else [filter]
|
|
74
|
+
for f in include_filters:
|
|
75
|
+
include_models = fnmatch.filter(all_models, f) # include these models
|
|
76
|
+
if len(include_models):
|
|
77
|
+
models = set(models).union(include_models)
|
|
78
|
+
else:
|
|
79
|
+
models = all_models
|
|
80
|
+
if exclude_filters:
|
|
81
|
+
if not isinstance(exclude_filters, (tuple, list)):
|
|
82
|
+
exclude_filters = [exclude_filters]
|
|
83
|
+
for xf in exclude_filters:
|
|
84
|
+
exclude_models = fnmatch.filter(models, xf) # exclude these models
|
|
85
|
+
if len(exclude_models):
|
|
86
|
+
models = set(models).difference(exclude_models)
|
|
87
|
+
if pretrained:
|
|
88
|
+
models = _model_has_pretrained.intersection(models)
|
|
89
|
+
if name_matches_cfg:
|
|
90
|
+
models = set(_model_default_cfgs).intersection(models)
|
|
91
|
+
return list(sorted(models, key=_natural_key))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def is_model(model_name):
|
|
95
|
+
""" Check if a model name exists
|
|
96
|
+
"""
|
|
97
|
+
return model_name in _model_entrypoints
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def model_entrypoint(model_name):
|
|
101
|
+
"""Fetch a model entrypoint for specified model name
|
|
102
|
+
"""
|
|
103
|
+
return _model_entrypoints[model_name]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def list_modules():
|
|
107
|
+
""" Return list of module names that contain models / model entrypoints
|
|
108
|
+
"""
|
|
109
|
+
modules = _module_to_models.keys()
|
|
110
|
+
return list(sorted(modules))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def is_model_in_modules(model_name, module_names):
|
|
114
|
+
"""Check if a model exists within a subset of modules
|
|
115
|
+
Args:
|
|
116
|
+
model_name (str) - name of model to check
|
|
117
|
+
module_names (tuple, list, set) - names of modules to search in
|
|
118
|
+
"""
|
|
119
|
+
assert isinstance(module_names, (tuple, list, set))
|
|
120
|
+
return any(model_name in _module_to_models[n] for n in module_names)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def has_model_default_key(model_name, cfg_key):
|
|
124
|
+
""" Query model default_cfgs for existence of a specific key.
|
|
125
|
+
"""
|
|
126
|
+
if model_name in _model_default_cfgs and cfg_key in _model_default_cfgs[model_name]:
|
|
127
|
+
return True
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def is_model_default_key(model_name, cfg_key):
|
|
132
|
+
""" Return truthy value for specified model default_cfg key, False if does not exist.
|
|
133
|
+
"""
|
|
134
|
+
if model_name in _model_default_cfgs and _model_default_cfgs[model_name].get(cfg_key, False):
|
|
135
|
+
return True
|
|
136
|
+
return False
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def get_model_default_value(model_name, cfg_key):
|
|
140
|
+
""" Get a specific model default_cfg value by key. None if it doesn't exist.
|
|
141
|
+
"""
|
|
142
|
+
if model_name in _model_default_cfgs:
|
|
143
|
+
return _model_default_cfgs[model_name].get(cfg_key, None)
|
|
144
|
+
else:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def is_model_pretrained(model_name):
|
|
149
|
+
return model_name in _model_has_pretrained
|