upd
This commit is contained in:
commit
9c2625b11e
@ -7,9 +7,9 @@ runner:
|
|||||||
parallel: False
|
parallel: False
|
||||||
|
|
||||||
experiment:
|
experiment:
|
||||||
name: train_ab_global_only
|
name: train_ab_global_only_with_accept_probability
|
||||||
root_dir: "experiments"
|
root_dir: "experiments"
|
||||||
use_checkpoint: True
|
use_checkpoint: False
|
||||||
epoch: -1 # -1 stands for last epoch
|
epoch: -1 # -1 stands for last epoch
|
||||||
max_epochs: 5000
|
max_epochs: 5000
|
||||||
save_checkpoint_interval: 1
|
save_checkpoint_interval: 1
|
||||||
@ -96,6 +96,9 @@ module:
|
|||||||
global_feat: True
|
global_feat: True
|
||||||
feature_transform: False
|
feature_transform: False
|
||||||
|
|
||||||
|
pointnet++_encoder:
|
||||||
|
in_dim: 3
|
||||||
|
|
||||||
transformer_seq_encoder:
|
transformer_seq_encoder:
|
||||||
embed_dim: 256
|
embed_dim: 256
|
||||||
num_heads: 4
|
num_heads: 4
|
||||||
|
@ -4,6 +4,7 @@ import PytorchBoot.namespace as namespace
|
|||||||
import PytorchBoot.stereotype as stereotype
|
import PytorchBoot.stereotype as stereotype
|
||||||
from PytorchBoot.config import ConfigManager
|
from PytorchBoot.config import ConfigManager
|
||||||
from PytorchBoot.utils.log_util import Log
|
from PytorchBoot.utils.log_util import Log
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@ -50,7 +51,7 @@ class NBVReconstructionDataset(BaseDataset):
|
|||||||
scene_name_list.append(scene_name)
|
scene_name_list.append(scene_name)
|
||||||
return scene_name_list
|
return scene_name_list
|
||||||
|
|
||||||
def get_datalist(self):
|
def get_datalist(self, bias=False):
|
||||||
datalist = []
|
datalist = []
|
||||||
for scene_name in self.scene_name_list:
|
for scene_name in self.scene_name_list:
|
||||||
seq_num = DataLoadUtil.get_label_num(self.root_dir, scene_name)
|
seq_num = DataLoadUtil.get_label_num(self.root_dir, scene_name)
|
||||||
@ -79,6 +80,8 @@ class NBVReconstructionDataset(BaseDataset):
|
|||||||
for data_pair in label_data["data_pairs"]:
|
for data_pair in label_data["data_pairs"]:
|
||||||
scanned_views = data_pair[0]
|
scanned_views = data_pair[0]
|
||||||
next_best_view = data_pair[1]
|
next_best_view = data_pair[1]
|
||||||
|
accept_probability = scanned_views[-1][1]
|
||||||
|
if accept_probability > np.random.rand():
|
||||||
datalist.append(
|
datalist.append(
|
||||||
{
|
{
|
||||||
"scanned_views": scanned_views,
|
"scanned_views": scanned_views,
|
||||||
@ -227,9 +230,10 @@ if __name__ == "__main__":
|
|||||||
torch.manual_seed(seed)
|
torch.manual_seed(seed)
|
||||||
np.random.seed(seed)
|
np.random.seed(seed)
|
||||||
config = {
|
config = {
|
||||||
"root_dir": "/data/hofee/data/packed_preprocessed_data",
|
"root_dir": "/data/hofee/data/new_full_data",
|
||||||
|
"model_dir": "../data/scaled_object_meshes",
|
||||||
"source": "nbv_reconstruction_dataset",
|
"source": "nbv_reconstruction_dataset",
|
||||||
"split_file": "/data/hofee/data/OmniObject3d_train.txt",
|
"split_file": "/data/hofee/data/new_full_data_list/OmniObject3d_train.txt",
|
||||||
"load_from_preprocess": True,
|
"load_from_preprocess": True,
|
||||||
"ratio": 0.5,
|
"ratio": 0.5,
|
||||||
"batch_size": 2,
|
"batch_size": 2,
|
||||||
|
@ -55,6 +55,7 @@ class SeqReconstructionDataset(BaseDataset):
|
|||||||
def get_scene_name_list(self):
|
def get_scene_name_list(self):
|
||||||
return self.scene_name_list
|
return self.scene_name_list
|
||||||
|
|
||||||
|
|
||||||
def get_datalist(self):
|
def get_datalist(self):
|
||||||
datalist = []
|
datalist = []
|
||||||
total = len(self.scene_name_list)
|
total = len(self.scene_name_list)
|
||||||
|
162
modules/module_lib/pointnet2_modules.py
Normal file
162
modules/module_lib/pointnet2_modules.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
import torch.nn.functional as F
|
||||||
|
|
||||||
|
from . import pointnet2_utils
|
||||||
|
from . import pytorch_utils as pt_utils
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
class _PointnetSAModuleBase(nn.Module):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.npoint = None
|
||||||
|
self.groupers = None
|
||||||
|
self.mlps = None
|
||||||
|
self.pool_method = 'max_pool'
|
||||||
|
|
||||||
|
def forward(self, xyz: torch.Tensor, features: torch.Tensor = None, new_xyz=None) -> (torch.Tensor, torch.Tensor):
|
||||||
|
"""
|
||||||
|
:param xyz: (B, N, 3) tensor of the xyz coordinates of the features
|
||||||
|
:param features: (B, N, C) tensor of the descriptors of the the features
|
||||||
|
:param new_xyz:
|
||||||
|
:return:
|
||||||
|
new_xyz: (B, npoint, 3) tensor of the new features' xyz
|
||||||
|
new_features: (B, npoint, \sum_k(mlps[k][-1])) tensor of the new_features descriptors
|
||||||
|
"""
|
||||||
|
new_features_list = []
|
||||||
|
|
||||||
|
xyz_flipped = xyz.transpose(1, 2).contiguous()
|
||||||
|
if new_xyz is None:
|
||||||
|
new_xyz = pointnet2_utils.gather_operation(
|
||||||
|
xyz_flipped,
|
||||||
|
pointnet2_utils.furthest_point_sample(xyz, self.npoint)
|
||||||
|
).transpose(1, 2).contiguous() if self.npoint is not None else None
|
||||||
|
|
||||||
|
for i in range(len(self.groupers)):
|
||||||
|
new_features = self.groupers[i](xyz, new_xyz, features) # (B, C, npoint, nsample)
|
||||||
|
|
||||||
|
new_features = self.mlps[i](new_features) # (B, mlp[-1], npoint, nsample)
|
||||||
|
|
||||||
|
if self.pool_method == 'max_pool':
|
||||||
|
new_features = F.max_pool2d(
|
||||||
|
new_features, kernel_size=[1, new_features.size(3)]
|
||||||
|
) # (B, mlp[-1], npoint, 1)
|
||||||
|
elif self.pool_method == 'avg_pool':
|
||||||
|
new_features = F.avg_pool2d(
|
||||||
|
new_features, kernel_size=[1, new_features.size(3)]
|
||||||
|
) # (B, mlp[-1], npoint, 1)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
new_features = new_features.squeeze(-1) # (B, mlp[-1], npoint)
|
||||||
|
new_features_list.append(new_features)
|
||||||
|
|
||||||
|
return new_xyz, torch.cat(new_features_list, dim=1)
|
||||||
|
|
||||||
|
|
||||||
|
class PointnetSAModuleMSG(_PointnetSAModuleBase):
|
||||||
|
"""Pointnet set abstraction layer with multiscale grouping"""
|
||||||
|
|
||||||
|
def __init__(self, *, npoint: int, radii: List[float], nsamples: List[int], mlps: List[List[int]], bn: bool = True,
|
||||||
|
use_xyz: bool = True, pool_method='max_pool', instance_norm=False):
|
||||||
|
"""
|
||||||
|
:param npoint: int
|
||||||
|
:param radii: list of float, list of radii to group with
|
||||||
|
:param nsamples: list of int, number of samples in each ball query
|
||||||
|
:param mlps: list of list of int, spec of the pointnet before the global pooling for each scale
|
||||||
|
:param bn: whether to use batchnorm
|
||||||
|
:param use_xyz:
|
||||||
|
:param pool_method: max_pool / avg_pool
|
||||||
|
:param instance_norm: whether to use instance_norm
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
assert len(radii) == len(nsamples) == len(mlps)
|
||||||
|
|
||||||
|
self.npoint = npoint
|
||||||
|
self.groupers = nn.ModuleList()
|
||||||
|
self.mlps = nn.ModuleList()
|
||||||
|
for i in range(len(radii)):
|
||||||
|
radius = radii[i]
|
||||||
|
nsample = nsamples[i]
|
||||||
|
self.groupers.append(
|
||||||
|
pointnet2_utils.QueryAndGroup(radius, nsample, use_xyz=use_xyz)
|
||||||
|
if npoint is not None else pointnet2_utils.GroupAll(use_xyz)
|
||||||
|
)
|
||||||
|
mlp_spec = mlps[i]
|
||||||
|
if use_xyz:
|
||||||
|
mlp_spec[0] += 3
|
||||||
|
|
||||||
|
self.mlps.append(pt_utils.SharedMLP(mlp_spec, bn=bn, instance_norm=instance_norm))
|
||||||
|
self.pool_method = pool_method
|
||||||
|
|
||||||
|
|
||||||
|
class PointnetSAModule(PointnetSAModuleMSG):
|
||||||
|
"""Pointnet set abstraction layer"""
|
||||||
|
|
||||||
|
def __init__(self, *, mlp: List[int], npoint: int = None, radius: float = None, nsample: int = None,
|
||||||
|
bn: bool = True, use_xyz: bool = True, pool_method='max_pool', instance_norm=False):
|
||||||
|
"""
|
||||||
|
:param mlp: list of int, spec of the pointnet before the global max_pool
|
||||||
|
:param npoint: int, number of features
|
||||||
|
:param radius: float, radius of ball
|
||||||
|
:param nsample: int, number of samples in the ball query
|
||||||
|
:param bn: whether to use batchnorm
|
||||||
|
:param use_xyz:
|
||||||
|
:param pool_method: max_pool / avg_pool
|
||||||
|
:param instance_norm: whether to use instance_norm
|
||||||
|
"""
|
||||||
|
super().__init__(
|
||||||
|
mlps=[mlp], npoint=npoint, radii=[radius], nsamples=[nsample], bn=bn, use_xyz=use_xyz,
|
||||||
|
pool_method=pool_method, instance_norm=instance_norm
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PointnetFPModule(nn.Module):
|
||||||
|
r"""Propigates the features of one set to another"""
|
||||||
|
|
||||||
|
def __init__(self, *, mlp: List[int], bn: bool = True):
|
||||||
|
"""
|
||||||
|
:param mlp: list of int
|
||||||
|
:param bn: whether to use batchnorm
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
self.mlp = pt_utils.SharedMLP(mlp, bn=bn)
|
||||||
|
|
||||||
|
def forward(
|
||||||
|
self, unknown: torch.Tensor, known: torch.Tensor, unknow_feats: torch.Tensor, known_feats: torch.Tensor
|
||||||
|
) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
:param unknown: (B, n, 3) tensor of the xyz positions of the unknown features
|
||||||
|
:param known: (B, m, 3) tensor of the xyz positions of the known features
|
||||||
|
:param unknow_feats: (B, C1, n) tensor of the features to be propigated to
|
||||||
|
:param known_feats: (B, C2, m) tensor of features to be propigated
|
||||||
|
:return:
|
||||||
|
new_features: (B, mlp[-1], n) tensor of the features of the unknown features
|
||||||
|
"""
|
||||||
|
if known is not None:
|
||||||
|
dist, idx = pointnet2_utils.three_nn(unknown, known)
|
||||||
|
dist_recip = 1.0 / (dist + 1e-8)
|
||||||
|
norm = torch.sum(dist_recip, dim=2, keepdim=True)
|
||||||
|
weight = dist_recip / norm
|
||||||
|
|
||||||
|
interpolated_feats = pointnet2_utils.three_interpolate(known_feats, idx, weight)
|
||||||
|
else:
|
||||||
|
interpolated_feats = known_feats.expand(*known_feats.size()[0:2], unknown.size(1))
|
||||||
|
|
||||||
|
if unknow_feats is not None:
|
||||||
|
new_features = torch.cat([interpolated_feats, unknow_feats], dim=1) # (B, C2 + C1, n)
|
||||||
|
else:
|
||||||
|
new_features = interpolated_feats
|
||||||
|
|
||||||
|
new_features = new_features.unsqueeze(-1)
|
||||||
|
|
||||||
|
new_features = self.mlp(new_features)
|
||||||
|
|
||||||
|
return new_features.squeeze(-1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
pass
|
291
modules/module_lib/pointnet2_utils.py
Normal file
291
modules/module_lib/pointnet2_utils.py
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
import torch
|
||||||
|
from torch.autograd import Variable
|
||||||
|
from torch.autograd import Function
|
||||||
|
import torch.nn as nn
|
||||||
|
from typing import Tuple
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pointnet2_cuda as pointnet2
|
||||||
|
|
||||||
|
|
||||||
|
class FurthestPointSampling(Function):
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, xyz: torch.Tensor, npoint: int) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
Uses iterative furthest point sampling to select a set of npoint features that have the largest
|
||||||
|
minimum distance
|
||||||
|
:param ctx:
|
||||||
|
:param xyz: (B, N, 3) where N > npoint
|
||||||
|
:param npoint: int, number of features in the sampled set
|
||||||
|
:return:
|
||||||
|
output: (B, npoint) tensor containing the set
|
||||||
|
"""
|
||||||
|
assert xyz.is_contiguous()
|
||||||
|
|
||||||
|
B, N, _ = xyz.size()
|
||||||
|
output = torch.cuda.IntTensor(B, npoint)
|
||||||
|
temp = torch.cuda.FloatTensor(B, N).fill_(1e10)
|
||||||
|
|
||||||
|
pointnet2.furthest_point_sampling_wrapper(B, N, npoint, xyz, temp, output)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(xyz, a=None):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
furthest_point_sample = FurthestPointSampling.apply
|
||||||
|
|
||||||
|
|
||||||
|
class GatherOperation(Function):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, features: torch.Tensor, idx: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
:param ctx:
|
||||||
|
:param features: (B, C, N)
|
||||||
|
:param idx: (B, npoint) index tensor of the features to gather
|
||||||
|
:return:
|
||||||
|
output: (B, C, npoint)
|
||||||
|
"""
|
||||||
|
assert features.is_contiguous()
|
||||||
|
assert idx.is_contiguous()
|
||||||
|
|
||||||
|
B, npoint = idx.size()
|
||||||
|
_, C, N = features.size()
|
||||||
|
output = torch.cuda.FloatTensor(B, C, npoint)
|
||||||
|
|
||||||
|
pointnet2.gather_points_wrapper(B, C, N, npoint, features, idx, output)
|
||||||
|
|
||||||
|
ctx.for_backwards = (idx, C, N)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(ctx, grad_out):
|
||||||
|
idx, C, N = ctx.for_backwards
|
||||||
|
B, npoint = idx.size()
|
||||||
|
|
||||||
|
grad_features = Variable(torch.cuda.FloatTensor(B, C, N).zero_())
|
||||||
|
grad_out_data = grad_out.data.contiguous()
|
||||||
|
pointnet2.gather_points_grad_wrapper(B, C, N, npoint, grad_out_data, idx, grad_features.data)
|
||||||
|
return grad_features, None
|
||||||
|
|
||||||
|
|
||||||
|
gather_operation = GatherOperation.apply
|
||||||
|
|
||||||
|
|
||||||
|
class ThreeNN(Function):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, unknown: torch.Tensor, known: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||||
|
"""
|
||||||
|
Find the three nearest neighbors of unknown in known
|
||||||
|
:param ctx:
|
||||||
|
:param unknown: (B, N, 3)
|
||||||
|
:param known: (B, M, 3)
|
||||||
|
:return:
|
||||||
|
dist: (B, N, 3) l2 distance to the three nearest neighbors
|
||||||
|
idx: (B, N, 3) index of 3 nearest neighbors
|
||||||
|
"""
|
||||||
|
assert unknown.is_contiguous()
|
||||||
|
assert known.is_contiguous()
|
||||||
|
|
||||||
|
B, N, _ = unknown.size()
|
||||||
|
m = known.size(1)
|
||||||
|
dist2 = torch.cuda.FloatTensor(B, N, 3)
|
||||||
|
idx = torch.cuda.IntTensor(B, N, 3)
|
||||||
|
|
||||||
|
pointnet2.three_nn_wrapper(B, N, m, unknown, known, dist2, idx)
|
||||||
|
return torch.sqrt(dist2), idx
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(ctx, a=None, b=None):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
three_nn = ThreeNN.apply
|
||||||
|
|
||||||
|
|
||||||
|
class ThreeInterpolate(Function):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, features: torch.Tensor, idx: torch.Tensor, weight: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
Performs weight linear interpolation on 3 features
|
||||||
|
:param ctx:
|
||||||
|
:param features: (B, C, M) Features descriptors to be interpolated from
|
||||||
|
:param idx: (B, n, 3) three nearest neighbors of the target features in features
|
||||||
|
:param weight: (B, n, 3) weights
|
||||||
|
:return:
|
||||||
|
output: (B, C, N) tensor of the interpolated features
|
||||||
|
"""
|
||||||
|
assert features.is_contiguous()
|
||||||
|
assert idx.is_contiguous()
|
||||||
|
assert weight.is_contiguous()
|
||||||
|
|
||||||
|
B, c, m = features.size()
|
||||||
|
n = idx.size(1)
|
||||||
|
ctx.three_interpolate_for_backward = (idx, weight, m)
|
||||||
|
output = torch.cuda.FloatTensor(B, c, n)
|
||||||
|
|
||||||
|
pointnet2.three_interpolate_wrapper(B, c, m, n, features, idx, weight, output)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(ctx, grad_out: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||||
|
"""
|
||||||
|
:param ctx:
|
||||||
|
:param grad_out: (B, C, N) tensor with gradients of outputs
|
||||||
|
:return:
|
||||||
|
grad_features: (B, C, M) tensor with gradients of features
|
||||||
|
None:
|
||||||
|
None:
|
||||||
|
"""
|
||||||
|
idx, weight, m = ctx.three_interpolate_for_backward
|
||||||
|
B, c, n = grad_out.size()
|
||||||
|
|
||||||
|
grad_features = Variable(torch.cuda.FloatTensor(B, c, m).zero_())
|
||||||
|
grad_out_data = grad_out.data.contiguous()
|
||||||
|
|
||||||
|
pointnet2.three_interpolate_grad_wrapper(B, c, n, m, grad_out_data, idx, weight, grad_features.data)
|
||||||
|
return grad_features, None, None
|
||||||
|
|
||||||
|
|
||||||
|
three_interpolate = ThreeInterpolate.apply
|
||||||
|
|
||||||
|
|
||||||
|
class GroupingOperation(Function):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, features: torch.Tensor, idx: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
:param ctx:
|
||||||
|
:param features: (B, C, N) tensor of features to group
|
||||||
|
:param idx: (B, npoint, nsample) tensor containing the indicies of features to group with
|
||||||
|
:return:
|
||||||
|
output: (B, C, npoint, nsample) tensor
|
||||||
|
"""
|
||||||
|
assert features.is_contiguous()
|
||||||
|
assert idx.is_contiguous()
|
||||||
|
|
||||||
|
B, nfeatures, nsample = idx.size()
|
||||||
|
_, C, N = features.size()
|
||||||
|
output = torch.cuda.FloatTensor(B, C, nfeatures, nsample)
|
||||||
|
|
||||||
|
pointnet2.group_points_wrapper(B, C, N, nfeatures, nsample, features, idx, output)
|
||||||
|
|
||||||
|
ctx.for_backwards = (idx, N)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(ctx, grad_out: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||||
|
"""
|
||||||
|
:param ctx:
|
||||||
|
:param grad_out: (B, C, npoint, nsample) tensor of the gradients of the output from forward
|
||||||
|
:return:
|
||||||
|
grad_features: (B, C, N) gradient of the features
|
||||||
|
"""
|
||||||
|
idx, N = ctx.for_backwards
|
||||||
|
|
||||||
|
B, C, npoint, nsample = grad_out.size()
|
||||||
|
grad_features = Variable(torch.cuda.FloatTensor(B, C, N).zero_())
|
||||||
|
|
||||||
|
grad_out_data = grad_out.data.contiguous()
|
||||||
|
pointnet2.group_points_grad_wrapper(B, C, N, npoint, nsample, grad_out_data, idx, grad_features.data)
|
||||||
|
return grad_features, None
|
||||||
|
|
||||||
|
|
||||||
|
grouping_operation = GroupingOperation.apply
|
||||||
|
|
||||||
|
|
||||||
|
class BallQuery(Function):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def forward(ctx, radius: float, nsample: int, xyz: torch.Tensor, new_xyz: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""
|
||||||
|
:param ctx:
|
||||||
|
:param radius: float, radius of the balls
|
||||||
|
:param nsample: int, maximum number of features in the balls
|
||||||
|
:param xyz: (B, N, 3) xyz coordinates of the features
|
||||||
|
:param new_xyz: (B, npoint, 3) centers of the ball query
|
||||||
|
:return:
|
||||||
|
idx: (B, npoint, nsample) tensor with the indicies of the features that form the query balls
|
||||||
|
"""
|
||||||
|
assert new_xyz.is_contiguous()
|
||||||
|
assert xyz.is_contiguous()
|
||||||
|
|
||||||
|
B, N, _ = xyz.size()
|
||||||
|
npoint = new_xyz.size(1)
|
||||||
|
idx = torch.cuda.IntTensor(B, npoint, nsample).zero_()
|
||||||
|
|
||||||
|
pointnet2.ball_query_wrapper(B, N, npoint, radius, nsample, new_xyz, xyz, idx)
|
||||||
|
return idx
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backward(ctx, a=None):
|
||||||
|
return None, None, None, None
|
||||||
|
|
||||||
|
|
||||||
|
ball_query = BallQuery.apply
|
||||||
|
|
||||||
|
|
||||||
|
class QueryAndGroup(nn.Module):
|
||||||
|
def __init__(self, radius: float, nsample: int, use_xyz: bool = True):
|
||||||
|
"""
|
||||||
|
:param radius: float, radius of ball
|
||||||
|
:param nsample: int, maximum number of features to gather in the ball
|
||||||
|
:param use_xyz:
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
self.radius, self.nsample, self.use_xyz = radius, nsample, use_xyz
|
||||||
|
|
||||||
|
def forward(self, xyz: torch.Tensor, new_xyz: torch.Tensor, features: torch.Tensor = None) -> Tuple[torch.Tensor]:
|
||||||
|
"""
|
||||||
|
:param xyz: (B, N, 3) xyz coordinates of the features
|
||||||
|
:param new_xyz: (B, npoint, 3) centroids
|
||||||
|
:param features: (B, C, N) descriptors of the features
|
||||||
|
:return:
|
||||||
|
new_features: (B, 3 + C, npoint, nsample)
|
||||||
|
"""
|
||||||
|
idx = ball_query(self.radius, self.nsample, xyz, new_xyz)
|
||||||
|
xyz_trans = xyz.transpose(1, 2).contiguous()
|
||||||
|
grouped_xyz = grouping_operation(xyz_trans, idx) # (B, 3, npoint, nsample)
|
||||||
|
grouped_xyz -= new_xyz.transpose(1, 2).unsqueeze(-1)
|
||||||
|
|
||||||
|
if features is not None:
|
||||||
|
grouped_features = grouping_operation(features, idx)
|
||||||
|
if self.use_xyz:
|
||||||
|
new_features = torch.cat([grouped_xyz, grouped_features], dim=1) # (B, C + 3, npoint, nsample)
|
||||||
|
else:
|
||||||
|
new_features = grouped_features
|
||||||
|
else:
|
||||||
|
assert self.use_xyz, "Cannot have not features and not use xyz as a feature!"
|
||||||
|
new_features = grouped_xyz
|
||||||
|
|
||||||
|
return new_features
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAll(nn.Module):
|
||||||
|
def __init__(self, use_xyz: bool = True):
|
||||||
|
super().__init__()
|
||||||
|
self.use_xyz = use_xyz
|
||||||
|
|
||||||
|
def forward(self, xyz: torch.Tensor, new_xyz: torch.Tensor, features: torch.Tensor = None):
|
||||||
|
"""
|
||||||
|
:param xyz: (B, N, 3) xyz coordinates of the features
|
||||||
|
:param new_xyz: ignored
|
||||||
|
:param features: (B, C, N) descriptors of the features
|
||||||
|
:return:
|
||||||
|
new_features: (B, C + 3, 1, N)
|
||||||
|
"""
|
||||||
|
grouped_xyz = xyz.transpose(1, 2).unsqueeze(2)
|
||||||
|
if features is not None:
|
||||||
|
grouped_features = features.unsqueeze(2)
|
||||||
|
if self.use_xyz:
|
||||||
|
new_features = torch.cat([grouped_xyz, grouped_features], dim=1) # (B, 3 + C, 1, N)
|
||||||
|
else:
|
||||||
|
new_features = grouped_features
|
||||||
|
else:
|
||||||
|
new_features = grouped_xyz
|
||||||
|
|
||||||
|
return new_features
|
236
modules/module_lib/pytorch_utils.py
Normal file
236
modules/module_lib/pytorch_utils.py
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import torch.nn as nn
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class SharedMLP(nn.Sequential):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
args: List[int],
|
||||||
|
*,
|
||||||
|
bn: bool = False,
|
||||||
|
activation=nn.ReLU(inplace=True),
|
||||||
|
preact: bool = False,
|
||||||
|
first: bool = False,
|
||||||
|
name: str = "",
|
||||||
|
instance_norm: bool = False,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
for i in range(len(args) - 1):
|
||||||
|
self.add_module(
|
||||||
|
name + 'layer{}'.format(i),
|
||||||
|
Conv2d(
|
||||||
|
args[i],
|
||||||
|
args[i + 1],
|
||||||
|
bn=(not first or not preact or (i != 0)) and bn,
|
||||||
|
activation=activation
|
||||||
|
if (not first or not preact or (i != 0)) else None,
|
||||||
|
preact=preact,
|
||||||
|
instance_norm=instance_norm
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _ConvBase(nn.Sequential):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_size,
|
||||||
|
out_size,
|
||||||
|
kernel_size,
|
||||||
|
stride,
|
||||||
|
padding,
|
||||||
|
activation,
|
||||||
|
bn,
|
||||||
|
init,
|
||||||
|
conv=None,
|
||||||
|
batch_norm=None,
|
||||||
|
bias=True,
|
||||||
|
preact=False,
|
||||||
|
name="",
|
||||||
|
instance_norm=False,
|
||||||
|
instance_norm_func=None
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
bias = bias and (not bn)
|
||||||
|
conv_unit = conv(
|
||||||
|
in_size,
|
||||||
|
out_size,
|
||||||
|
kernel_size=kernel_size,
|
||||||
|
stride=stride,
|
||||||
|
padding=padding,
|
||||||
|
bias=bias
|
||||||
|
)
|
||||||
|
init(conv_unit.weight)
|
||||||
|
if bias:
|
||||||
|
nn.init.constant_(conv_unit.bias, 0)
|
||||||
|
|
||||||
|
if bn:
|
||||||
|
if not preact:
|
||||||
|
bn_unit = batch_norm(out_size)
|
||||||
|
else:
|
||||||
|
bn_unit = batch_norm(in_size)
|
||||||
|
if instance_norm:
|
||||||
|
if not preact:
|
||||||
|
in_unit = instance_norm_func(out_size, affine=False, track_running_stats=False)
|
||||||
|
else:
|
||||||
|
in_unit = instance_norm_func(in_size, affine=False, track_running_stats=False)
|
||||||
|
|
||||||
|
if preact:
|
||||||
|
if bn:
|
||||||
|
self.add_module(name + 'bn', bn_unit)
|
||||||
|
|
||||||
|
if activation is not None:
|
||||||
|
self.add_module(name + 'activation', activation)
|
||||||
|
|
||||||
|
if not bn and instance_norm:
|
||||||
|
self.add_module(name + 'in', in_unit)
|
||||||
|
|
||||||
|
self.add_module(name + 'conv', conv_unit)
|
||||||
|
|
||||||
|
if not preact:
|
||||||
|
if bn:
|
||||||
|
self.add_module(name + 'bn', bn_unit)
|
||||||
|
|
||||||
|
if activation is not None:
|
||||||
|
self.add_module(name + 'activation', activation)
|
||||||
|
|
||||||
|
if not bn and instance_norm:
|
||||||
|
self.add_module(name + 'in', in_unit)
|
||||||
|
|
||||||
|
|
||||||
|
class _BNBase(nn.Sequential):
|
||||||
|
|
||||||
|
def __init__(self, in_size, batch_norm=None, name=""):
|
||||||
|
super().__init__()
|
||||||
|
self.add_module(name + "bn", batch_norm(in_size))
|
||||||
|
|
||||||
|
nn.init.constant_(self[0].weight, 1.0)
|
||||||
|
nn.init.constant_(self[0].bias, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class BatchNorm1d(_BNBase):
|
||||||
|
|
||||||
|
def __init__(self, in_size: int, *, name: str = ""):
|
||||||
|
super().__init__(in_size, batch_norm=nn.BatchNorm1d, name=name)
|
||||||
|
|
||||||
|
|
||||||
|
class BatchNorm2d(_BNBase):
|
||||||
|
|
||||||
|
def __init__(self, in_size: int, name: str = ""):
|
||||||
|
super().__init__(in_size, batch_norm=nn.BatchNorm2d, name=name)
|
||||||
|
|
||||||
|
|
||||||
|
class Conv1d(_ConvBase):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_size: int,
|
||||||
|
out_size: int,
|
||||||
|
*,
|
||||||
|
kernel_size: int = 1,
|
||||||
|
stride: int = 1,
|
||||||
|
padding: int = 0,
|
||||||
|
activation=nn.ReLU(inplace=True),
|
||||||
|
bn: bool = False,
|
||||||
|
init=nn.init.kaiming_normal_,
|
||||||
|
bias: bool = True,
|
||||||
|
preact: bool = False,
|
||||||
|
name: str = "",
|
||||||
|
instance_norm=False
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
in_size,
|
||||||
|
out_size,
|
||||||
|
kernel_size,
|
||||||
|
stride,
|
||||||
|
padding,
|
||||||
|
activation,
|
||||||
|
bn,
|
||||||
|
init,
|
||||||
|
conv=nn.Conv1d,
|
||||||
|
batch_norm=BatchNorm1d,
|
||||||
|
bias=bias,
|
||||||
|
preact=preact,
|
||||||
|
name=name,
|
||||||
|
instance_norm=instance_norm,
|
||||||
|
instance_norm_func=nn.InstanceNorm1d
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Conv2d(_ConvBase):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_size: int,
|
||||||
|
out_size: int,
|
||||||
|
*,
|
||||||
|
kernel_size: Tuple[int, int] = (1, 1),
|
||||||
|
stride: Tuple[int, int] = (1, 1),
|
||||||
|
padding: Tuple[int, int] = (0, 0),
|
||||||
|
activation=nn.ReLU(inplace=True),
|
||||||
|
bn: bool = False,
|
||||||
|
init=nn.init.kaiming_normal_,
|
||||||
|
bias: bool = True,
|
||||||
|
preact: bool = False,
|
||||||
|
name: str = "",
|
||||||
|
instance_norm=False
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
in_size,
|
||||||
|
out_size,
|
||||||
|
kernel_size,
|
||||||
|
stride,
|
||||||
|
padding,
|
||||||
|
activation,
|
||||||
|
bn,
|
||||||
|
init,
|
||||||
|
conv=nn.Conv2d,
|
||||||
|
batch_norm=BatchNorm2d,
|
||||||
|
bias=bias,
|
||||||
|
preact=preact,
|
||||||
|
name=name,
|
||||||
|
instance_norm=instance_norm,
|
||||||
|
instance_norm_func=nn.InstanceNorm2d
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FC(nn.Sequential):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_size: int,
|
||||||
|
out_size: int,
|
||||||
|
*,
|
||||||
|
activation=nn.ReLU(inplace=True),
|
||||||
|
bn: bool = False,
|
||||||
|
init=None,
|
||||||
|
preact: bool = False,
|
||||||
|
name: str = ""
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
fc = nn.Linear(in_size, out_size, bias=not bn)
|
||||||
|
if init is not None:
|
||||||
|
init(fc.weight)
|
||||||
|
if not bn:
|
||||||
|
nn.init.constant(fc.bias, 0)
|
||||||
|
|
||||||
|
if preact:
|
||||||
|
if bn:
|
||||||
|
self.add_module(name + 'bn', BatchNorm1d(in_size))
|
||||||
|
|
||||||
|
if activation is not None:
|
||||||
|
self.add_module(name + 'activation', activation)
|
||||||
|
|
||||||
|
self.add_module(name + 'fc', fc)
|
||||||
|
|
||||||
|
if not preact:
|
||||||
|
if bn:
|
||||||
|
self.add_module(name + 'bn', BatchNorm1d(out_size))
|
||||||
|
|
||||||
|
if activation is not None:
|
||||||
|
self.add_module(name + 'activation', activation)
|
||||||
|
|
121
modules/pointnet++_encoder.py
Normal file
121
modules/pointnet++_encoder.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
path = os.path.abspath(__file__)
|
||||||
|
for i in range(2):
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
PROJECT_ROOT = path
|
||||||
|
sys.path.append(PROJECT_ROOT)
|
||||||
|
import PytorchBoot.stereotype as stereotype
|
||||||
|
from modules.module_lib.pointnet2_modules import PointnetSAModuleMSG
|
||||||
|
|
||||||
|
|
||||||
|
ClsMSG_CFG_Dense = {
|
||||||
|
'NPOINTS': [512, 256, 128, None],
|
||||||
|
'RADIUS': [[0.02, 0.04], [0.04, 0.08], [0.08, 0.16], [None, None]],
|
||||||
|
'NSAMPLE': [[32, 64], [16, 32], [8, 16], [None, None]],
|
||||||
|
'MLPS': [[[16, 16, 32], [32, 32, 64]],
|
||||||
|
[[64, 64, 128], [64, 96, 128]],
|
||||||
|
[[128, 196, 256], [128, 196, 256]],
|
||||||
|
[[256, 256, 512], [256, 384, 512]]],
|
||||||
|
'DP_RATIO': 0.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
ClsMSG_CFG_Light = {
|
||||||
|
'NPOINTS': [512, 256, 128, None],
|
||||||
|
'RADIUS': [[0.02, 0.04], [0.04, 0.08], [0.08, 0.16], [None, None]],
|
||||||
|
'NSAMPLE': [[16, 32], [16, 32], [16, 32], [None, None]],
|
||||||
|
'MLPS': [[[16, 16, 32], [32, 32, 64]],
|
||||||
|
[[64, 64, 128], [64, 96, 128]],
|
||||||
|
[[128, 196, 256], [128, 196, 256]],
|
||||||
|
[[256, 256, 512], [256, 384, 512]]],
|
||||||
|
'DP_RATIO': 0.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
ClsMSG_CFG_Lighter = {
|
||||||
|
'NPOINTS': [512, 256, 128, 64, None],
|
||||||
|
'RADIUS': [[0.01], [0.02], [0.04], [0.08], [None]],
|
||||||
|
'NSAMPLE': [[64], [32], [16], [8], [None]],
|
||||||
|
'MLPS': [[[32, 32, 64]],
|
||||||
|
[[64, 64, 128]],
|
||||||
|
[[128, 196, 256]],
|
||||||
|
[[256, 256, 512]],
|
||||||
|
[[512, 512, 1024]]],
|
||||||
|
'DP_RATIO': 0.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def select_params(name):
|
||||||
|
if name == 'light':
|
||||||
|
return ClsMSG_CFG_Light
|
||||||
|
elif name == 'lighter':
|
||||||
|
return ClsMSG_CFG_Lighter
|
||||||
|
elif name == 'dense':
|
||||||
|
return ClsMSG_CFG_Dense
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def break_up_pc(pc):
|
||||||
|
xyz = pc[..., 0:3].contiguous()
|
||||||
|
features = (
|
||||||
|
pc[..., 3:].transpose(1, 2).contiguous()
|
||||||
|
if pc.size(-1) > 3 else None
|
||||||
|
)
|
||||||
|
|
||||||
|
return xyz, features
|
||||||
|
|
||||||
|
|
||||||
|
@stereotype.module("pointnet++_encoder")
|
||||||
|
class PointNet2Encoder(nn.Module):
|
||||||
|
def encode_points(self, pts, require_per_point_feat=False):
|
||||||
|
return self.forward(pts)
|
||||||
|
|
||||||
|
def __init__(self, config:dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
channel_in = config.get("in_dim", 3) - 3
|
||||||
|
params_name = config.get("params_name", "light")
|
||||||
|
|
||||||
|
self.SA_modules = nn.ModuleList()
|
||||||
|
selected_params = select_params(params_name)
|
||||||
|
for k in range(selected_params['NPOINTS'].__len__()):
|
||||||
|
mlps = selected_params['MLPS'][k].copy()
|
||||||
|
channel_out = 0
|
||||||
|
for idx in range(mlps.__len__()):
|
||||||
|
mlps[idx] = [channel_in] + mlps[idx]
|
||||||
|
channel_out += mlps[idx][-1]
|
||||||
|
|
||||||
|
self.SA_modules.append(
|
||||||
|
PointnetSAModuleMSG(
|
||||||
|
npoint=selected_params['NPOINTS'][k],
|
||||||
|
radii=selected_params['RADIUS'][k],
|
||||||
|
nsamples=selected_params['NSAMPLE'][k],
|
||||||
|
mlps=mlps,
|
||||||
|
use_xyz=True,
|
||||||
|
bn=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
channel_in = channel_out
|
||||||
|
|
||||||
|
def forward(self, point_cloud: torch.cuda.FloatTensor):
|
||||||
|
xyz, features = break_up_pc(point_cloud)
|
||||||
|
|
||||||
|
l_xyz, l_features = [xyz], [features]
|
||||||
|
for i in range(len(self.SA_modules)):
|
||||||
|
li_xyz, li_features = self.SA_modules[i](l_xyz[i], l_features[i])
|
||||||
|
l_xyz.append(li_xyz)
|
||||||
|
l_features.append(li_features)
|
||||||
|
return l_features[-1].squeeze(-1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
seed = 100
|
||||||
|
torch.manual_seed(seed)
|
||||||
|
torch.cuda.manual_seed(seed)
|
||||||
|
net = PointNet2Encoder(config={"in_dim": 3, "params_name": "light"}).cuda()
|
||||||
|
pts = torch.randn(2, 1024, 3).cuda()
|
||||||
|
print(torch.mean(pts, dim=1))
|
||||||
|
pre = net.encode_points(pts)
|
||||||
|
print(pre.shape)
|
@ -142,6 +142,7 @@ class Inferencer(Runner):
|
|||||||
voxel_downsampled_combined_scanned_pts_np, inverse = self.voxel_downsample_with_mapping(combined_scanned_pts, voxel_threshold)
|
voxel_downsampled_combined_scanned_pts_np, inverse = self.voxel_downsample_with_mapping(combined_scanned_pts, voxel_threshold)
|
||||||
output = self.pipeline(input_data)
|
output = self.pipeline(input_data)
|
||||||
pred_pose_9d = output["pred_pose_9d"]
|
pred_pose_9d = output["pred_pose_9d"]
|
||||||
|
import ipdb; ipdb.set_trace()
|
||||||
pred_pose = torch.eye(4, device=pred_pose_9d.device)
|
pred_pose = torch.eye(4, device=pred_pose_9d.device)
|
||||||
|
|
||||||
pred_pose[:3,:3] = PoseUtil.rotation_6d_to_matrix_tensor_batch(pred_pose_9d[:,:6])[0]
|
pred_pose[:3,:3] = PoseUtil.rotation_6d_to_matrix_tensor_batch(pred_pose_9d[:,:6])[0]
|
||||||
|
@ -84,7 +84,6 @@ class RenderUtil:
|
|||||||
params_data_path = os.path.join(temp_dir, "params.json")
|
params_data_path = os.path.join(temp_dir, "params.json")
|
||||||
with open(params_data_path, 'w') as f:
|
with open(params_data_path, 'w') as f:
|
||||||
json.dump(params, f)
|
json.dump(params, f)
|
||||||
#import ipdb; ipdb.set_trace()
|
|
||||||
result = subprocess.run([
|
result = subprocess.run([
|
||||||
'/home/hofee/blender-4.0.2-linux-x64/blender', '-b', '-P', script_path, '--', temp_dir
|
'/home/hofee/blender-4.0.2-linux-x64/blender', '-b', '-P', script_path, '--', temp_dir
|
||||||
], capture_output=True, text=True)
|
], capture_output=True, text=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user