Skip to content

chamfer

Chamfer distance between packed point sets.

Classes:

ChamferDistance [source] ΒΆ

ChamferDistance(norm: Literal['l1', 'l2'] = 'l2')

Bases: Module

Module form of chamfer_distance.

The reconstruction criterion of the masked point modeling models, whose pretraining forward returns the (pred, target, pred_batch, target_batch) tuple this module takes.

Parameters:

  • norm (Literal['l1', 'l2'], default: 'l2' ) –

    Distance variant, "l1" (euclidean) or "l2" (squared euclidean).

Example
import torch
from torch_pointcloud.losses import ChamferDistance

criterion = ChamferDistance(norm="l1")
criterion(torch.zeros(8, 3), torch.zeros(4, 3)).item()  # 0.0

Methods:

  • forward –

    Compute the Chamfer distance between the packed sets pred \((N, 3)\) and target \((M, 3)\).

forward [source] ΒΆ

forward(
    pred: Tensor,
    target: Tensor,
    pred_batch: Optional[Tensor] = None,
    target_batch: Optional[Tensor] = None,
) -> Tensor

Compute the Chamfer distance between the packed sets pred \((N, 3)\) and target \((M, 3)\).

chamfer_distance [source] ΒΆ

chamfer_distance(
    pred: Tensor,
    target: Tensor,
    *,
    pred_batch: Optional[Tensor] = None,
    target_batch: Optional[Tensor] = None,
    norm: Literal["l1", "l2"] = "l2",
) -> Tensor

Symmetric Chamfer distance between packed point sets.

Set-to-set reconstruction objective introduced for point cloud generation in A Point Set Generation Network for 3D Object Reconstruction from a Single Image (Fan et al., 2017) and standard for masked point modeling pretraining. Every point is matched to its nearest neighbor in the other set of the same index (its group, its scene), and the squared euclidean distances are averaged over all points:

\[\text{CD}_{\ell_2} = \frac{1}{N} \sum_i \min_j \lVert p_i - q_j \rVert_2^2 + \frac{1}{M} \sum_j \min_i \lVert p_i - q_j \rVert_2^2\]
\[\text{CD}_{\ell_1} = \frac{1}{2} \Big( \frac{1}{N} \sum_i \min_j \lVert p_i - q_j \rVert_2 + \frac{1}{M} \sum_j \min_i \lVert p_i - q_j \rVert_2 \Big)\]

The "l2" variant sums the two directed means of squared distances (no square root, no halving); the "l1" variant averages the two directed means of euclidean distances. Both follow the reference pretraining convention, so losses are comparable with published values.

The nearest neighbors come from the sided_distance kernel of kaolin when it is installed and the points are on CUDA, otherwise from the kNN kernel of torch_geometric (pyg-lib); either way without autograd, and only the matched pairs are differentiated, so the memory grows with \(N + M\) rather than \(N \cdot M\) and whole clouds fit. Without either kernel the search falls back to the dense distance matrix.

Parameters:

  • pred (Tensor) –

    Predicted points of every set, packed, shape \((N, 3)\).

  • target (Tensor) –

    Target points of every set, packed, shape \((M, 3)\).

  • pred_batch (Optional[Tensor], default: None ) –

    Set index of every predicted point (sorted), shape \((N,)\); None for a single set.

  • target_batch (Optional[Tensor], default: None ) –

    Set index of every target point (sorted), shape \((M,)\); None for a single set.

  • norm (Literal['l1', 'l2'], default: 'l2' ) –

    Distance variant, "l1" (euclidean) or "l2" (squared euclidean).

Returns:

  • Tensor –

    Scalar Chamfer distance averaged over all points.

Shape
  • pred: \((N, 3)\)
  • target: \((M, 3)\)
  • pred_batch: \((N,)\)
  • target_batch: \((M,)\)
  • output: scalar
Example
import torch
from torch_pointcloud.losses import chamfer_distance

pred = torch.randn(64 * 32, 3, requires_grad=True)
target = torch.randn(64 * 32, 3)
batch = torch.arange(64).repeat_interleave(32)
loss = chamfer_distance(pred, target, pred_batch=batch, target_batch=batch)
loss.backward()
print(loss.shape)