Skip to content

Commit

Permalink
SPC batching (#594)
Browse files Browse the repository at this point in the history
* SPC batching

Signed-off-by: operel <operel@nvidia.com>

* fix doc rendering issue

Signed-off-by: operel <operel@nvidia.com>

Co-authored-by: operel <operel@nvidia.com>
  • Loading branch information
orperel and operel committed Jul 26, 2022
1 parent 9ac407f commit cfe08db
Show file tree
Hide file tree
Showing 5 changed files with 480 additions and 130 deletions.
2 changes: 1 addition & 1 deletion ci/gitlab_jenkins_templates/core_ci.jenkins
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ node {
configName,
baseImageTag,
config['archsToTest']
)
)
}

for (config in ubuntu_cpuonly_configs) {
Expand Down
201 changes: 104 additions & 97 deletions ci/gitlab_jenkins_templates/ubuntu_test_CI.jenkins
Original file line number Diff line number Diff line change
Expand Up @@ -28,117 +28,124 @@ spec:
node(POD_LABEL) {
container("docker") {
timeout(time: 25, unit: 'MINUTES') {
updateGitlabCommitStatus(name: "test-${configName}-${arch}", state: "running")
stage("Install deps") {
sh 'pip install -r /kaolin/tools/ci_requirements.txt'
sh 'apt update && apt install -y unzip && unzip /kaolin/examples/samples/rendered_clock.zip -d /kaolin/examples/samples/'
}
def build_passed = true
try {
stage('Disp info') {
sh 'nvidia-smi'
sh 'python --version'
gitlabCommitStatus("test-${configName}-${arch}") {
stage("Install deps") {
sh 'pip install -r /kaolin/tools/ci_requirements.txt'
sh 'apt update && apt install -y unzip && unzip /kaolin/examples/samples/rendered_clock.zip -d /kaolin/examples/samples/'
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("Pytest") {
sh '''
export KAOLIN_TEST_NVIDIFFRAST=1
pytest -s --cov=/kaolin/kaolin /kaolin/tests/python/kaolin
'''
def build_passed = true
try {
stage('Disp info') {
sh 'nvidia-smi'
sh 'python --version'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
if (arch == "TITAN_RTX") {
stage("Doc examples") {
// using wheel you don't have /kaolin/kaolin
try {
stage("Pytest") {
sh '''
if [ -f "/kaolin/kaolin" ]; then
pytest --doctest-modules --ignore=/kaolin/kaolin/experimental /kaolin/kaolin
fi
export KAOLIN_TEST_NVIDIFFRAST=1
pytest -s --cov=/kaolin/kaolin /kaolin/tests/python/kaolin
'''
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("DIB-R Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython dibr_tutorial.ipynb'
try {
if (arch == "TITAN_RTX") {
stage("Doc examples") {
// using wheel you don't have /kaolin/kaolin
sh '''
if [ -f "/kaolin/kaolin" ]; then
pytest --doctest-modules --ignore=/kaolin/kaolin/experimental /kaolin/kaolin
fi
'''
}
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("DMTet Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython dmtet_tutorial.ipynb'
try {
stage("DIB-R Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython dibr_tutorial.ipynb'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("Understanding SPCs Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython understanding_spcs_tutorial.ipynb'
try {
stage("DMTet Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython dmtet_tutorial.ipynb'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC from Pointcloud Recipe") {
sh 'cd /kaolin/examples/recipes/dataload/ && python spc_from_pointcloud.py'
try {
stage("Understanding SPCs Tutorial") {
sh 'cd /kaolin/examples/tutorial && ipython understanding_spcs_tutorial.ipynb'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC Basics Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_basics.py'
try {
stage("SPC from Pointcloud Recipe") {
sh 'cd /kaolin/examples/recipes/dataload/ && python spc_from_pointcloud.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("Occupancy Sampling Recipe") {
sh 'cd /kaolin/examples/recipes/preprocess/ && python occupancy_sampling.py'
try {
stage("SPC Basics Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_basics.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC Dual Octree Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_dual_octree.py'
try {
stage("Occupancy Sampling Recipe") {
sh 'cd /kaolin/examples/recipes/preprocess/ && python occupancy_sampling.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC Trilinear Interpolation Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_trilinear_interp.py'
try {
stage("SPC Dual Octree Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_dual_octree.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC Trilinear Interpolation Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_trilinear_interp.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
try {
stage("SPC Batching Recipe") {
sh 'cd /kaolin/examples/recipes/spc/ && python spc_batching.py'
}
} catch(e) {
build_passed = false
echo e.toString()
}
if (build_passed) {
currentBuild.result = "SUCCESS"
} else {
currentBuild.result = "FAILURE"
}
} catch(e) {
build_passed = false
echo e.toString()
}
if (build_passed) {
currentBuild.result = "SUCCESS"
updateGitlabCommitStatus(name: "test-${configName}-${arch}", state: "success")
} else {
currentBuild.result = "FAILURE"
updateGitlabCommitStatus(name: "test-${configName}-${arch}", state: "failed")
}
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/notes/tutorial_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Simple Recipes
* `spc_basics.py <https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/recipes/spc/spc_basics.py>`_: showing attributes of an SPC object
* `spc_dual_octree.py <https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/recipes/spc/spc_dual_octree.py>`_: computing and explaining the dual of an SPC octree
* `spc_trilinear_interp.py <https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/recipes/spc/spc_trilinear_interp.py>`_: computing trilinear interpolation of a point cloud on an SPC
* `spc_batching.py <https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/recipes/spc/spc_batching.py>`_: using SPC objects with unbatched ops in kaolin
* Visualization:
* `visualize_main.py <https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/tutorial/visualize_main.py>`_: using Timelapse API to write mock 3D checkpoints

63 changes: 63 additions & 0 deletions examples/recipes/spc/spc_batching.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ==============================================================================================================
# The following snippet demonstrates how to use a batched Spc object with unbatched operations.
# ==============================================================================================================
# See also:
# - Code: kaolin.ops.spc.SPC
# https://kaolin.readthedocs.io/en/latest/modules/kaolin.rep.html?highlight=SPC#kaolin.rep.Spc
#
# - Tutorial: Understanding Structured Point Clouds (SPCs)
# https://github.com/NVIDIAGameWorks/kaolin/blob/master/examples/tutorial/understanding_spcs_tutorial.ipynb
#
# - Documentation: Structured Point Clouds
# https://kaolin.readthedocs.io/en/latest/modules/kaolin.ops.spc.html?highlight=spc#kaolin-ops-spc
# ==============================================================================================================

import torch
import kaolin
from kaolin.rep.spc import Spc

lod = 3 # In this example we set the SPC to 3 levels of detail
pts_per_spc = 100, 500, 1000 # This example works with a batch of SPCs, each of different size

# Construct SPC from some points data. Point coordinates are expected to be normalized to the range [-1, 1].
# We start by creating each individual entry separately, using the SPC low level api
octrees = list()
for size in pts_per_spc:
points = torch.rand(size, 3, device='cuda') # Randomize some points
points = points * 2.0 - 1.0 # Normalize points between [-1, 1]
points = kaolin.ops.spc.quantize_points(points.contiguous(), level=lod) # Quantize them for octree
octree = kaolin.ops.spc.unbatched_points_to_octree(points, level=lod) # Generate single octree entry
octrees.append(octree)

# Then we join them together to form the batched SPC instance, of 3 entries.
# From this point onwards we can access the SPC via the object-oriented api.
spc = Spc.from_list(octrees)

# The Spc is a batched object. In turn, its fields are either packed or batched.
# (see: https://kaolin.readthedocs.io/en/latest/modules/kaolin.ops.batch.html#kaolin-ops-batch )
# spc.length defines the boundaries between different batched SPC instances the same object holds.
print(f'spc.batch_size: {spc.batch_size}')
print(f'spc.lengths (cells per batch entry): {spc.lengths}')

# Batched fields can be accessed directly
print(f'spc.pyramids is of shape (#num_entries, 2, lod+2): {spc.pyramids.shape}')

# Packed fields are flat, and require extra consideration when accessing individual octree entries.
# (boundaries must be tracked to separate the batched Structured Point Clouds)
print(f'spc.point_hierarchies is of shape (#num_entries x total points, 3): {spc.point_hierarchies.shape}')

# Occasionally, you may come across unbatched operations, which take as an argument a single spc entry.
# In such cases, kaolin supports iteration over the spc structure.
print('Example of iteration:')
query_points = torch.tensor([[1,1,0], [1,0,1]], device='cuda', dtype=torch.short)
for idx, single_spc in enumerate(spc):
# Invoke the unbatched operation per entry, this is of course slower.
# Always prefer a batched operations over an unbatched ones, if an implementation is available!
query_results = kaolin.ops.spc.unbatched_query(single_spc.octrees, single_spc.exsum, query_points, level=2)
print(f'Spc #{idx+1}: unbatched query results are {query_results}')

# kaolin also supports indexing of specific spc entries
print('Example of indexing:')
query_results = kaolin.ops.spc.unbatched_query(single_spc.octrees, single_spc.exsum, query_points, level=lod)
print(f'SPC #2: {spc[1]}')
print(f'Spc #2: unbatched query results are {query_results}')

0 comments on commit cfe08db

Please sign in to comment.