Quick Start¶
This page will help you get started and run a pretrained model on a point cloud.
Run a pretrained model¶
The example reads one object of the ModelNet40 test set, which
ModelNetNormalResampled downloads on first use:
import torch
import torch_pointcloud as tp
from torch_pointcloud.datasets import ModelNetNormalResampled
from torch_pointcloud.utils.data import collate
# Instantiate the model and return associated info.
model, info = tp.create_model(
"pointnet2-ssg.modelnet40.xu-yan",
task="classification",
pretrained=True,
return_info=True,
)
model = model.eval()
# Get associated transform for inference.
transform = info["transform"]
# Load input data. The dataset applies the transform, which samples points and normals together.
dataset = ModelNetNormalResampled(root="data", variant="40", train=False, download=True, transform=transform)
sample = dataset[0]
# Pack into a batch. The provided `collate` function
# handles the packed-batch convention, but you can use your own.
batch = collate([sample])
# Forward pass. Models take packed batches, never padded (B, N, ...) tensors.
with torch.no_grad():
logits = model(batch.get("x"), batch["pos"], batch["batch"])
classes = info["weights"]["classes"]
top = logits.softmax(dim=-1).topk(3, dim=-1)
for index, score in zip(top.indices[0].tolist(), top.values[0].tolist()):
print(f"{classes[index]:>12} {score:.2f}")

The packed-batch convention comes from PyTorch Geometric: instead of zero-padding clouds to a common size, we concatenate them and tag each point with its sample index. See Data conventions below.
Using a real dataset¶
The same model, over a whole dataset. ModelNetNormalResampled is what this checkpoint was trained on: each shape
ships as 10,000 surface points with their normals, which is why the snippet above builds a normal key.
It downloads on first use.
import torch
import torch_pointcloud.transforms as T
from torch_pointcloud.datasets import ModelNetNormalResampled
from torch_pointcloud.utils.data import PointCloudDataLoader
dataset = ModelNetNormalResampled(
root="data",
variant="40",
train=False,
download=True,
transform=info["transform"],
)
dataloader = PointCloudDataLoader(dataset, batch_size=32)
with torch.no_grad():
for data in dataloader:
logits = model(data.get("x"), data["pos"], data["batch"])
preds = logits.argmax(dim=-1) # (32,) one class per cloud
break
PointCloudDataLoader is a DataLoader with the packed-batch collate wired in: per-point tensors are
concatenated along the batch axis and a batch index is built for you, while scene-level tensors (label)
are stacked.
Data conventions¶
All point clouds use a packed (flat-batch) format (a.k.a. ragged tensors). This is what PyTorch Geometric uses. For a batch of \(B\) samples with \(N_i\) points each (\(N = N_1 + N_2 + \ldots + N_B\)):

| Tensor | Shape | Description |
|---|---|---|
pos |
\((N, 3)\) | 3D coordinates, all points concatenated |
x |
\((N, C)\) | Per-point features |
batch |
\((N,)\) | Per-point batch index \((0, \ldots, B-1)\) |
normal, color |
\((N, 3)\) | Per-point attributes |
segment |
\((N,)\) | Per-point semantic label |
label |
\((B,)\) | Scene / object-level label |