Skip to content

Commit f8acecb

Browse files
Michele Sannafacebook-github-bot
Michele Sanna
authored andcommitted
a formula for bin size for images over 64x64 (facebookresearch#90)
Summary: Signed-off-by: Michele Sanna <sanna@arrival.com> fixes the bin_size calculation with a formula for any image_size > 64. Matches the values chosen so far. simple test: ``` import numpy as np import matplotlib.pyplot as plt image_size = np.arange(64, 2048) bin_size = np.where(image_size <= 64, 8, (2 ** np.maximum(np.ceil(np.log2(image_size)) - 4, 4)).astype(int)) print(image_size) print(bin_size) for ims, bins in zip(image_size, bin_size): if ims <= 64: assert bins == 8 elif ims <= 256: assert bins == 16 elif ims <= 512: assert bins == 32 elif ims <= 1024: assert bins == 64 elif ims <= 2048: assert bins == 128 assert (ims + bins - 1) // bins < 22 plt.plot(image_size, bin_size) plt.grid() plt.show() ``` ![img](https://user-images.githubusercontent.com/54891577/75464693-795bcf00-597f-11ea-9061-26440211691c.png) Pull Request resolved: facebookresearch#90 Reviewed By: jcjohnson Differential Revision: D21160372 Pulled By: nikhilaravi fbshipit-source-id: 660cf5832f4ca5be243c435a6bed969596fc0188
1 parent c3d636d commit f8acecb

File tree

6 files changed

+52
-7
lines changed

6 files changed

+52
-7
lines changed

pytorch3d/csrc/rasterize_meshes/rasterize_meshes.cu

+1-1
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ at::Tensor RasterizeMeshesCoarseCuda(
696696
const int num_bins = 1 + (image_size - 1) / bin_size; // Divide round up.
697697
const int M = max_faces_per_bin;
698698

699-
if (num_bins >= 22) {
699+
if (num_bins >= kMaxFacesPerBin) {
700700
std::stringstream ss;
701701
ss << "Got " << num_bins << "; that's too many!";
702702
AT_ERROR(ss.str());

pytorch3d/csrc/rasterize_points/rasterization_utils.cuh

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ __device__ inline float PixToNdc(int i, int S) {
1717
// TODO: is 8 enough? Would increasing have performance considerations?
1818
const int32_t kMaxPointsPerPixel = 150;
1919

20+
const int32_t kMaxFacesPerBin = 22;
21+
2022
template <typename T>
2123
__device__ inline void BubbleSort(T* arr, int n) {
2224
// Bubble sort. We only use it for tiny thread-local arrays (n < 8); in this

pytorch3d/renderer/mesh/rasterize_meshes.py

+21-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
# TODO make the epsilon user configurable
1212
kEpsilon = 1e-8
1313

14+
# Maxinum number of faces per bins for
15+
# coarse-to-fine rasterization
16+
kMaxFacesPerBin = 22
17+
1418

1519
def rasterize_meshes(
1620
meshes,
@@ -107,12 +111,23 @@ def rasterize_meshes(
107111
# TODO better heuristics for bin size.
108112
if image_size <= 64:
109113
bin_size = 8
110-
elif image_size <= 256:
111-
bin_size = 16
112-
elif image_size <= 512:
113-
bin_size = 32
114-
elif image_size <= 1024:
115-
bin_size = 64
114+
else:
115+
# Heuristic based formula maps image_size -> bin_size as follows:
116+
# image_size < 64 -> 8
117+
# 16 < image_size < 256 -> 16
118+
# 256 < image_size < 512 -> 32
119+
# 512 < image_size < 1024 -> 64
120+
# 1024 < image_size < 2048 -> 128
121+
bin_size = int(2 ** max(np.ceil(np.log2(image_size)) - 4, 4))
122+
123+
if bin_size != 0:
124+
# There is a limit on the number of faces per bin in the cuda kernel.
125+
faces_per_bin = 1 + (image_size - 1) // bin_size
126+
if faces_per_bin >= kMaxFacesPerBin:
127+
raise ValueError(
128+
"bin_size too small, number of faces per bin must be less than %d; got %d"
129+
% (kMaxFacesPerBin, faces_per_bin)
130+
)
116131

117132
if max_faces_per_bin is None:
118133
max_faces_per_bin = int(max(10000, verts_packed.shape[0] / 5))

pytorch3d/renderer/points/rasterize_points.py

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
from pytorch3d.renderer.mesh.rasterize_meshes import pix_to_ndc
88

99

10+
# Maxinum number of faces per bins for
11+
# coarse-to-fine rasterization
12+
kMaxPointsPerBin = 22
13+
14+
1015
# TODO(jcjohns): Support non-square images
1116
def rasterize_points(
1217
pointclouds,
@@ -82,6 +87,15 @@ def rasterize_points(
8287
elif image_size <= 1024:
8388
bin_size = 64
8489

90+
if bin_size != 0:
91+
# There is a limit on the number of points per bin in the cuda kernel.
92+
points_per_bin = 1 + (image_size - 1) // bin_size
93+
if points_per_bin >= kMaxPointsPerBin:
94+
raise ValueError(
95+
"bin_size too small, number of points per bin must be less than %d; got %d"
96+
% (kMaxPointsPerBin, points_per_bin)
97+
)
98+
8599
if max_points_per_bin is None:
86100
max_points_per_bin = int(max(10000, points_packed.shape[0] / 5))
87101

tests/test_rasterize_meshes.py

+7
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,13 @@ def test_cuda_naive_vs_binned_perspective_correct(self):
382382
args = ()
383383
self._compare_impls(fn1, fn2, args, args, verts1, verts2, compare_grads=True)
384384

385+
def test_bin_size_error(self):
386+
meshes = ico_sphere(2)
387+
image_size = 1024
388+
bin_size = 16
389+
with self.assertRaisesRegex(ValueError, "bin_size too small"):
390+
rasterize_meshes(meshes, image_size, 0.0, 2, bin_size)
391+
385392
def _test_back_face_culling(self, rasterize_meshes_fn, device, bin_size):
386393
# Square based pyramid mesh.
387394
# fmt: off

tests/test_rasterize_points.py

+7
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ def _compare_impls(
212212
if compare_grads:
213213
self.assertClose(grad_points1, grad_points2, atol=2e-6)
214214

215+
def test_bin_size_error(self):
216+
points = Pointclouds(points=torch.rand(5, 100, 3))
217+
image_size = 1024
218+
bin_size = 16
219+
with self.assertRaisesRegex(ValueError, "bin_size too small"):
220+
rasterize_points(points, image_size, 0.0, 2, bin_size=bin_size)
221+
215222
def _test_behind_camera(self, rasterize_points_fn, device, bin_size=None):
216223
# Test case where all points are behind the camera -- nothing should
217224
# get rasterized

0 commit comments

Comments
 (0)