Paper Walkthroughs
3D Object DetectionPart 9

Voxel R-CNN: refinement from voxels alone

Do we really need raw points to refine a box? Voxel R-CNN pools RoI features straight from the sparse 3D voxel volumes, with a voxel query in place of the ball query — PV-RCNN accuracy at about three times the speed.

October 30, 2026 · 9 min read

Motivation & Main Contribution

  • By 2020 the leaderboards were led by point-based or point–voxel detectors (PointRCNN, STD, 3DSSD, PV-RCNN), and the common belief was: precise raw-point positions are needed for accurate boxes.
  • Voxel R-CNN tests that belief and rejects it: coarse voxels are enough, if the second stage reads the 3D voxel features instead of only the BEV map.
  • Design: SECOND-style 3D sparse backbone → 2D BEV backbone + RPN → voxel RoI pooling → detect head. No keypoints, no raw points in the second stage.
  • Main contributions:
    1. Voxel RoI pooling — RoI-grid features pooled directly from sparse 3D voxel volumes.
    2. Voxel query — neighbour search by voxel indices instead of PointNet++ ball query.
    3. Accelerated PointNet module — split the first FC layer to cut the cost of local aggregation.
  • Result: PV-RCNN-level accuracy on KITTI at 25.2 FPS vs. 8.9 FPS for PV-RCNN.

Challenges at the Time

  • The paper’s own diagnosis compares SECOND and PV-RCNN on KITTI val (car, moderate, R11):
    • SECOND: 78.62 AP. Adding a BEV detect head (rotated RoI Align on the BEV map): only 79.26 (+0.6).
    • PV-RCNN: 83.69. So box refinement helps a bit, but BEV features alone are too limited — 3D structure is what matters (Table 1).
  • Point–voxel interaction is slow. In PV-RCNN, VSA takes 49.4 ms of about 99 ms per frame — 3D backbone 21.1 ms, 2D backbone 9.4 ms, detect head 19.1 ms (Table 2).
  • Ball query on voxels is still expensive: finding neighbours of a query point among NN voxels is O(N)O(N).

Naive Questions

  • If voxels lose precise positions, how can refinement work without raw points? The voxel features already encode local geometry; the experiments show that is almost sufficient.
  • Why not RoI-pool from the BEV map, like a 2D detector? Tried in the paper: +0.6 AP only. The height structure is gone in BEV.
  • Why not max-pool the voxels inside each sub-cell, like Fast R-CNN’s RoI pooling? Fewer than 3% of voxels are non-empty; most sub-cells would be empty.
  • What is wrong with ball query? Nothing in accuracy — it is just slow. Voxels sit on a grid, so neighbours can be looked up by index.
  • Why the Manhattan distance? On voxel indices it is cheap to compute and enumerate: add offsets like (Δi,Δj,Δk)∈{−1,0,1}3(\Delta i, \Delta j, \Delta k) \in \{-1, 0, 1\}^3.
  • Is this just PV-RCNN without keypoints? Roughly, yes — the RoI-grid idea stays, the keypoint detour goes.

Key Idea

Key idea. Keep the whole detector in voxels: pool each proposal’s grid-point features directly from the sparse 3D feature volumes, using index-based voxel queries instead of point-based ball queries.

For grid point gig_i with its queried neighbour voxels {vi1,…,viK}\{v_i^1, \dots, v_i^K\}:

ηi=max⁡k=1,…,K{Ψ([ vik−gi ; ϕik ])}\eta_i = \max_{k = 1, \dots, K} \Big\{ \Psi\big( [\, v_i^k - g_i \,;\, \phi_i^k \,] \big) \Big\}
  • vik−giv_i^k - g_i: relative position of voxel centre kk; ϕik\phi_i^k: its feature; Ψ\Psi: an MLP; max⁡\max: channel-wise max pool — the PointNet recipe once more, now on voxel centres.

Builds on. PointNet’s shared MLP + max pool (walkthrough 01).

Voxel query uses the Manhattan distance on voxel indices:

Dm(α,β)=∣iα−iβ∣+∣jα−jβ∣+∣kα−kβ∣D_m(\alpha, \beta) = |i_\alpha - i_\beta| + |j_\alpha - j_\beta| + |k_\alpha - k_\beta|

Dive into Model Architecture & Key Components

Voxel R-CNN from raw points to boxes, laid out like the paper’s Figure 2 (KITTI settings): a SECOND-style 3D backbone and BEV RPN give the proposals; voxel RoI pooling reads the 3D voxel features of the last two backbone stages straight from the sparse volumes — no keypoints, no raw points. One block per row of the table below; solid blocks are learned layers, dashed ones fixed operations.

The pipeline, step by step

  1. Voxelize the scan.
  2. 3D backbone: sparse 3D convolutions, four stages (SECOND / PV-RCNN design).
  3. BEV: stack the output along Z into a BEV map.
  4. 2D backbone + RPN: two conv blocks, multi-scale fusion, two sibling 1×11 \times 1 convs → anchor proposals.
  5. Proposals: NMS with IoU 0.7, keep top 100.
  6. Voxel RoI pooling: 6×6×66 \times 6 \times 6 grid per proposal; features from the last two 3D stages, two query distances per stage.
  7. Detect head: shared 2-layer MLP → box-residual branch and IoU-guided confidence branch; final NMS with IoU 0.1.

Builds on. SECOND’s sparse 3D backbone and BEV RPN (walkthrough 04), and PV-RCNN’s RoI grid and IoU-guided scoring (walkthrough 07).

Tensor shapes (KITTI)

StageOperation → purposeShape
Input rangeX [0,70.4][0, 70.4] m, Y [−40,40][-40, 40] m, Z [−3,1][-3, 1] m → the region that is voxelizedraw points
Voxel gridvoxel size (0.05,0.05,0.1)(0.05, 0.05, 0.1) m → fine voxels for the sparse CNN1408×1600×401408 \times 1600 \times 40 (range ÷ voxel size)
3D backbonefour sparse-conv stages → multi-scale 3D voxel features, kept for the second stage16, 32, 48, 64 channels
2D backbonestack along Z into BEV; block 1 (same X–Y resolution as 3D output), block 2 (half) → BEV features for the proposals5 conv layers each; 64, 128 channels
RPNanchor-based BEV head, NMS IoU 0.7 → high-recall proposalstop 100 proposals
Voxel RoI poolinggrid per proposal; query distances 2 and 4 → box features straight from the 3D voxels, no raw points6×6×6=2166 \times 6 \times 6 = 216 grid points; 32 channels per aggregation
Detect headshared 2-layer MLP, two branches → a refined box and an IoU-aware scorebox residual + IoU score per proposal
  • Waymo: range [−75.2,75.2][-75.2, 75.2] m in X and Y, [−2,4][-2, 4] m in Z; voxel size (0.1,0.1,0.15)(0.1, 0.1, 0.15) m; 2D channels (128, 256); aggregation output 64 channels.

Voxel query: neighbours by index

  • Treat the sparse volume as a set of non-empty voxel centres {vi}\{v_i\} with features {ϕi}\{\phi_i\}.
  • Quantise the query point to a voxel, then reach its neighbours by index offsets; keep up to KK voxels within a Manhattan-distance threshold.
  • Cost: O(K)O(K) per query, vs. O(N)O(N) for a ball query over NN non-empty voxels.
Voxel RoI pooling around a real car, on the 8×8\times-downsampled voxels seen from above (the query is drawn in 2D, as in the paper’s own figure). Most of the 6×6×66 \times 6 \times 6 sub-voxels hold no point, so each grid point gathers neighbouring voxels instead: a ball query must check every non-empty voxel of the scan, the voxel query only steps through index offsets within Manhattan distance 2 and 4. A shared MLP and a max pool then give the grid point’s feature.

Voxel RoI pooling

  • Divide each proposal into G×G×GG \times G \times G sub-voxels (G=6G = 6); each sub-voxel centre is a grid point.
  • Because the volume is so sparse (< 3% non-empty), do not max-pool inside sub-voxels — instead, gather neighbouring voxels around each grid point with voxel query and aggregate them with the PointNet module above.
  • Pool from the last two 3D stages, two distance thresholds each, and concatenate the four results as the RoI feature.
  • Compared with PV-RCNN: the same idea of grid points inside the box, but they look up voxels, not keypoints.

Accelerated local aggregation

  • With M=r×G3M = r \times G^3 grid points (rr RoIs) and KK voxels each, the first FC layer on [coords;feature][\text{coords}; \text{feature}] costs O(M×K×(C+3)×C′)O(M \times K \times (C + 3) \times C').
  • Split its weight W∈RC′×(C+3)W \in \mathbb{R}^{C' \times (C+3)} into WF∈RC′×CW_F \in \mathbb{R}^{C' \times C} (features) and WC∈RC′×3W_C \in \mathbb{R}^{C' \times 3} (coordinates):
    • apply WFW_F once per voxel, before the query;
    • after the query, apply only WCW_C to the relative coordinates and add.
  • New cost: O(N×C×C′+M×K×3×C′)O(N \times C \times C' + M \times K \times 3 \times C') — cheaper, since M×KM \times K is an order of magnitude larger than NN.
The accelerated PointNet module, after the paper’s Figure 4. Splitting the first FC layer lets its feature part run once per non-empty voxel before the query; after the query only the 3 relative coordinates are multiplied. The FLOP counts use C=64C = 64, C′=32C' = 32 and M⋅K=10 NM \cdot K = 10\,N for illustration — the paper only states that M⋅KM \cdot K is an order of magnitude larger than NN.

Losses

  • RPN (as SECOND / PointPillars): focal loss for classification, Huber loss for box regression on foreground anchors.
  • Detect head: IoU-shaped confidence target
li∗(IoUi)={0IoUi<θLIoUi−θLθH−θLθL≤IoUi<θH1IoUi>θHθL=0.25,  θH=0.75l_i^*(\mathrm{IoU}_i) = \begin{cases} 0 & \mathrm{IoU}_i < \theta_L \\ \dfrac{\mathrm{IoU}_i - \theta_L}{\theta_H - \theta_L} & \theta_L \le \mathrm{IoU}_i < \theta_H \\ 1 & \mathrm{IoU}_i > \theta_H \end{cases} \qquad \theta_L = 0.25,\; \theta_H = 0.75
  • Binary cross-entropy on li∗l_i^*; Huber loss for box residuals on proposals with IoU ≥ θreg=0.55\theta_{reg} = 0.55.
  • 128 sampled RoIs per scene, half of them positive. Trained end to end with Adam, lr 0.01, cosine annealing (KITTI: 80 epochs, batch 16). Implemented in OpenPCDet.

Conclusion

Results

KITTI test set, car 3D AP with 40 recall positions, and speed (Voxel R-CNN, Table 3):

MethodTypeFPS ↑Easy ↑Moderate ↑Hard ↑
PointRCNNpoint10.086.9675.6470.70
STDpoint12.587.9579.7175.09
3DSSDpoint26.388.3679.5774.55
PV-RCNNpoint–voxel8.990.2581.4376.82
SECONDvoxel30.483.3472.5565.82
PointPillarsvoxel42.482.5874.3168.99
SA-SSDvoxel25.088.7579.7974.16
Voxel R-CNNvoxel25.290.9081.6277.06

KITTI val set, car 3D AP with 11 recall positions (Table 5):

MethodEasy ↑Moderate ↑Hard ↑
PointRCNN88.8878.6377.38
STD89.7079.8079.30
PV-RCNN89.3583.6978.70
SECOND88.6178.6277.22
SA-SSD90.1579.9178.78
Voxel R-CNN89.4184.5278.93

Waymo Open Dataset (val), vehicle, LEVEL 1 3D mAP at IoU 0.7 (Table 6):

MethodOverall ↑0–30 m ↑30–50 m ↑50 m–∞ ↑
PointPillars56.6281.0151.7527.94
MVF62.9386.3060.0236.02
Pillar-OD69.8088.5366.5042.93
PV-RCNN70.3091.9269.2142.17
Voxel R-CNN75.5992.4974.0953.15

Ablation on KITTI val, car moderate 3D AP (R11) and speed (Table 7):

ConfigurationModerate AP ↑FPS ↑
one-stage BEV baseline77.9940.8
+ detect head (ball query, original PointNet module)84.2117.4
full Voxel R-CNN (voxel query + accelerated PointNet)84.5225.2

Pros and Cons

  • Pros
    • PV-RCNN-level accuracy from voxels alone, about three times faster (25.2 vs 8.9 FPS).
    • Voxel query uses the grid: neighbours by index, O(K)O(K) instead of O(N)O(N).
    • Splitting the first FC layer removes most of the per-neighbour compute.
    • Biggest gains far away on Waymo (+10.98 mAP beyond 50 m over PV-RCNN).
  • Cons
    • Still anchor-based proposals from a BEV RPN.
    • Sparse convolutions keep a local receptive field.
    • LiDAR only: far and small objects stay sparse.

Future Work

  • Wider context than local sparse convolutions — e.g. attention over sparse voxels.
  • Fusing camera images to help where LiDAR points are scarce.

Next

  • This closes the nine core papers. Next on the list (no walkthrough yet): transformers on sparse voxels (SST, DSVT) and LiDAR–camera fusion (BEVFusion).