Skip to content
Search

Pointcept:SmallObjectAnalysis

lastmod 2026-09-14created 2026-09-141 edits

Procedure for analyzing why PointGroup misses small objects

Background

  • Running instance segmentation with Pointcept's PointGroup (PG-v1m1, SpUNet backbone)
  • Quality was low with the initial 100 scans, so about 600 more PointClouds were added for training
  • Even with more data, small objects are still not detected

Summary of conclusions

When small objects are still missed after adding data, the cause is usually not "the amount of data" but one of the three below.

  1. Size filters hard-coded in the pipeline
  2. Misses in the semantic branch
  3. Large-object bias in offset regression

Proceed in an order that checks these three separately.

Structural cause: size filters hard-coded in the code

Reference files:

  • configs/scannet/insseg-pointgroup-v1m1-0-spunet-base.py
  • pointcept/models/point_group/point_group_v1m1_base.py
  • pointcept/engines/hooks/evaluator.py

The PointGroup code has at least four places that filter out small objects. All are in units of grid_size=0.02 voxels.

Location

Default

Effect

GridSample grid_size

0.02

2cm voxelization. Point counts of small objects drop sharply

cluster_min_points (bfs_cluster)

50

Clusters with fewer than 50 points are not created

cluster_propose_points

100

Proposals with 100 points or fewer are discarded (point_group_v1m1_base.py:154)

evaluator min_region_sizes

100

Predictions with fewer than 100 points are excluded from evaluation (evaluator.py:339)

In other words, objects with 100 points or fewer after voxelization are not output even if the model gets them right, and not evaluated even if output. Increasing the data sixfold leaves this wall in place.

Other structural factors

  • Clustering only groups points with the same segment_pred. If the semantic branch classifies a small class as wall/floor, it never reaches the instance stage at all.
  • The offset loss is a per-point average, so large objects dominate the gradient. Center predictions for small objects are noisy, so they easily get merged with neighboring objects or split apart within cluster_thresh=1.5 (3cm).

Procedure

1. Data statistics

  • Compute the number of instances per class and the distribution of points per instance, measured after applying GridSample 0.02
  • Ratio of instances with fewer than 100 points = ratio that is structurally undetectable
  • Check the label quality of the 600 added scans
    • Whether small objects are labeled consistently
    • Whether instance ids are unique within a scene
    • Whether the sensor/point density matches the original 100 scans

2. Check the semantic upper bound

  • Check per-class semantic IoU on the validation set
  • If IoU for small classes is low, it is a semantic problem, not an instance problem
  • Remedy: class-weighted CE, oversampling scenes containing small objects, reducing grid_size

3. Isolate branches with oracle experiments

Experiment

If AP rises sharply

Cluster with GT semantic + predicted offset

Semantic branch problem

Cluster with predicted semantic + GT centroid

Offset branch problem

If neither rises, it is a filter or label problem.

4. Filter relaxation experiment

Just rerun test without retraining.

Parameter

Default

Relaxed value

cluster_min_points

50

10

cluster_propose_points

100

20

evaluator min_region_sizes

100

20

If AP25 recovers, the model was already detecting them and the filters were throwing them away.

5. Classify failure types

Compare predictions against each small-object GT and tag them into four types.

  1. Semantic miss
  2. Merged into a neighboring object
  3. Split into multiple fragments
  4. Discarded by a size filter

This distribution determines the final remedy.

6. Check training status

  • Going from 100 → 700 scans means 7x the iterations even at the same 800 epochs
  • Check the training curve together with AP on the train set
    • If small classes are missed even on train, it is underfitting or a label problem
    • If they are detected on train but not on val, it is a generalization problem

Candidate remedies

  • grid_size 0.02 → 0.01 (2–4x more memory, the most direct fix for small objects)
  • Normalize the offset loss per instance, or give more weight to small instances
  • Class weights in the semantic CE, repeated sampling of scenes containing small objects
  • Check whether SphereCrop sample_rate=0.8 crops out small objects
  • If it is a limitation of PointGroup itself, consider the query-based SGIFormer
    • configs/scannetpp/insseg-sgiformer-v1m1-0-ptv3-base.py

See also

author Zer0 sitemap