diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1436e1a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extension"] + path = extension + url = git@github.com:ThibaultGROUEIX/chamfer_pytorch.git diff --git a/extension b/extension new file mode 160000 index 0000000..719b0f1 --- /dev/null +++ b/extension @@ -0,0 +1 @@ +Subproject commit 719b0f1ca5ba370616cb837c03ab88d9a88173ff diff --git a/extension/README.md b/extension/README.md deleted file mode 100755 index 9cae8d1..0000000 --- a/extension/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Chamfer distance timings for records - -| 50 epoch AE_Atlasnet_25prim | time(s) | memory(GB) | -| -------------------------------- | ------- | ---------- | -| without chamfer loss (just mean) | 20.46 | 4.08 | -| with pytorch chamfer | 24.86 | 8.80 | -| with CUDA chamfer | 20.90 | 4.08 | - diff --git a/extension/chamfer.cu b/extension/chamfer.cu deleted file mode 100755 index d5b886d..0000000 --- a/extension/chamfer.cu +++ /dev/null @@ -1,196 +0,0 @@ - -#include -#include - -#include -#include - -#include - - - -__global__ void NmDistanceKernel(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i){ - const int batch=512; - __shared__ float buf[batch*3]; - for (int i=blockIdx.x;ibest){ - result[(i*n+j)]=best; - result_i[(i*n+j)]=best_i; - } - } - __syncthreads(); - } - } -} -// int chamfer_cuda_forward(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i,float * result2,int * result2_i, cudaStream_t stream){ -int chamfer_cuda_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2, at::Tensor idx1, at::Tensor idx2){ - - const auto batch_size = xyz1.size(0); - const auto n = xyz1.size(1); //num_points point cloud A - const auto m = xyz2.size(1); //num_points point cloud B - - NmDistanceKernel<<>>(batch_size, n, xyz1.data(), m, xyz2.data(), dist1.data(), idx1.data()); - NmDistanceKernel<<>>(batch_size, m, xyz2.data(), n, xyz1.data(), dist2.data(), idx2.data()); - - cudaError_t err = cudaGetLastError(); - if (err != cudaSuccess) { - printf("error in nnd updateOutput: %s\n", cudaGetErrorString(err)); - //THError("aborting"); - return 0; - } - return 1; - - -} -__global__ void NmDistanceGradKernel(int b,int n,const float * xyz1,int m,const float * xyz2,const float * grad_dist1,const int * idx1,float * grad_xyz1,float * grad_xyz2){ - for (int i=blockIdx.x;i>>(batch_size,n,xyz1.data(),m,xyz2.data(),graddist1.data(),idx1.data(),gradxyz1.data(),gradxyz2.data()); - NmDistanceGradKernel<<>>(batch_size,m,xyz2.data(),n,xyz1.data(),graddist2.data(),idx2.data(),gradxyz2.data(),gradxyz1.data()); - - cudaError_t err = cudaGetLastError(); - if (err != cudaSuccess) { - printf("error in nnd get grad: %s\n", cudaGetErrorString(err)); - //THError("aborting"); - return 0; - } - return 1; - -} - diff --git a/extension/chamfer_cuda.cpp b/extension/chamfer_cuda.cpp deleted file mode 100755 index 67574e2..0000000 --- a/extension/chamfer_cuda.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -///TMP -//#include "common.h" -/// NOT TMP - - -int chamfer_cuda_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2, at::Tensor idx1, at::Tensor idx2); - - -int chamfer_cuda_backward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor gradxyz1, at::Tensor gradxyz2, at::Tensor graddist1, at::Tensor graddist2, at::Tensor idx1, at::Tensor idx2); - - - - -int chamfer_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2, at::Tensor idx1, at::Tensor idx2) { - return chamfer_cuda_forward(xyz1, xyz2, dist1, dist2, idx1, idx2); -} - - -int chamfer_backward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor gradxyz1, at::Tensor gradxyz2, at::Tensor graddist1, - at::Tensor graddist2, at::Tensor idx1, at::Tensor idx2) { - - return chamfer_cuda_backward(xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2); -} - - - -PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("forward", &chamfer_forward, "chamfer forward (CUDA)"); - m.def("backward", &chamfer_backward, "chamfer backward (CUDA)"); -} \ No newline at end of file diff --git a/extension/chamfer_python.py b/extension/chamfer_python.py deleted file mode 100644 index 3a86186..0000000 --- a/extension/chamfer_python.py +++ /dev/null @@ -1,28 +0,0 @@ -import torch - - -def pairwise_dist(x, y): - xx, yy, zz = torch.mm(x, x.t()), torch.mm(y, y.t()), torch.mm(x, y.t()) - rx = xx.diag().unsqueeze(0).expand_as(xx) - ry = yy.diag().unsqueeze(0).expand_as(yy) - P = rx.t() + ry - 2 * zz - return P - - -def NN_loss(x, y, dim=0): - dist = pairwise_dist(x, y) - values, indices = dist.min(dim=dim) - return values.mean() - - -def distChamfer(a, b): - x, y = a, b - bs, num_points, points_dim = x.size() - xx = torch.bmm(x, x.transpose(2, 1)) - yy = torch.bmm(y, y.transpose(2, 1)) - zz = torch.bmm(x, y.transpose(2, 1)) - diag_ind = torch.arange(0, num_points).type(torch.cuda.LongTensor) - rx = xx[:, diag_ind, diag_ind].unsqueeze(1).expand_as(xx) - ry = yy[:, diag_ind, diag_ind].unsqueeze(1).expand_as(yy) - P = rx.transpose(2, 1) + ry - 2 * zz - return torch.min(P, 1)[0], torch.min(P, 2)[0], torch.min(P, 1)[1], torch.min(P, 2)[1] diff --git a/extension/dist_chamfer.py b/extension/dist_chamfer.py deleted file mode 100755 index 3350304..0000000 --- a/extension/dist_chamfer.py +++ /dev/null @@ -1,54 +0,0 @@ -import math -from torch import nn -from torch.autograd import Function -import torch -import sys -from numbers import Number -from collections import Set, Mapping, deque -import chamfer - - -# Chamfer's distance module @thibaultgroueix -# GPU tensors only -class chamferFunction(Function): - @staticmethod - def forward(ctx, xyz1, xyz2): - batchsize, n, _ = xyz1.size() - _, m, _ = xyz2.size() - - dist1 = torch.zeros(batchsize, n) - dist2 = torch.zeros(batchsize, m) - - idx1 = torch.zeros(batchsize, n).type(torch.IntTensor) - idx2 = torch.zeros(batchsize, m).type(torch.IntTensor) - - dist1 = dist1.cuda() - dist2 = dist2.cuda() - idx1 = idx1.cuda() - idx2 = idx2.cuda() - - chamfer.forward(xyz1, xyz2, dist1, dist2, idx1, idx2) - ctx.save_for_backward(xyz1, xyz2, idx1, idx2) - return dist1, dist2 - - @staticmethod - def backward(ctx, graddist1, graddist2): - xyz1, xyz2, idx1, idx2 = ctx.saved_tensors - graddist1 = graddist1.contiguous() - graddist2 = graddist2.contiguous() - - gradxyz1 = torch.zeros(xyz1.size()) - gradxyz2 = torch.zeros(xyz2.size()) - - gradxyz1 = gradxyz1.cuda() - gradxyz2 = gradxyz2.cuda() - chamfer.backward(xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2) - return gradxyz1, gradxyz2 - -class chamferDist(nn.Module): - def __init__(self): - super(chamferDist, self).__init__() - - def forward(self, input1, input2): - return chamferFunction.apply(input1, input2) - diff --git a/extension/dist_chamfer_idx.py b/extension/dist_chamfer_idx.py deleted file mode 100644 index 7551bf3..0000000 --- a/extension/dist_chamfer_idx.py +++ /dev/null @@ -1,52 +0,0 @@ -from torch import nn -from torch.autograd import Function -import torch -import chamfer - - -# Chamfer's distance module @thibaultgroueix -# GPU tensors only -class chamferFunction(Function): - @staticmethod - def forward(ctx, xyz1, xyz2): - batchsize, n, _ = xyz1.size() - _, m, _ = xyz2.size() - - dist1 = torch.zeros(batchsize, n) - dist2 = torch.zeros(batchsize, m) - - idx1 = torch.zeros(batchsize, n).type(torch.IntTensor) - idx2 = torch.zeros(batchsize, m).type(torch.IntTensor) - - dist1 = dist1.cuda() - dist2 = dist2.cuda() - idx1 = idx1.cuda() - idx2 = idx2.cuda() - - chamfer.forward(xyz1, xyz2, dist1, dist2, idx1, idx2) - ctx.save_for_backward(xyz1, xyz2, idx1, idx2) - return dist1, dist2, idx1, idx2 - - @staticmethod - def backward(ctx, graddist1, graddist2, gradidx1, gradidx2): - xyz1, xyz2, idx1, idx2 = ctx.saved_tensors - graddist1 = graddist1.contiguous() - graddist2 = graddist2.contiguous() - - gradxyz1 = torch.zeros(xyz1.size()) - gradxyz2 = torch.zeros(xyz2.size()) - - gradxyz1 = gradxyz1.cuda() - gradxyz2 = gradxyz2.cuda() - chamfer.backward( - xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2 - ) - return gradxyz1, gradxyz2 - - -class chamferDist(nn.Module): - def __init__(self): - super(chamferDist, self).__init__() - - def forward(self, input1, input2): - return chamferFunction.apply(input1, input2) diff --git a/extension/get_chamfer.py b/extension/get_chamfer.py deleted file mode 100644 index 314e7da..0000000 --- a/extension/get_chamfer.py +++ /dev/null @@ -1,10 +0,0 @@ -def get(opt): - if opt.accelerated_chamfer: - import dist_chamfer_idx as ext - - distChamfer = ext.chamferDist() - else: - import chamfer_python - - distChamfer = chamfer_python.distChamfer - return distChamfer diff --git a/extension/setup.py b/extension/setup.py deleted file mode 100755 index 9055958..0000000 --- a/extension/setup.py +++ /dev/null @@ -1,14 +0,0 @@ -from setuptools import setup -from torch.utils.cpp_extension import BuildExtension, CUDAExtension - -setup( - name='chamfer', - ext_modules=[ - CUDAExtension('chamfer', [ - 'chamfer_cuda.cpp', - 'chamfer.cu', - ]), - ], - cmdclass={ - 'build_ext': BuildExtension - }) \ No newline at end of file diff --git a/extension/test_chamfer.py b/extension/test_chamfer.py deleted file mode 100644 index 33f7a51..0000000 --- a/extension/test_chamfer.py +++ /dev/null @@ -1,57 +0,0 @@ -import torch -import dist_chamfer as ext - -distChamfer = ext.chamferDist() -from torch.autograd import Variable - - -def pairwise_dist(x, y): - xx, yy, zz = torch.mm(x, x.t()), torch.mm(y, y.t()), torch.mm(x, y.t()) - rx = xx.diag().unsqueeze(0).expand_as(xx) - ry = yy.diag().unsqueeze(0).expand_as(yy) - P = rx.t() + ry - 2 * zz - return P - - -def NN_loss(x, y, dim=0): - dist = pairwise_dist(x, y) - values, indices = dist.min(dim=dim) - return values.mean() - - -def mydistChamfer(a, b): - x, y = a, b - bs, num_points, points_dim = x.size() - xx = torch.bmm(x, x.transpose(2, 1)) - yy = torch.bmm(y, y.transpose(2, 1)) - zz = torch.bmm(x, y.transpose(2, 1)) - diag_ind = torch.arange(0, num_points).type(torch.cuda.LongTensor) - rx = xx[:, diag_ind, diag_ind].unsqueeze(1).expand_as(xx) - ry = yy[:, diag_ind, diag_ind].unsqueeze(1).expand_as(yy) - P = rx.transpose(2, 1) + ry - 2 * zz - return torch.min(P, 2)[0], torch.min(P, 1)[0] - - -def test_chamfer(): - distChamfer = ext.chamferDist() - p1 = torch.rand(4, 100, 3).cuda() - p2 = torch.rand(4, 100, 3).cuda() - points1 = Variable(p1, requires_grad=True) - points2 = Variable(p2) - dist1, dist2, = distChamfer(points1, points2) - - loss = torch.sum(dist1) - print(loss) - loss.backward() - print(points1.grad, points2.grad) - - mydist1, mydist2 = mydistChamfer(points1, points2) - d1 = (dist1 - mydist1) ** 2 - d2 = (dist2 - mydist2) ** 2 - print(d1, d2) - assert ( - torch.sum(d1) + torch.sum(d2) < 0.00000001 - ), "chamfer cuda and chamfer normal are not giving the same results" - - -test_chamfer()