|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 MinkowskiCommon import convert_to_int_list |
|
|
import examples.minkunet as UNets |
|
|
from tests.python.common import data_loader, load_file, batched_coordinates |
|
|
from examples.common import Timer |
|
|
|
|
|
|
|
|
if not os.path.isfile("weights.pth"): |
|
|
print("Downloading weights and a room ply file...") |
|
|
urlretrieve( |
|
|
"http://cvgl.stanford.edu/data2/minkowskiengine/weights.pth", "weights.pth" |
|
|
) |
|
|
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("--weights", type=str, default="weights.pth") |
|
|
parser.add_argument("--use_cpu", action="store_true") |
|
|
parser.add_argument("--backward", action="store_true") |
|
|
parser.add_argument("--max_batch", type=int, default=12) |
|
|
|
|
|
|
|
|
def quantize(coordinates): |
|
|
D = coordinates.size(1) - 1 |
|
|
coordinate_manager = ME.CoordinateManager( |
|
|
D=D, coordinate_map_type=ME.CoordinateMapType.CPU |
|
|
) |
|
|
coordinate_map_key = ME.CoordinateMapKey(convert_to_int_list(1, D), "") |
|
|
key, (unique_map, inverse_map) = coordinate_manager.insert_and_map( |
|
|
coordinates, *coordinate_map_key.get_key() |
|
|
) |
|
|
return unique_map, inverse_map |
|
|
|
|
|
|
|
|
def load_file(file_name, voxel_size): |
|
|
pcd = o3d.io.read_point_cloud(file_name) |
|
|
coords = torch.from_numpy(np.array(pcd.points)) |
|
|
feats = torch.from_numpy(np.array(pcd.colors)).float() |
|
|
|
|
|
quantized_coords = torch.floor(coords / voxel_size).int() |
|
|
inds, inverse_inds = quantize(quantized_coords) |
|
|
|
|
|
return quantized_coords[inds], feats[inds], pcd |
|
|
|
|
|
|
|
|
def forward(coords, colors, model): |
|
|
|
|
|
timer = Timer() |
|
|
for i in range(5): |
|
|
|
|
|
timer.tic() |
|
|
sinput = ME.SparseTensor( |
|
|
features=colors, |
|
|
coordinates=coords, |
|
|
device=device, |
|
|
allocator_type=ME.GPUMemoryAllocatorType.PYTORCH, |
|
|
) |
|
|
logits = model(sinput) |
|
|
timer.toc() |
|
|
return timer.min_time, len(logits) |
|
|
|
|
|
|
|
|
def train(coords, colors, model): |
|
|
|
|
|
timer = Timer() |
|
|
for i in range(5): |
|
|
|
|
|
timer.tic() |
|
|
sinput = ME.SparseTensor( |
|
|
colors, |
|
|
coords, |
|
|
device=device, |
|
|
allocator_type=ME.GPUMemoryAllocatorType.PYTORCH, |
|
|
) |
|
|
logits = model(sinput) |
|
|
logits.F.sum().backward() |
|
|
timer.toc() |
|
|
return timer.min_time, len(logits) |
|
|
|
|
|
|
|
|
def test_network(coords, feats, model, batch_sizes, forward_only=True): |
|
|
for batch_size in batch_sizes: |
|
|
bcoords = batched_coordinates([coords for i in range(batch_size)]) |
|
|
bfeats = torch.cat([feats for i in range(batch_size)], 0) |
|
|
if forward_only: |
|
|
with torch.no_grad(): |
|
|
time, length = forward(bcoords, bfeats, model) |
|
|
else: |
|
|
time, length = train(bcoords, bfeats, model) |
|
|
|
|
|
print(f"{net.__name__}\t{voxel_size}\t{batch_size}\t{length}\t{time}") |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
config = parser.parse_args() |
|
|
device = torch.device( |
|
|
"cuda" if (torch.cuda.is_available() and not config.use_cpu) else "cpu" |
|
|
) |
|
|
print(f"Using {device}") |
|
|
print(f"Using backward {config.backward}") |
|
|
|
|
|
batch_sizes = [i for i in range(2, config.max_batch + 1, 2)] |
|
|
batch_sizes = [1, *batch_sizes] |
|
|
|
|
|
for net in [UNets.MinkUNet14, UNets.MinkUNet18, UNets.MinkUNet34, UNets.MinkUNet50]: |
|
|
model = net(3, 20).to(device) |
|
|
model.eval() |
|
|
for voxel_size in [0.02]: |
|
|
print(voxel_size) |
|
|
coords, feats, _ = load_file(config.file_name, voxel_size) |
|
|
test_network(coords, feats, model, batch_sizes, not config.backward) |
|
|
torch.cuda.empty_cache() |
|
|
del model |
|
|
|