Skip to content
AI360Xpert
Beta

PointNet and PointNet++ on Raw Points

Points arrive shuffled with no grid. PointNet reads each point alone then max-pools so order never matters; PointNet++ adds local neighborhoods.

Per-point MLPs max-pool into one global vector while hierarchy adds local groups
Per-point MLPs max-pool into one global vector while hierarchy adds local groups

Why Does This Exist?

Point clouds are sets: shuffling 10241024 points must not change the answer, which rules out plain sequence nets. PointNet exists as the order-free baseline that point cloud processing introduces: shared MLPs plus symmetric pooling. PointNet++ fixes its blindness to local curves by grouping neighborhoods hierarchically. The architecture-deep version lives in core ML PointNet; this page is the vision use and the merged Plus upgrade.

Graph and attention successors are DGCNN and Point Transformer.

Think of It Like This

Judging Lego builds from sorted piles

Dump two identical Lego builds on tables in different orders and judge by counting brick types, not sequence. Then zoom into wheels and windows locally before judging the whole castle.

Max-pooling is the counting and set abstraction is the zoom. The analogy stops at rotation: brick counts ignore pose while points need alignment, handled by a small spatial transformer.

How It Actually Works

PointNet maps each point pip_i through shared h(pi)h(p_i) into 10241024 dims, then g=max⁡ih(pi)g = \max_i h(p_i) gives permutation invariance since max ignores order. A mini spatial transformer predicts a 3×33 \times 3 alignment from the cloud itself. PointNet++ samples farthest points, balls rr-neighborhoods around each, runs mini-PointNets locally, and repeats: set abstraction layers shrink 10241024 to 256256 to 6464 centroids with growing radii 0.10.1, 0.20.2, 0.40.4 m, capturing curves at multiple scales.

Worked numbers

Four points (0,0,0)(0,0,0), (1,0,0)(1,0,0), (0,1,0)(0,1,0), (0,0,1)(0,0,1) through h(p)=[x+y,z]h(p) = [x + y, z] give [0,0][0,0], [1,0][1,0], [1,0][1,0], [0,1][0,1]; max-pool gives [1,1][1,1] regardless of input order. Shuffling the list returns the same [1,1][1,1]. On ModelNet40 with 10241024 points, reference accuracy moves from about 8989 percent PointNet to 9191 percent PointNet++.

Code

def pointnet_pool(feats: list[list[float]]) -> list[float]:    dims = len(feats[0])    return [max(f[d] for f in feats) for d in range(dims)]  # symmetric: order-free

print(pointnet_pool([[0, 0], [1, 0], [1, 0], [0, 1]]))  # -> [1, 1]

Watch Out For

Expecting fine local detail from vanilla PointNet

Global pooling keeps one max per channel, so small handles and thin legs vanish. The symptom is great classification with blobby segmentations. Use PointNet++ grouping or a local operator such as KPConv when parts matter.

The Quick Version

  • PointNet reads raw points with shared MLPs plus max-pooling for order freedom.
  • Shuffled inputs give identical global vectors by construction.
  • A learned 3×33 \times 3 transform adds rough rotation robustness.
  • PointNet++ groups neighborhoods hierarchically for local geometry.
  • Reference ModelNet40 rises from 8989 to 9191 percent with hierarchy.
  • Use Plus or local operators when parts and curves matter.