learning3d 0.0.7__py3-none-any.whl → 0.2.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.
Files changed (87) hide show
  1. {learning3d/data_utils → data_utils}/dataloaders.py +16 -14
  2. examples/test_curvenet.py +118 -0
  3. {learning3d/examples → examples}/test_dcp.py +1 -1
  4. {learning3d/examples → examples}/test_deepgmr.py +1 -1
  5. {learning3d/examples → examples}/test_prnet.py +1 -1
  6. {learning3d-0.0.7.dist-info → learning3d-0.2.0.dist-info}/METADATA +56 -11
  7. learning3d-0.2.0.dist-info/RECORD +70 -0
  8. {learning3d-0.0.7.dist-info → learning3d-0.2.0.dist-info}/WHEEL +1 -1
  9. learning3d-0.2.0.dist-info/top_level.txt +6 -0
  10. {learning3d/models → models}/__init__.py +7 -1
  11. models/curvenet.py +130 -0
  12. {learning3d/models → models}/dgcnn.py +1 -35
  13. {learning3d/models → models}/prnet.py +5 -39
  14. utils/__init__.py +23 -0
  15. utils/curvenet_util.py +540 -0
  16. utils/model_common_utils.py +156 -0
  17. learning3d/losses/cuda/chamfer_distance/__init__.py +0 -1
  18. learning3d/losses/cuda/chamfer_distance/chamfer_distance.cpp +0 -185
  19. learning3d/losses/cuda/chamfer_distance/chamfer_distance.cu +0 -209
  20. learning3d/losses/cuda/chamfer_distance/chamfer_distance.py +0 -66
  21. learning3d/losses/cuda/emd_torch/pkg/emd_loss_layer.py +0 -41
  22. learning3d/losses/cuda/emd_torch/pkg/include/cuda/emd.cuh +0 -347
  23. learning3d/losses/cuda/emd_torch/pkg/include/cuda_helper.h +0 -18
  24. learning3d/losses/cuda/emd_torch/pkg/include/emd.h +0 -54
  25. learning3d/losses/cuda/emd_torch/pkg/layer/__init__.py +0 -1
  26. learning3d/losses/cuda/emd_torch/pkg/layer/emd_loss_layer.py +0 -40
  27. learning3d/losses/cuda/emd_torch/pkg/src/cuda/emd.cu +0 -70
  28. learning3d/losses/cuda/emd_torch/pkg/src/emd.cpp +0 -1
  29. learning3d/losses/cuda/emd_torch/setup.py +0 -29
  30. learning3d/ops/__init__.py +0 -0
  31. learning3d/utils/__init__.py +0 -4
  32. learning3d-0.0.7.dist-info/RECORD +0 -80
  33. learning3d-0.0.7.dist-info/top_level.txt +0 -1
  34. {learning3d/data_utils → data_utils}/__init__.py +0 -0
  35. {learning3d/data_utils → data_utils}/user_data.py +0 -0
  36. {learning3d/examples → examples}/test_masknet.py +0 -0
  37. {learning3d/examples → examples}/test_masknet2.py +0 -0
  38. {learning3d/examples → examples}/test_pcn.py +0 -0
  39. {learning3d/examples → examples}/test_pcrnet.py +0 -0
  40. {learning3d/examples → examples}/test_pnlk.py +0 -0
  41. {learning3d/examples → examples}/test_pointconv.py +0 -0
  42. {learning3d/examples → examples}/test_pointnet.py +0 -0
  43. {learning3d/examples → examples}/test_rpmnet.py +0 -0
  44. {learning3d/examples → examples}/train_PointNetLK.py +0 -0
  45. {learning3d/examples → examples}/train_dcp.py +0 -0
  46. {learning3d/examples → examples}/train_deepgmr.py +0 -0
  47. {learning3d/examples → examples}/train_masknet.py +0 -0
  48. {learning3d/examples → examples}/train_pcn.py +0 -0
  49. {learning3d/examples → examples}/train_pcrnet.py +0 -0
  50. {learning3d/examples → examples}/train_pointconv.py +0 -0
  51. {learning3d/examples → examples}/train_pointnet.py +0 -0
  52. {learning3d/examples → examples}/train_prnet.py +0 -0
  53. {learning3d/examples → examples}/train_rpmnet.py +0 -0
  54. {learning3d-0.0.7.dist-info → learning3d-0.2.0.dist-info}/LICENSE +0 -0
  55. {learning3d/losses → losses}/__init__.py +0 -0
  56. {learning3d/losses → losses}/chamfer_distance.py +0 -0
  57. {learning3d/losses → losses}/classification.py +0 -0
  58. {learning3d/losses → losses}/correspondence_loss.py +0 -0
  59. {learning3d/losses → losses}/emd.py +0 -0
  60. {learning3d/losses → losses}/frobenius_norm.py +0 -0
  61. {learning3d/losses → losses}/rmse_features.py +0 -0
  62. {learning3d/models → models}/classifier.py +0 -0
  63. {learning3d/models → models}/dcp.py +0 -0
  64. {learning3d/models → models}/deepgmr.py +0 -0
  65. {learning3d/models → models}/masknet.py +0 -0
  66. {learning3d/models → models}/masknet2.py +0 -0
  67. {learning3d/models → models}/pcn.py +0 -0
  68. {learning3d/models → models}/pcrnet.py +0 -0
  69. {learning3d/models → models}/pointconv.py +0 -0
  70. {learning3d/models → models}/pointnet.py +0 -0
  71. {learning3d/models → models}/pointnetlk.py +0 -0
  72. {learning3d/models → models}/pooling.py +0 -0
  73. {learning3d/models → models}/ppfnet.py +0 -0
  74. {learning3d/models → models}/rpmnet.py +0 -0
  75. {learning3d/models → models}/segmentation.py +0 -0
  76. {learning3d → ops}/__init__.py +0 -0
  77. {learning3d/ops → ops}/data_utils.py +0 -0
  78. {learning3d/ops → ops}/invmat.py +0 -0
  79. {learning3d/ops → ops}/quaternion.py +0 -0
  80. {learning3d/ops → ops}/se3.py +0 -0
  81. {learning3d/ops → ops}/sinc.py +0 -0
  82. {learning3d/ops → ops}/so3.py +0 -0
  83. {learning3d/ops → ops}/transform_functions.py +0 -0
  84. {learning3d/utils → utils}/pointconv_util.py +0 -0
  85. {learning3d/utils → utils}/ppfnet_util.py +0 -0
  86. {learning3d/utils → utils}/svd.py +0 -0
  87. {learning3d/utils → utils}/transformer.py +0 -0
@@ -0,0 +1,156 @@
1
+ import torch
2
+
3
+ def knn(x, k, add_one_to_k=False):
4
+ if add_one_to_k: k = k + 1
5
+ inner = -2 * torch.matmul(x.transpose(2, 1).contiguous(), x)
6
+ xx = torch.sum(x**2, dim=1, keepdim=True)
7
+ pairwise_distance = -xx - inner - xx.transpose(2, 1).contiguous()
8
+ idx = pairwise_distance.topk(k=k, dim=-1)[1] # (batch_size, num_points, k)
9
+ return idx
10
+
11
+ def pc_normalize(pc):
12
+ l = pc.shape[0]
13
+ centroid = np.mean(pc, axis=0)
14
+ pc = pc - centroid
15
+ m = np.max(np.sqrt(np.sum(pc**2, axis=1)))
16
+ pc = pc / m
17
+ return pc
18
+
19
+ def square_distance(src, dst):
20
+ """
21
+ Calculate Euclid distance between each two points.
22
+ src^T * dst = xn * xm + yn * ym + zn * zm;
23
+ sum(src^2, dim=-1) = xn*xn + yn*yn + zn*zn;
24
+ sum(dst^2, dim=-1) = xm*xm + ym*ym + zm*zm;
25
+ dist = (xn - xm)^2 + (yn - ym)^2 + (zn - zm)^2
26
+ = sum(src**2,dim=-1)+sum(dst**2,dim=-1)-2*src^T*dst
27
+ Input:
28
+ src: source points, [B, N, C]
29
+ dst: target points, [B, M, C]
30
+ Output:
31
+ dist: per-point square distance, [B, N, M]
32
+ """
33
+ B, N, _ = src.shape
34
+ _, M, _ = dst.shape
35
+ dist = -2 * torch.matmul(src, dst.permute(0, 2, 1))
36
+ dist += torch.sum(src ** 2, -1).view(B, N, 1)
37
+ dist += torch.sum(dst ** 2, -1).view(B, 1, M)
38
+ return dist
39
+
40
+ def index_points(points, idx):
41
+ """
42
+ Input:
43
+ points: input points data, [B, N, C]
44
+ idx: sample index data, [B, S]
45
+ Return:
46
+ new_points:, indexed points data, [B, S, C]
47
+ """
48
+ device = points.device
49
+ B = points.shape[0]
50
+ view_shape = list(idx.shape)
51
+ view_shape[1:] = [1] * (len(view_shape) - 1)
52
+ repeat_shape = list(idx.shape)
53
+ repeat_shape[0] = 1
54
+ batch_indices = torch.arange(B, dtype=torch.long).to(device).view(view_shape).repeat(repeat_shape)
55
+ new_points = points[batch_indices, idx, :]
56
+ return new_points
57
+
58
+ def farthest_point_sample(xyz, npoint, start_with_first_point=False):
59
+ """
60
+ Input:
61
+ xyz: pointcloud data, [B, N, C]
62
+ npoint: number of samples
63
+ Return:
64
+ centroids: sampled pointcloud index, [B, npoint]
65
+ """
66
+ device = xyz.device
67
+ B, N, C = xyz.shape
68
+ centroids = torch.zeros(B, npoint, dtype=torch.long).to(device)
69
+ distance = torch.ones(B, N).to(device) * 1e10
70
+ if not start_with_first_point:
71
+ farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device)
72
+ else:
73
+ farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device) * 0
74
+ batch_indices = torch.arange(B, dtype=torch.long).to(device)
75
+ for i in range(npoint):
76
+ centroids[:, i] = farthest
77
+ centroid = xyz[batch_indices, farthest, :].view(B, 1, 3)
78
+ dist = torch.sum((xyz - centroid) ** 2, -1)
79
+ mask = dist < distance
80
+ distance[mask] = dist[mask]
81
+ farthest = torch.max(distance, -1)[1]
82
+ return centroids
83
+
84
+ def knn_point(k, pos1, pos2):
85
+ '''
86
+ Input:
87
+ k: int32, number of k in k-nn search
88
+ pos1: (batch_size, ndataset, c) float32 array, input points
89
+ pos2: (batch_size, npoint, c) float32 array, query points
90
+ Output:
91
+ val: (batch_size, npoint, k) float32 array, L2 distances
92
+ idx: (batch_size, npoint, k) int32 array, indices to input points
93
+ '''
94
+ B, N, C = pos1.shape
95
+ M = pos2.shape[1]
96
+ pos1 = pos1.view(B,1,N,-1).repeat(1,M,1,1)
97
+ pos2 = pos2.view(B,M,1,-1).repeat(1,1,N,1)
98
+ dist = torch.sum(-(pos1-pos2)**2,-1)
99
+ val,idx = dist.topk(k=k,dim = -1)
100
+ return torch.sqrt(-val), idx
101
+
102
+ def query_ball_point(radius, nsample, xyz, new_xyz, get_cnt=False):
103
+ """
104
+ Input:
105
+ radius: local region radius
106
+ nsample: max sample number in local region
107
+ xyz: all points, [B, N, C]
108
+ new_xyz: query points, [B, S, C]
109
+ Return:
110
+ group_idx: grouped points index, [B, S, nsample]
111
+ """
112
+ device = xyz.device
113
+ B, N, C = xyz.shape
114
+ _, S, _ = new_xyz.shape
115
+ group_idx = torch.arange(N, dtype=torch.long).to(device).view(1, 1, N).repeat([B, S, 1])
116
+ sqrdists = square_distance(new_xyz, xyz)
117
+ group_idx[sqrdists > radius ** 2] = N
118
+
119
+ if get_cnt:
120
+ mask = group_idx != N
121
+ cnt = mask.sum(dim=-1)
122
+
123
+ group_idx = group_idx.sort(dim=-1)[0][:, :, :nsample]
124
+ group_first = group_idx[:, :, 0].view(B, S, 1).repeat([1, 1, nsample])
125
+ mask = group_idx == N
126
+ group_idx[mask] = group_first[mask]
127
+ if get_cnt:
128
+ return group_idx, cnt
129
+ else:
130
+ return group_idx
131
+
132
+ def get_graph_feature(x, k=20, device=None):
133
+ # x = x.squeeze()
134
+ x = x.view(*x.size()[:3])
135
+ idx = knn(x, k=k) # (batch_size, num_points, k)
136
+ batch_size, num_points, _ = idx.size()
137
+
138
+ if device is None:
139
+ device = 'cuda' if torch.cuda.is_available() else 'cpu'
140
+
141
+ idx_base = torch.arange(0, batch_size, device=device).view(-1, 1, 1) * num_points
142
+
143
+ idx = idx + idx_base
144
+
145
+ idx = idx.view(-1)
146
+
147
+ _, num_dims, _ = x.size()
148
+
149
+ x = x.transpose(2, 1).contiguous() # (batch_size, num_points, num_dims) -> (batch_size*num_points, num_dims) # batch_size * num_points * k + range(0, batch_size*num_points)
150
+ feature = x.view(batch_size * num_points, -1)[idx, :]
151
+ feature = feature.view(batch_size, num_points, k, num_dims)
152
+ x = x.view(batch_size, num_points, 1, num_dims).repeat(1, 1, k, 1)
153
+
154
+ feature = torch.cat((feature, x), dim=3).permute(0, 3, 1, 2)
155
+
156
+ return feature
@@ -1 +0,0 @@
1
- from .chamfer_distance import ChamferDistance
@@ -1,185 +0,0 @@
1
- #include <torch/torch.h>
2
-
3
- // CUDA forward declarations
4
- int ChamferDistanceKernelLauncher(
5
- const int b, const int n,
6
- const float* xyz,
7
- const int m,
8
- const float* xyz2,
9
- float* result,
10
- int* result_i,
11
- float* result2,
12
- int* result2_i);
13
-
14
- int ChamferDistanceGradKernelLauncher(
15
- const int b, const int n,
16
- const float* xyz1,
17
- const int m,
18
- const float* xyz2,
19
- const float* grad_dist1,
20
- const int* idx1,
21
- const float* grad_dist2,
22
- const int* idx2,
23
- float* grad_xyz1,
24
- float* grad_xyz2);
25
-
26
-
27
- void chamfer_distance_forward_cuda(
28
- const at::Tensor xyz1,
29
- const at::Tensor xyz2,
30
- const at::Tensor dist1,
31
- const at::Tensor dist2,
32
- const at::Tensor idx1,
33
- const at::Tensor idx2)
34
- {
35
- ChamferDistanceKernelLauncher(xyz1.size(0), xyz1.size(1), xyz1.data<float>(),
36
- xyz2.size(1), xyz2.data<float>(),
37
- dist1.data<float>(), idx1.data<int>(),
38
- dist2.data<float>(), idx2.data<int>());
39
- }
40
-
41
- void chamfer_distance_backward_cuda(
42
- const at::Tensor xyz1,
43
- const at::Tensor xyz2,
44
- at::Tensor gradxyz1,
45
- at::Tensor gradxyz2,
46
- at::Tensor graddist1,
47
- at::Tensor graddist2,
48
- at::Tensor idx1,
49
- at::Tensor idx2)
50
- {
51
- ChamferDistanceGradKernelLauncher(xyz1.size(0), xyz1.size(1), xyz1.data<float>(),
52
- xyz2.size(1), xyz2.data<float>(),
53
- graddist1.data<float>(), idx1.data<int>(),
54
- graddist2.data<float>(), idx2.data<int>(),
55
- gradxyz1.data<float>(), gradxyz2.data<float>());
56
- }
57
-
58
-
59
- void nnsearch(
60
- const int b, const int n, const int m,
61
- const float* xyz1,
62
- const float* xyz2,
63
- float* dist,
64
- int* idx)
65
- {
66
- for (int i = 0; i < b; i++) {
67
- for (int j = 0; j < n; j++) {
68
- const float x1 = xyz1[(i*n+j)*3+0];
69
- const float y1 = xyz1[(i*n+j)*3+1];
70
- const float z1 = xyz1[(i*n+j)*3+2];
71
- double best = 0;
72
- int besti = 0;
73
- for (int k = 0; k < m; k++) {
74
- const float x2 = xyz2[(i*m+k)*3+0] - x1;
75
- const float y2 = xyz2[(i*m+k)*3+1] - y1;
76
- const float z2 = xyz2[(i*m+k)*3+2] - z1;
77
- const double d=x2*x2+y2*y2+z2*z2;
78
- if (k==0 || d < best){
79
- best = d;
80
- besti = k;
81
- }
82
- }
83
- dist[i*n+j] = best;
84
- idx[i*n+j] = besti;
85
- }
86
- }
87
- }
88
-
89
-
90
- void chamfer_distance_forward(
91
- const at::Tensor xyz1,
92
- const at::Tensor xyz2,
93
- const at::Tensor dist1,
94
- const at::Tensor dist2,
95
- const at::Tensor idx1,
96
- const at::Tensor idx2)
97
- {
98
- const int batchsize = xyz1.size(0);
99
- const int n = xyz1.size(1);
100
- const int m = xyz2.size(1);
101
-
102
- const float* xyz1_data = xyz1.data<float>();
103
- const float* xyz2_data = xyz2.data<float>();
104
- float* dist1_data = dist1.data<float>();
105
- float* dist2_data = dist2.data<float>();
106
- int* idx1_data = idx1.data<int>();
107
- int* idx2_data = idx2.data<int>();
108
-
109
- nnsearch(batchsize, n, m, xyz1_data, xyz2_data, dist1_data, idx1_data);
110
- nnsearch(batchsize, m, n, xyz2_data, xyz1_data, dist2_data, idx2_data);
111
- }
112
-
113
-
114
- void chamfer_distance_backward(
115
- const at::Tensor xyz1,
116
- const at::Tensor xyz2,
117
- at::Tensor gradxyz1,
118
- at::Tensor gradxyz2,
119
- at::Tensor graddist1,
120
- at::Tensor graddist2,
121
- at::Tensor idx1,
122
- at::Tensor idx2)
123
- {
124
- const int b = xyz1.size(0);
125
- const int n = xyz1.size(1);
126
- const int m = xyz2.size(1);
127
-
128
- const float* xyz1_data = xyz1.data<float>();
129
- const float* xyz2_data = xyz2.data<float>();
130
- float* gradxyz1_data = gradxyz1.data<float>();
131
- float* gradxyz2_data = gradxyz2.data<float>();
132
- float* graddist1_data = graddist1.data<float>();
133
- float* graddist2_data = graddist2.data<float>();
134
- const int* idx1_data = idx1.data<int>();
135
- const int* idx2_data = idx2.data<int>();
136
-
137
- for (int i = 0; i < b*n*3; i++)
138
- gradxyz1_data[i] = 0;
139
- for (int i = 0; i < b*m*3; i++)
140
- gradxyz2_data[i] = 0;
141
- for (int i = 0;i < b; i++) {
142
- for (int j = 0; j < n; j++) {
143
- const float x1 = xyz1_data[(i*n+j)*3+0];
144
- const float y1 = xyz1_data[(i*n+j)*3+1];
145
- const float z1 = xyz1_data[(i*n+j)*3+2];
146
- const int j2 = idx1_data[i*n+j];
147
-
148
- const float x2 = xyz2_data[(i*m+j2)*3+0];
149
- const float y2 = xyz2_data[(i*m+j2)*3+1];
150
- const float z2 = xyz2_data[(i*m+j2)*3+2];
151
- const float g = graddist1_data[i*n+j]*2;
152
-
153
- gradxyz1_data[(i*n+j)*3+0] += g*(x1-x2);
154
- gradxyz1_data[(i*n+j)*3+1] += g*(y1-y2);
155
- gradxyz1_data[(i*n+j)*3+2] += g*(z1-z2);
156
- gradxyz2_data[(i*m+j2)*3+0] -= (g*(x1-x2));
157
- gradxyz2_data[(i*m+j2)*3+1] -= (g*(y1-y2));
158
- gradxyz2_data[(i*m+j2)*3+2] -= (g*(z1-z2));
159
- }
160
- for (int j = 0; j < m; j++) {
161
- const float x1 = xyz2_data[(i*m+j)*3+0];
162
- const float y1 = xyz2_data[(i*m+j)*3+1];
163
- const float z1 = xyz2_data[(i*m+j)*3+2];
164
- const int j2 = idx2_data[i*m+j];
165
- const float x2 = xyz1_data[(i*n+j2)*3+0];
166
- const float y2 = xyz1_data[(i*n+j2)*3+1];
167
- const float z2 = xyz1_data[(i*n+j2)*3+2];
168
- const float g = graddist2_data[i*m+j]*2;
169
- gradxyz2_data[(i*m+j)*3+0] += g*(x1-x2);
170
- gradxyz2_data[(i*m+j)*3+1] += g*(y1-y2);
171
- gradxyz2_data[(i*m+j)*3+2] += g*(z1-z2);
172
- gradxyz1_data[(i*n+j2)*3+0] -= (g*(x1-x2));
173
- gradxyz1_data[(i*n+j2)*3+1] -= (g*(y1-y2));
174
- gradxyz1_data[(i*n+j2)*3+2] -= (g*(z1-z2));
175
- }
176
- }
177
- }
178
-
179
-
180
- PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
181
- m.def("forward", &chamfer_distance_forward, "ChamferDistance forward");
182
- m.def("forward_cuda", &chamfer_distance_forward_cuda, "ChamferDistance forward (CUDA)");
183
- m.def("backward", &chamfer_distance_backward, "ChamferDistance backward");
184
- m.def("backward_cuda", &chamfer_distance_backward_cuda, "ChamferDistance backward (CUDA)");
185
- }
@@ -1,209 +0,0 @@
1
- #include <ATen/ATen.h>
2
-
3
- #include <cuda.h>
4
- #include <cuda_runtime.h>
5
-
6
- __global__
7
- void ChamferDistanceKernel(
8
- int b,
9
- int n,
10
- const float* xyz,
11
- int m,
12
- const float* xyz2,
13
- float* result,
14
- int* result_i)
15
- {
16
- const int batch=512;
17
- __shared__ float buf[batch*3];
18
- for (int i=blockIdx.x;i<b;i+=gridDim.x){
19
- for (int k2=0;k2<m;k2+=batch){
20
- int end_k=min(m,k2+batch)-k2;
21
- for (int j=threadIdx.x;j<end_k*3;j+=blockDim.x){
22
- buf[j]=xyz2[(i*m+k2)*3+j];
23
- }
24
- __syncthreads();
25
- for (int j=threadIdx.x+blockIdx.y*blockDim.x;j<n;j+=blockDim.x*gridDim.y){
26
- float x1=xyz[(i*n+j)*3+0];
27
- float y1=xyz[(i*n+j)*3+1];
28
- float z1=xyz[(i*n+j)*3+2];
29
- int best_i=0;
30
- float best=0;
31
- int end_ka=end_k-(end_k&3);
32
- if (end_ka==batch){
33
- for (int k=0;k<batch;k+=4){
34
- {
35
- float x2=buf[k*3+0]-x1;
36
- float y2=buf[k*3+1]-y1;
37
- float z2=buf[k*3+2]-z1;
38
- float d=x2*x2+y2*y2+z2*z2;
39
- if (k==0 || d<best){
40
- best=d;
41
- best_i=k+k2;
42
- }
43
- }
44
- {
45
- float x2=buf[k*3+3]-x1;
46
- float y2=buf[k*3+4]-y1;
47
- float z2=buf[k*3+5]-z1;
48
- float d=x2*x2+y2*y2+z2*z2;
49
- if (d<best){
50
- best=d;
51
- best_i=k+k2+1;
52
- }
53
- }
54
- {
55
- float x2=buf[k*3+6]-x1;
56
- float y2=buf[k*3+7]-y1;
57
- float z2=buf[k*3+8]-z1;
58
- float d=x2*x2+y2*y2+z2*z2;
59
- if (d<best){
60
- best=d;
61
- best_i=k+k2+2;
62
- }
63
- }
64
- {
65
- float x2=buf[k*3+9]-x1;
66
- float y2=buf[k*3+10]-y1;
67
- float z2=buf[k*3+11]-z1;
68
- float d=x2*x2+y2*y2+z2*z2;
69
- if (d<best){
70
- best=d;
71
- best_i=k+k2+3;
72
- }
73
- }
74
- }
75
- }else{
76
- for (int k=0;k<end_ka;k+=4){
77
- {
78
- float x2=buf[k*3+0]-x1;
79
- float y2=buf[k*3+1]-y1;
80
- float z2=buf[k*3+2]-z1;
81
- float d=x2*x2+y2*y2+z2*z2;
82
- if (k==0 || d<best){
83
- best=d;
84
- best_i=k+k2;
85
- }
86
- }
87
- {
88
- float x2=buf[k*3+3]-x1;
89
- float y2=buf[k*3+4]-y1;
90
- float z2=buf[k*3+5]-z1;
91
- float d=x2*x2+y2*y2+z2*z2;
92
- if (d<best){
93
- best=d;
94
- best_i=k+k2+1;
95
- }
96
- }
97
- {
98
- float x2=buf[k*3+6]-x1;
99
- float y2=buf[k*3+7]-y1;
100
- float z2=buf[k*3+8]-z1;
101
- float d=x2*x2+y2*y2+z2*z2;
102
- if (d<best){
103
- best=d;
104
- best_i=k+k2+2;
105
- }
106
- }
107
- {
108
- float x2=buf[k*3+9]-x1;
109
- float y2=buf[k*3+10]-y1;
110
- float z2=buf[k*3+11]-z1;
111
- float d=x2*x2+y2*y2+z2*z2;
112
- if (d<best){
113
- best=d;
114
- best_i=k+k2+3;
115
- }
116
- }
117
- }
118
- }
119
- for (int k=end_ka;k<end_k;k++){
120
- float x2=buf[k*3+0]-x1;
121
- float y2=buf[k*3+1]-y1;
122
- float z2=buf[k*3+2]-z1;
123
- float d=x2*x2+y2*y2+z2*z2;
124
- if (k==0 || d<best){
125
- best=d;
126
- best_i=k+k2;
127
- }
128
- }
129
- if (k2==0 || result[(i*n+j)]>best){
130
- result[(i*n+j)]=best;
131
- result_i[(i*n+j)]=best_i;
132
- }
133
- }
134
- __syncthreads();
135
- }
136
- }
137
- }
138
-
139
- void ChamferDistanceKernelLauncher(
140
- const int b, const int n,
141
- const float* xyz,
142
- const int m,
143
- const float* xyz2,
144
- float* result,
145
- int* result_i,
146
- float* result2,
147
- int* result2_i)
148
- {
149
- ChamferDistanceKernel<<<dim3(32,16,1),512>>>(b, n, xyz, m, xyz2, result, result_i);
150
- ChamferDistanceKernel<<<dim3(32,16,1),512>>>(b, m, xyz2, n, xyz, result2, result2_i);
151
-
152
- cudaError_t err = cudaGetLastError();
153
- if (err != cudaSuccess)
154
- printf("error in chamfer distance updateOutput: %s\n", cudaGetErrorString(err));
155
- }
156
-
157
-
158
- __global__
159
- void ChamferDistanceGradKernel(
160
- int b, int n,
161
- const float* xyz1,
162
- int m,
163
- const float* xyz2,
164
- const float* grad_dist1,
165
- const int* idx1,
166
- float* grad_xyz1,
167
- float* grad_xyz2)
168
- {
169
- for (int i = blockIdx.x; i<b; i += gridDim.x) {
170
- for (int j = threadIdx.x + blockIdx.y * blockDim.x; j < n; j += blockDim.x*gridDim.y) {
171
- float x1=xyz1[(i*n+j)*3+0];
172
- float y1=xyz1[(i*n+j)*3+1];
173
- float z1=xyz1[(i*n+j)*3+2];
174
- int j2=idx1[i*n+j];
175
- float x2=xyz2[(i*m+j2)*3+0];
176
- float y2=xyz2[(i*m+j2)*3+1];
177
- float z2=xyz2[(i*m+j2)*3+2];
178
- float g=grad_dist1[i*n+j]*2;
179
- atomicAdd(&(grad_xyz1[(i*n+j)*3+0]),g*(x1-x2));
180
- atomicAdd(&(grad_xyz1[(i*n+j)*3+1]),g*(y1-y2));
181
- atomicAdd(&(grad_xyz1[(i*n+j)*3+2]),g*(z1-z2));
182
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+0]),-(g*(x1-x2)));
183
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+1]),-(g*(y1-y2)));
184
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+2]),-(g*(z1-z2)));
185
- }
186
- }
187
- }
188
-
189
- void ChamferDistanceGradKernelLauncher(
190
- const int b, const int n,
191
- const float* xyz1,
192
- const int m,
193
- const float* xyz2,
194
- const float* grad_dist1,
195
- const int* idx1,
196
- const float* grad_dist2,
197
- const int* idx2,
198
- float* grad_xyz1,
199
- float* grad_xyz2)
200
- {
201
- cudaMemset(grad_xyz1, 0, b*n*3*4);
202
- cudaMemset(grad_xyz2, 0, b*m*3*4);
203
- ChamferDistanceGradKernel<<<dim3(1,16,1), 256>>>(b, n, xyz1, m, xyz2, grad_dist1, idx1, grad_xyz1, grad_xyz2);
204
- ChamferDistanceGradKernel<<<dim3(1,16,1), 256>>>(b, m, xyz2, n, xyz1, grad_dist2, idx2, grad_xyz2, grad_xyz1);
205
-
206
- cudaError_t err = cudaGetLastError();
207
- if (err != cudaSuccess)
208
- printf("error in chamfer distance get grad: %s\n", cudaGetErrorString(err));
209
- }
@@ -1,66 +0,0 @@
1
- import torch
2
- from torch.utils.cpp_extension import load
3
- import os
4
-
5
- script_dir = os.path.dirname(__file__)
6
- sources = [
7
- os.path.join(script_dir, "chamfer_distance.cpp"),
8
- os.path.join(script_dir, "chamfer_distance.cu"),
9
- ]
10
-
11
- cd = load(name="cd", sources=sources)
12
-
13
-
14
- class ChamferDistanceFunction(torch.autograd.Function):
15
- @staticmethod
16
- def forward(ctx, xyz1, xyz2):
17
- batchsize, n, _ = xyz1.size()
18
- _, m, _ = xyz2.size()
19
- xyz1 = xyz1.contiguous()
20
- xyz2 = xyz2.contiguous()
21
- dist1 = torch.zeros(batchsize, n)
22
- dist2 = torch.zeros(batchsize, m)
23
-
24
- idx1 = torch.zeros(batchsize, n, dtype=torch.int)
25
- idx2 = torch.zeros(batchsize, m, dtype=torch.int)
26
-
27
- if not xyz1.is_cuda:
28
- cd.forward(xyz1, xyz2, dist1, dist2, idx1, idx2)
29
- else:
30
- dist1 = dist1.cuda()
31
- dist2 = dist2.cuda()
32
- idx1 = idx1.cuda()
33
- idx2 = idx2.cuda()
34
- cd.forward_cuda(xyz1, xyz2, dist1, dist2, idx1, idx2)
35
-
36
- ctx.save_for_backward(xyz1, xyz2, idx1, idx2)
37
-
38
- return dist1, dist2
39
-
40
- @staticmethod
41
- def backward(ctx, graddist1, graddist2):
42
- xyz1, xyz2, idx1, idx2 = ctx.saved_tensors
43
-
44
- graddist1 = graddist1.contiguous()
45
- graddist2 = graddist2.contiguous()
46
-
47
- gradxyz1 = torch.zeros(xyz1.size())
48
- gradxyz2 = torch.zeros(xyz2.size())
49
-
50
- if not graddist1.is_cuda:
51
- cd.backward(
52
- xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2
53
- )
54
- else:
55
- gradxyz1 = gradxyz1.cuda()
56
- gradxyz2 = gradxyz2.cuda()
57
- cd.backward_cuda(
58
- xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2
59
- )
60
-
61
- return gradxyz1, gradxyz2
62
-
63
-
64
- class ChamferDistance(torch.nn.Module):
65
- def forward(self, xyz1, xyz2):
66
- return ChamferDistanceFunction.apply(xyz1, xyz2)
@@ -1,41 +0,0 @@
1
- import torch
2
- import torch.nn as nn
3
-
4
- import _emd_ext._emd as emd
5
-
6
-
7
- class EMDFunction(torch.autograd.Function):
8
- @staticmethod
9
- def forward(self, xyz1, xyz2):
10
- cost, match = emd.emd_forward(xyz1, xyz2)
11
- self.save_for_backward(xyz1, xyz2, match)
12
- return cost
13
-
14
-
15
- @staticmethod
16
- def backward(self, grad_output):
17
- xyz1, xyz2, match = self.saved_tensors
18
- grad_xyz1, grad_xyz2 = emd.emd_backward(xyz1, xyz2, match)
19
- return grad_xyz1, grad_xyz2
20
-
21
-
22
-
23
-
24
- class EMDLoss(nn.Module):
25
- '''
26
- Computes the (approximate) Earth Mover's Distance between two point sets.
27
-
28
- IMPLEMENTATION LIMITATIONS:
29
- - Double tensors must have <=11 dimensions
30
- - Float tensors must have <=23 dimensions
31
- This is due to the use of CUDA shared memory in the computation. This shared memory is limited by the hardware to 48kB.
32
- '''
33
-
34
- def __init__(self):
35
- super(EMDLoss, self).__init__()
36
-
37
- def forward(self, xyz1, xyz2):
38
-
39
- assert xyz1.shape[-1] == xyz2.shape[-1], 'Both point sets must have the same dimensions!'
40
- assert xyz1.shape[1] == xyz2.shape[1], 'Both Point Clouds must have same number of points in it.'
41
- return EMDFunction.apply(xyz1, xyz2)