UH-OH

It looks like you don’t have access to that feature yet

Contact sales to get upgraded to the full DevStudio experience.

UH-OH

It looks like you don't have access to that feature yet.

Introduction to the Chimera SDK
Chimera SDK Quick Start Guide
Chimera SDK Command Line Interface (CLI)
Tutorial: Using SDK as a Library
Tutorials & Model Demos
Custom Op Tutorials
Multicore Demo
Chimera LLVM C++ Compiler
Chimera SDK Licensing Policy Documentation
Glossary
Chimera Software User GuideTutorials & Model DemosCustom Op TutorialsTutorial: Voxel Pooling

Tutorial: Voxel Pooling


NOTE: The Jupyter Notebook below is included in the Chimera SDK and can be run interactively by running the following CLI command:

$ quadric sdk notebook

From the Jupyter Notebook window in your browser, select the notebook named /quadric/sdk-cli/examples/custom_op/voxel_pooling/voxel_pooling.ipynb.


Tutorial: Voxel Pooling

Voxel Pooling is an operator commonly used in neural networks like BEVDepth. Due to its highly parallel data processing nature, Voxel Pooling often lacks a native PyTorch implementation and is typically accelerated on GPUs. You can see an example of this in the following code: Voxel Pooling CUDA Implementation.

In this notebook, we’ll walk through a simple neural network that utilizes Voxel Pooling. We will:

  • Demonstrate how Voxel Pooling operates within the network.
  • Replace the standard operator with a Custom Operator using our Quadric Custom Operator tooling.
  • Compile and profile the performance of the new operator.

To achieve this, we first implemented Voxel Pooling as a CCL (Custom Compute Language) operator.

CCL Implementation Details

We harnessed the parallel processing capabilities of the Quadric Chimera GPNPU to translate the original CUDA code into an efficient CCL implementation.

voxel_cuda.png voxel_ccl.png

For more in-depth implementation details, refer to the techincal documentation here.

The Voxel Pooling Graph

The Voxel Pooling graph can be seen below

Screenshot 2025-02-07 at 2.56.45 PM.png

To export a graph that includes custom operations, modify your PyTorch graph by registering a symbolic operator. The example below demonstrates how to define a custom autograd function with symbolic registration for a voxel pooling operation. This network shown below is for demonstration purposes only.

## Define a custom autograd function for VoxelPooling.
class VoxelPoolingFunction(torch.autograd.Function):
    @staticmethod
    def forward(ctx, img_features, geom):
        # Dummy implementation: simply add the two inputs.
        # Replace this with your voxel pooling logic.
        return img_features + geom

    @staticmethod
    def symbolic(g, img_features, geom):
        # This tells the ONNX exporter to create a custom op.
        # The operator name here is "VoxelPooling" under the domain "mydomain".
        return g.op("mydomain::VoxelPooling", img_features, geom)

## Wrap the custom function in a module.
class VoxelPoolingModule(nn.Module):
    def forward(self, img_features, geom):
        return VoxelPoolingFunction.apply(img_features, geom)

Steps

1. Replace Voxel Pooling with a Custom Operator

We can then utilize our Custom Operations library to transform this operator and replace it with our nn::voxelPooling operator we've created in CCL

from tvm.contrib.epu.graphutils import FilterNode, CustomOpReplacer
import onnx
import onnxoptimizer

inp = CustomOpReplacer.FilterWildcard
voxel_pooling = FilterNode("VoxelPooling", [inp, inp])

util = CustomOpReplacer(onnx.load("voxel_original.onnx"))
custom_op_onnx_model = util.replace_all(
    voxel_pooling,
    "nn::voxelPooling",
    False,
    allow_io_in_l2_mem=True,
    reserved_ocm=1024 << 10,
)

optimized_model = onnxoptimizer.optimize(custom_op_onnx_model, ["eliminate_identity"])
onnx.save(optimized_model, "voxel_opt.onnx")
WARNING:root:ONNX node does not have a name, deriving temp name from its outputs. Node was named to: output
WARNING:root:ONNX node does not have a name, deriving temp name from its outputs. Node was named to: scale
WARNING:root:ONNX node does not have a name, deriving temp name from its outputs. Node was named to: zero_point

2. Inspect the Custom Operation

After applying our Custom Operator, the computational graph should now resemble the image below:

Screenshot 2025-02-07 at 3.20.41 PM.png

3. Compile and Profile the Voxel Pooling Operator Using ChimeraJob with Real Inputs

Next, we’ll compile and profile the operator using ChimeraJob. We’ll also use real input data since the algorithm’s performance is data-dependent.

from tvm.contrib.epu.chimera_job.chimera_job import ChimeraJob
import numpy as np

cgc_job = ChimeraJob(
    "voxel_opt.onnx",
    region_timeout=3600,  # In case of slower CPU.
)

data = np.load("voxel_pooling_inputs.npy", allow_pickle=True).item()
geom_xyz_reshaped = data["geom_xyz"].reshape(1, 1, 473088, 3)  # Reshape Data To 4D
img_feat_reshaped = data["img_feat_with_depth"].reshape(1, 1, 473088, 80)  # Reshape Data To 4D

cgc_job.run_inference_harness(
    compare_ort=False,
    inputs={"geom_xyz": geom_xyz_reshaped, "img_feat_with_depth": img_feat_reshaped},
)
cgc_job.plot_run_statistics()
print(cgc_job)
/usr/local/lib/python3.10/dist-packages/tvm/relay/frontend/onnx.py:6270: UserWarning: No Op registered for VoxelPooling with domain_version of 16

==> Context: Bad node spec for node. Name: CustomOp/nn::voxelPooling0 OpType: QuadricCustomOp
  warnings.warn(str(e))
2026-07-18 12:09 - INFO - epu - iss_testing - No tranges found for input, use default float range: <tvm.contrib.epu.interval.Interval object at 0x7beee2bd25f0>
2026-07-18 12:09 - INFO - epu - iss_testing - No tranges found for input, use default float range: <tvm.contrib.epu.interval.Interval object at 0x7beee2bd25f0>
FILM 3/3: 100%|██████████████████████████████████████████████████████| 3/3 [18:04<00:00, 361.49s/it]
2026-07-18 12:28 - INFO - epu - chimera_job - Combined plots generated and saved to: 
/quadric/sdk-cli/examples/custom_op/voxel_pooling/ccl_build/voxel_opt_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260718_120929_cf37a7/data/voxel_opt_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1.combined.png



╒═════════════════════╤══════════════════════════════════════════════════════════╕
 Module Name          voxel_opt_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1 
├─────────────────────┼──────────────────────────────────────────────────────────┤
 ONNX File            voxel_opt.onnx                                           
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Product Target       QC-U                                                     
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Number of Cores      1                                                        
├─────────────────────┼──────────────────────────────────────────────────────────┤
 ISS Clock Frequency  1.700                                                    
├─────────────────────┼──────────────────────────────────────────────────────────┤
 L2M Size             16MB                                                     
├─────────────────────┼──────────────────────────────────────────────────────────┤
 LRM Size             4kB                                                      
├─────────────────────┼──────────────────────────────────────────────────────────┤
 External Read BW     128GBps                                                  
├─────────────────────┼──────────────────────────────────────────────────────────┤
 External Write BW    128GBps                                                  
├─────────────────────┼──────────────────────────────────────────────────────────┤
 MACS per PE          16                                                       
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Max L2M              6.250MB                                                  
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Max LRM              0.391kB                                                  
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Max Temp Ext Bytes   37.344MB                                                 
├─────────────────────┼──────────────────────────────────────────────────────────┤
 Network GMACs                                                                 
╘═════════════════════╧══════════════════════════════════════════════════════════╛

╒════╤════════╤═════════════════════╤════════════════════╤══════════════════════════╤═══════╕
     Type    Name                 shape               type                      mse   
╞════╪════════╪═════════════════════╪════════════════════╪══════════════════════════╪═══════╡
  0  Input   img_feat_with_depth  [1, 1, 473088, 80]  tensor[FixedPoint32<27>]  n/a   
├────┼────────┼─────────────────────┼────────────────────┼──────────────────────────┼───────┤
  1  Input   geom_xyz             [1, 1, 473088, 3]   tensor[int32]             n/a   
├────┼────────┼─────────────────────┼────────────────────┼──────────────────────────┼───────┤
  2  Output  output               [1, 80, 128, 128]   tensor[int32]             n/a   
╘════╧════════╧═════════════════════╧════════════════════╧══════════════════════════╧═══════╛

Post-ISS Report 1.7 GHz ***
Fully placed-and-routed gate simulation: 
╒══════════════════════════════════╤═════════╕
 Latency (ms)                        39.7  
├──────────────────────────────────┼─────────┤
 FPS                                 25.19 
├──────────────────────────────────┼─────────┤
 Average Power @ 3nm SSGNP (mW)    2187.12 
├──────────────────────────────────┼─────────┤
 FPS per Watt @ 3nm SSGNP (FPS/W)    11.52 
├──────────────────────────────────┼─────────┤
 Ext Rd Bytes (MB)                  216.01 
├──────────────────────────────────┼─────────┤
 Ext Wr Bytes (MB)                   42.34 
├──────────────────────────────────┼─────────┤
 Avg Ext Rd BW (GBps)                 5.31 
├──────────────────────────────────┼─────────┤
 Avg Ext Wr BW (GBps)                 1.04 
╘══════════════════════════════════╧═════════╛
*** Data generated using 7nm SSGNP gatesim and scaled to 3nm

[SDK-CLI] : TotalCycles: 67,484,896
[SDK-CLI] : Executions/second: 25.19

compute      : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 36.702M
data_array   : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 10.303M
mac          :  0
data_external:  105.71K
data_ocm     : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 20.371M

for more information check run directory: /quadric/sdk-cli/examples/custom_op/voxel_pooling/ccl_build/voxel_opt_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260718_120929_cf37a7

Note how FILM Region 2/3 takes ~60M cycles, this region represents the nn::voxelPooling operator as seen in the CCL code generated by the compiler below

  cgc::profileStart("region: 2 / 3");
  free_core_memory(cgc_core_stack_pointer, 800);
  DdrTensor<int8_t, 1, 80, 128, 128> ext_tensor_1(pExtTempsPtr + 37847040);
  nn::voxelPooling(input_geom_xyz, ext_tensor_0, ext_tensor_1, mem_allocator) /* CustomOp/nn::voxelPooling0 */ ;
  cgc::profileStop("region: 2 / 3");
Table of Contents
Introduction to the Chimera SDK
Chimera SDK Quick Start Guide
Chimera SDK Command Line Interface (CLI)
Tutorial: Using SDK as a Library
Tutorials & Model Demos
Custom Op Tutorials
Multicore Demo
Chimera LLVM C++ Compiler
Chimera SDK Licensing Policy Documentation
Glossary

Sign in to your account

Don't have an account? Create an Account
By signing in, you are agreeing to our Terms of Use and Privacy Policy.

Develop.

Simulate.

Profile.

Collaborate.