Heads and assigners¶
--set head=--set assigner=14 optionsThe head bundle predicts the grasp at every seed: in-plane rotation, depth, width and score. The assigner matches every seed with the grasp labels it is trained on.
Use it¶
grasppanda compose graspnet_baseline/graspnet-baseline_pointnet2_g1b-realsense_18e \
--set head=swad-focal -o graspnet-baseline_swad-focal.yaml
grasppanda compose graspnet_baseline/graspnet-baseline_pointnet2_g1b-realsense_18e --list head
grasppanda compose gsnet/gsnet_sunet14_g1b-realsense_10e \
--set head=swad-focal -o gsnet_swad-focal.yaml
grasppanda compose gsnet/gsnet_sunet14_g1b-realsense_10e --list head
grasppanda compose scale_balanced_grasp/sbg_pointnet2-transformer_g1b-realsense_18e \
--set head=swad-focal -o scale-balanced-grasp_swad-focal.yaml
grasppanda compose scale_balanced_grasp/sbg_pointnet2-transformer_g1b-realsense_18e --list head
grasppanda compose economicgrasp/economicgrasp_sunet14_g1b-realsense_10e \
--set head=swad-focal -o economicgrasp_swad-focal.yaml
grasppanda compose economicgrasp/economicgrasp_sunet14_g1b-realsense_10e --list head
grasppanda compose finegrasp/finegrasp_sunet14_g1b-realsense_10e \
--set head=swad-focal -o finegrasp_swad-focal.yaml
grasppanda compose finegrasp/finegrasp_sunet14_g1b-realsense_10e --list head
The first command writes a checked config; the second lists every option of the slot under that method, with what was measured. Then grasppanda probe <file> tries the config on real frames and grasppanda train <file> trains it (Swap a component). Each method page lists the same: GraspNet-baseline · GSNet · Scale-Balanced-Grasp · EconomicGrasp · FineGrasp.
An assigner is set the same way, --set assigner=<option>.
Options¶
A probe shows that a combination trains on real frames of GraspNet-1Billion, not how good it is. Accuracy is claimed only for a method trained and evaluated here.
Head bundles
Assigners
What the columns say, and who is left out
- Runs: out of the methods the option is a swap under, those under which its probe trained on real frames without error. A method that ships the option is named own and not counted; a method still undecided is counted and named. Measured on 20 training iterations on 8 RealSense frames of GraspNet-1Billion (one scene), seed 0, one run per cell; nothing was measured on GraspClutter6D or on Kinect frames.
- Trains like shipped: out of the methods under which the swap ran, those under which every comparable loss term ended within the method's tolerance of the component it ships, with nothing rising; a method left out is named with why. Measured on 250 iterations on 8 RealSense frames of GraspNet-1Billion (one scene), seed 0, at a constant learning rate (FineGrasp: its own warm-up), beside the method as shipped trained the same way twice.
- How we measure defines every word of these columns.
Who is left out, and why:
economic, runs: own in EconomicGrasp, FineGrasp; not GraspNet-baseline, Scale-Balanced-Grasp (incompatible by design).economic-focal, runs: not GraspNet-baseline, Scale-Balanced-Grasp (incompatible by design).nearest-label-object-seeds, runs: own in GraspNet-baseline; not EconomicGrasp, FineGrasp (incompatible by design).NearestLabelAssigner, runs: own in GSNet; not EconomicGrasp, FineGrasp (incompatible by design).NearestLabelAssigner, trains like shipped: not comparable under GraspNet-baseline; diverging under Scale-Balanced-Grasp.scale-balanced, runs: own in Scale-Balanced-Grasp; not EconomicGrasp, FineGrasp (incompatible by design).
Sources and extras
The work each option follows; extra: the optional install it needs (every extra).
| Source | Options |
|---|---|
| After the grasp head of FGC-GraspNet (Lu et al., ICRA 2022), written here; width bins with the distribution focal loss of Generalized Focal Loss (Li et al., NeurIPS 2020) | decoupled-grid, decoupled-grid-bins, decoupled-grid-class, decoupled-grid-regression |
| EconomicGrasp (Wu et al., ECCV 2024) | economic, economic-focal, compact-label |
| GraspNet-baseline (Fang et al., CVPR 2020) | operation, operation-objectness |
| GSNet (Wang et al., ICCV 2021) | swad, swad-focal |
| Label matching of GraspNet-baseline and GSNet | nearest-label-object-seeds, NearestLabelAssigner |
| Scale-Balanced-Grasp (Ma and Huang, CoRL 2022) | scale-balanced |
Compare under every method: head bundles · assigners
Choosing¶
- A head is swapped whole. Its network, target encoder, loss and decoder share one way of writing a grasp. Its loss terms are swapped one by one on Losses.
- Head, assigner and labels go together. A head is trained on dense label grids or on compact best grasps; compose switches the assigner and the dataset section to the head's label set and says so.
- The crop decides the head. A head reads one feature per seed or one per depth bin; Grouper lists which crop gives which.
- Classify or regress depth and width:
decoupled-grid-classanddecoupled-grid-regressionare the two ends;decoupled-grid-binspredicts the width as a distribution. - Scores of two heads are not comparable. A score threshold fitted to one head does not carry over to another.
Details¶
Input and output of a head bundle
class HeadBundle(nn.Module):
def forward(self, crops: GroupFeatures) -> Predictions: ... # raw outputs, with gradients
def encode(self, matched: MatchedLabels, ...) -> Targets: ... # labels -> targets
def loss(self, predictions, targets, ...) -> dict[str, Tensor]: # named, weighted terms
def decode(self, raw, seeds, approach, gripper) -> GraspGroup: ... # one grasp per seed
| in: crop features | from the grouper, one row per valid seed, with the grouper's out_axes: ('seed', 'channel') or ('seed', 'depth', 'channel'). |
| in: matched labels | from the assigner, reduced to the chosen view: dense (a friction and a width per in-plane angle and depth bin) or compact (one best grasp per seed). |
| out, training | named loss terms, each multiplied by its weight; the trainer sums them and logs each as loss/<name>. |
| out, prediction | a GraspGroup with one grasp per seed: translation (the seed), rotation (approach from the view stage, in-plane angle from the head), depth, width (metres), score. |
| Attribute | Meaning | Rule |
|---|---|---|
in_axes |
axes of the crop features it expects | must equal the grouper's out_axes |
label_format |
dense or compact |
must equal the assigner's (and the dataset must serve that label set) |
score_kind |
meaning of the decoded score | scores of different kinds are not comparable |
applies_seed_weights |
whether its loss honours a weight per seed | an assigner that returns weights needs a head that applies them |
loss_terms |
loss option → kind of term | every loss node is checked against it (Losses) |
The assigner
The assigner runs in training only. It matches every seed with the labels of the label point it sits on and hands them, reduced to the chosen view, to the view stage and the head. So it is chosen with the head and the label set, not on its own.
NearestLabelAssigner(its defaults, no preset): every seed takes the labels of the nearest label point of its object; every seed is supervised.nearest-label-object-seeds: the same matching; only seeds on an object are supervised, and training crops sit at the matched label point.compact-label: one labelled grasp per seed at its chosen view, only within 5 mm of a label point; it brings the dataset sectioncompact_labels.scale-balanced: the matching above plus a loss weight per seed, larger for rare grasp widths. It needs the width histogram of the training split (grasppanda prepare graspnet1b --scale-statistic;configs/scale_balanced_grasp/README.md); compose adds the dataset sectionscale_statisticand says so.
grasppanda compose --show assigner=scale-balanced prints a preset with what must be
re-tuned.
The settings of DecoupledGridHead
model:
head:
type: DecoupledGridHead
num_angle: 12
num_depth: 4
depth_step: 0.01
depth: class # class | regression (a continuous depth between the bins)
width: bins # regression | class (bin centre) | bins (expectation)
width_bins: 16 # for class and bins: 16 over 0.1 m is a bin every 6.7 mm
score_target: log_friction_fixed_range
friction_range: [0.1, 1.0] # the range of the GraspNet-1Billion labels
width_loss: {type: DistributionFocal, weight: 1.0}
- The kind of
depth_lossandwidth_lossfollows the optionsdepthandwidth, so a loss must change with them (the presets do). - The class terms start near ln 12 and ln 4, a regressed width is a distance in metres × 10:
watch
loss/angleandloss/depthbesideloss/scoreand re-tune the weights. width_decode_gain: 1.2opens the gripper 20 % wider than learned, as the other heads of the family do; 1.0 decodes what was learned.- A head and a loss combine:
--set head=decoupled-grid --set head.score_loss=varifocal.
DecoupledGridHead is written here after the idea of the grasp head of FGC-GraspNet
(arXiv 2206.11141, ICRA 2022), without its code. No head
has released weights of its own.
Pitfalls met while building this
-
A label set is a contract. Compose switches the labels and the assigner for a head of the other label set, and the dense grids then come from the label store of
grasppanda prepare <dataset> --labels. A config written by hand with a mismatch is refused:✗ assigner · head: CompactLabelAssigner returns 'compact' matched labels, but DecoupledGridHead is supervised with 'dense' ones. A head bundle and the assigner that feeds it must agree on the label set; the dataset must serve that label set too. -
A logit loss changes what the score is. A score threshold fitted on the unbounded score of
swaddoes not carry over toswad-focal, whose score lies in [0, 1]. SWADHeadwithscore_target: log_friction_batch_norm(the GSNet reference) normalises targets with the extrema of the batch;log_friction_fixed_rangegives a target that means the same in every batch (swad-focalsets it).- The extra class of
EconomicHead. Withunmatched_class: trueevery classifier has one output that is never supervised; label smoothing gives it target mass. Usedecode_argmax: supervised(aseconomic-focaldoes) orunmatched_class: false. - Seed weights. A stage that receives the weights of
ScaleBalancedAssignermust apply them (applies_seed_weights); a loss that scores the supervised set as a whole cannot, so it is refused there (Losses).
Not wrapped
| Candidate | Why not |
|---|---|
| The grasp head of FGC-GraspNet as code | no licence file, and it derives from graspnet-baseline (non-commercial); its idea is DecoupledGridHead, written here. |
| Heads of graspnet-baseline and its descendants as code | a non-commercial licence; the ported heads are written from papers and behaviour. |
| Contact-GraspNet's per-point contact head | an NVIDIA non-commercial licence. |
| A decoupled head for depth-bin crops or for compact labels | DecoupledGridHead reads dense label grids and one feature per seed; under the other methods compose changes their labels or crop for it. |