|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
import argparse |
|
|
import numpy as np |
|
|
from urllib.request import urlretrieve |
|
|
try: |
|
|
import open3d as o3d |
|
|
except ImportError: |
|
|
raise ImportError('Please install open3d with `pip install open3d`.') |
|
|
|
|
|
import torch |
|
|
import MinkowskiEngine as ME |
|
|
from examples.common import Timer |
|
|
|
|
|
|
|
|
if not os.path.isfile('1.ply'): |
|
|
print('Downloading a room ply file...') |
|
|
urlretrieve("http://cvgl.stanford.edu/data2/minkowskiengine/1.ply", '1.ply') |
|
|
|
|
|
parser = argparse.ArgumentParser() |
|
|
parser.add_argument('--file_name', type=str, default='1.ply') |
|
|
parser.add_argument('--voxel_size', type=float, default=0.02) |
|
|
parser.add_argument('--batch_size', type=int, default=2) |
|
|
parser.add_argument('--max_kernel_size', type=int, default=7) |
|
|
|
|
|
|
|
|
def load_file(file_name, voxel_size): |
|
|
pcd = o3d.io.read_point_cloud(file_name) |
|
|
coords = np.array(pcd.points) |
|
|
feats = np.array(pcd.colors) |
|
|
|
|
|
quantized_coords = np.floor(coords / voxel_size) |
|
|
unique_coords, unique_feats = ME.utils.sparse_quantize(quantized_coords, feats) |
|
|
return unique_coords, unique_feats, pcd |
|
|
|
|
|
|
|
|
def generate_input_sparse_tensor(file_name, voxel_size=0.05, batch_size=1): |
|
|
|
|
|
batch = [ |
|
|
load_file(file_name, voxel_size), |
|
|
] * batch_size |
|
|
coordinates_, featrues_, pcds = list(zip(*batch)) |
|
|
coordinates, features = ME.utils.sparse_collate(coordinates_, featrues_) |
|
|
|
|
|
|
|
|
return features, coordinates |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
config = parser.parse_args() |
|
|
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
|
|
|
|
|
|
|
|
feats = [3, 8, 16, 32, 64, 128] |
|
|
features, coordinates = generate_input_sparse_tensor( |
|
|
config.file_name, |
|
|
voxel_size=config.voxel_size, |
|
|
batch_size=config.batch_size) |
|
|
pool = ME.MinkowskiGlobalAvgPooling() |
|
|
|
|
|
|
|
|
print('Forward') |
|
|
for feat in feats: |
|
|
timer = Timer() |
|
|
features = torch.rand(len(coordinates), feat).to(device) |
|
|
|
|
|
|
|
|
for i in range(20): |
|
|
sinput = ME.SparseTensor(features, coordinates=coordinates, device=device) |
|
|
|
|
|
timer.tic() |
|
|
soutput = pool(sinput) |
|
|
timer.toc() |
|
|
print( |
|
|
f'{timer.min_time:.12f} for feature size: {feat} with {len(sinput)} voxel' |
|
|
) |
|
|
|
|
|
print('Backward') |
|
|
for feat in feats: |
|
|
timer = Timer() |
|
|
sinput._F = torch.rand(len(sinput), feat).to(device).requires_grad_() |
|
|
soutput = pool(sinput) |
|
|
loss = soutput.F.sum() |
|
|
|
|
|
for i in range(20): |
|
|
timer.tic() |
|
|
loss.backward() |
|
|
timer.toc() |
|
|
print( |
|
|
f'{timer.min_time:.12f} for feature size {feat} with {len(sinput)} voxel' |
|
|
) |
|
|
|