HGGD¶
From an RGB-D image, it predicts a heat-map of grasp centres in 2-D, lifts each peak to 3-D and completes the grasp with a PointNet over a ball of scene points.
Paper · Reference code · Configs, results and notes
Run HGGD in five minutes¶
Four steps from the authors' checkpoint to grasps. A test parses each command and runs the demo and the Python code on a toy detector of the method's family.
1. Get the weights¶
GraspPanda publishes no weights for HGGD: the file to download is the authors' checkpoint, under its licence. Download HGGD_realsense_checkpoint (Tsinghua Cloud) and convert it once, from the root of a GraspPanda checkout:
python -m tools.convert_checkpoint HGGD_realsense_checkpoint hggd_realsense.pth \
--source-format hggd --camera realsense
Licence, checksum and what the converter writes
- Licence: MIT (the upstream repository); trained on GraspNet-1Billion (CC BY-NC-SA 4.0)
- SHA-256 of the download:
b95da06d8723298ad28e4c720c3a6a8af73dfe6f2e8126f43de8845bf62ad6df - What the converter writes:
hggd_realsense.pth, every tensor of the downloaded file under the name of the module that plays its role here, no value changed, with a note of the file it came from. A tensor left over or missing stops the conversion with a report; nothing is ever loaded partially. The converter is a tool of the repository; it is not installed with the package.
2. Grasps on the example scene¶
grasppanda demo hggd/hggd_r34w8_g1b-realsense_15e \
--weights hggd_realsense.pth --example --collision-filter
--example is a synthetic table-top scene shipped with GraspPanda: no dataset, no download. 14.5 s for the whole command, 72 grasps kept (one NVIDIA RTX A6000 shared with other jobs).
What it prints and writes, and every measured run
The command prints the config and its hash, how the weights loaded (every tensor matched, none missing), the test pipeline, the cloud, how many grasps the model predicted and how many the collision filter left (the config's variant cd: ModelFreeCollisionFilter then GraspNMS), and the ten best grasps. It writes into work_dirs/hggd_r34w8_g1b-realsense_15e/demo/:
grasps.npy: the grasps that are left,(G, 17)float32 in the GraspNet layout, best first, camera frame, metres;grasps.pngandgrasps.gif: the cloud with the 30 best grasps, still and swinging around the scene;example/: the scene as files (depth.png,rgb.png,mask.png,intrinsics.txt).
Measured with the authors' checkpoint, converted: 14.5 s for the whole command; 25,600 points to the model; 470 grasps predicted, then 287 after ModelFreeCollisionFilter → 72 after GraspNMS (2026-10-15, commit ea6268b, one NVIDIA RTX A6000 shared with other jobs). Run again at commit 0ddca31 (2026-10-15): the same counts, 16.9 s.
From Python (step 3): 72 grasps, 8.2 s for the script (2026-10-15, commit 0ddca31, one NVIDIA RTX A6000 shared with other jobs).
3. From Python, a browser or your camera¶
from grasppanda import GraspInferencer
from grasppanda.apis import example_scene
scene = example_scene() # the scene of --example
inferencer = GraspInferencer(
"hggd/hggd_r34w8_g1b-realsense_15e", "hggd_realsense.pth"
)
grasps = inferencer(
depth=scene.depth, intrinsics=scene.intrinsics,
depth_scale=scene.depth_scale, rgb=scene.rgb, collision_filter=True,
)
print(len(grasps), grasps.sort_by_score().to_graspnet_array()[:3])
It runs the demo's pipeline on the demo's scene and returns its 72 grasps. HGGD reads the colour image (rgb=) and takes no mask. More: From Python.
# ~/grasppanda_weights: the folder that holds hggd_realsense.pth
grasppanda explore --weights-dir ~/grasppanda_weights
Open http://127.0.0.1:8765/ and choose HGGD in the Run tab: hggd_realsense.pth is chosen for you by its name. Keep the example scene or upload a depth image with its intrinsics, and press Run: the page shows the picture, the best ten grasps, the counts through the post-processing and the command that does the same in a terminal. The server listens on your machine only and downloads nothing: Run in the browser.
grasppanda demo hggd/hggd_r34w8_g1b-realsense_15e \
--weights hggd_realsense.pth \
--depth work_dirs/hggd_r34w8_g1b-realsense_15e/demo/example/depth.png \
--intrinsics work_dirs/hggd_r34w8_g1b-realsense_15e/demo/example/intrinsics.txt \
--rgb work_dirs/hggd_r34w8_g1b-realsense_15e/demo/example/rgb.png \
--collision-filter --out work_dirs/camera
The scene files of step 2 stand in for a camera. HGGD reads the colour image registered to the depth image (--rgb) and crops no workspace. Units, frames, the depth scale and the intrinsics: Your own camera.
4. A first number on the benchmark¶
With GraspNet-1Billion on disk (Datasets), score every 64th frame of the seen test scenes, 120 frames:
grasppanda test hggd/hggd_r34w8_g1b-realsense_15e \
--weights hggd_realsense.pth \
--opts data.test.dataset.split=test_seen data.test.dataset.frame_step=64 \
evaluation.num_workers=4
Measured with the authors' checkpoint, converted: AP 58.16 without the collision filter and 64.14 with it, within 0.44 AP of the whole split.
What it prints, and every measured run against the whole split
It prints AP, AP0.8 and AP0.4 for every variant of the config, raw (the predictions as they are) and cd (with the collision filter), and writes a result record per variant into the run directory under work_dirs/. Testing needs no derived asset; the evaluator extracts a cache from the dataset's object models the first time it runs, which the times below do not include.
| Weights, provenance | Collision filter | AP, 120 frames of test_seen | AP, whole seen split | Difference | Wall time, commit |
|---|---|---|---|---|---|
the authors' checkpoint, converted, author-ckpt |
off | 58.16 | 58.33 (record) | −0.17 | 53 s, ea6268b |
| on | 64.14 | 63.70 (record) | +0.44 |
Provenance: author-ckpt, the authors' checkpoint, evaluated by GraspPanda. Inputs: no input is derived from ground truth (the config crops no workspace). On these 120 frames the AP is within 0.44 AP of the whole split, so the subset tells you quickly whether your installation gives what the records say; it is not a benchmark number. Measured on 2026-10-15 on one NVIDIA RTX A6000 shared with other jobs.
The machine: one NVIDIA RTX A6000 (48 GB) shared with other jobs, an AMD EPYC 7262 with OMP_NUM_THREADS=3; Python 3.12, PyTorch 2.7.1 with CUDA 11.8, spconv 2.3.8.
Numbers¶
GraspNet-1Billion, RealSense, the whole test split: AP on seen / similar / novel, from the metafile.
| Weights | Collision filter | Seen | Similar | Novel | Record |
|---|---|---|---|---|---|
| reported (paper) | not stated | 59.36 | 51.20 | 22.17 | — |
| reported (repository README) | not stated | 64.45 | 53.59 | 24.59 | — |
| authors' weights | off | 58.33 | 47.96 | 22.03 | record |
| authors' weights | on | 63.70 | 52.90 | 24.18 | record |
Where these numbers come from
- The status of these numbers: authors' weights scored here, the authors' checkpoint, converted and scored on whole test splits; nothing trained here yet.
- reported: paper; row 'In paper' of the repository README; repository README, row 'In repo' (also the arXiv version).
- authors' weights, scored here: the authors' checkpoint, converted and run through
grasppanda teston every frame of the test split; the record holds the per-scene values, the config hash and the hashes of code and weights. - Inputs: nothing derived from ground truth: HGGD crops no workspace (gt_assisted: none).
- Other cameras, GraspClutter6D and what is known about each gap: the README; every method side by side: Model zoo.
The options of every slot¶
Every option that fits HGGD, except target-mask, was composed under it; those accepted were probed on real frames; the others say why.
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.
| Slot | Shipped | Composes | Refused | Runs here | Explorer |
|---|---|---|---|---|---|
| Image encoder | its built-in encoder | 37 · 1 needs consent | 0 | 36/37 | compare |
| Post-processing | variants cd, raw | 14 · 1 no record | 0 | 14/14 | compare |
| Optimizer | AdamW |
15 | 2 | 14/15 | compare |
| Schedule | StepLR |
7 | 0 | 7/7 | compare |
| Hooks | accumulate-2 |
5 | 2 | 4/5 | compare |
| Augmentation | its own | 1 | 2 | 1/3 | compare |
| Recipe | its own | 1 | 2 | 1/1 | compare |
Image encoder: 38 options
--set image_encoder=<option>. What each option is: the image encoder page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
convnextv2-atto |
HGGD ✓ | HGGD: worse | learns ? (as shipped); predicts ✗: no grasp on any frame |
convnextv2-tiny |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
dinov2-small-reg-depth-stem |
HGGD ✓ | HGGD: on a par | ✓ |
dinov2-small-reg |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
dinov3-convnext-tiny |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
dinov3-vits16 |
HGGD ✓ | HGGD: diverging | learns ? (as shipped) |
efficientnetv2-s |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
efficientvit-b1 |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
eva02-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
fastvit-sa12 |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
fastvit-t8 |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
hf-convnextv2-tiny |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
hf-depth-anything-v2-small |
HGGD ✓ | HGGD: worse | ✓ |
hf-dinov2-small-reg |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
hf-dinov2-small |
HGGD ✓ | HGGD: worse | ✓ |
hf-hiera-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
hf-radio-v3-base |
HGGD ? undecided (needs your consent (remote code)) |
not compared | needs your consent: model.image_encoder: HFImageEncoder: model_args.trust_remote_code: true runs Python code downloaded from the hub repository 'nvidia/C-RADIOv3-B' on this machine. Read that repository, then state that you accept it with accept_remote_code: true (--opts model.image_encoder.accept_remote_code=true). |
hf-siglip2-base |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
hf-swinv2-tiny |
HGGD ✓ | HGGD: on a par | ✓ |
hggd-residual |
own only own in HGGD |
not compared | learns ? (as shipped) |
hiera-small-abswin |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
maxvit-tiny |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
mobilenetv4-conv-small |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
mobilenetv4-hybrid-medium |
HGGD ✓ | HGGD: on a par | learns ? (as shipped); predicts ✗: no grasp on any frame |
pe-spatial-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
repvit-m1 |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
resnet18 |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
resnet34-rgbd |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
resnet34 |
HGGD ✓ | HGGD: on a par | ✓ |
resnet50 |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
sam2-hiera-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
siglip2-base |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
swinv2-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
tv-convnext-tiny |
HGGD ✓ | HGGD: worse | learns ? (as shipped) |
tv-efficientnetv2-s |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
tv-mobilenetv3-large |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
tv-regnet-y-800mf |
HGGD ✓ | HGGD: on a par | ✓ |
tv-resnet34 |
HGGD ✓ | HGGD: on a par | learns ? (as shipped) |
learns ? (as shipped): HGGD as shipped does not reach learns in a short run either (anchor_offset flat), so under HGGD that level says nothing about an option.
Post-processing: 15 options
--set post=<option>. What each option is: the post-processing page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
approach-cone |
6/6 | — | learns ? (as shipped) |
center-gripper |
6/6 | — | learns ? (as shipped) |
collision-strict |
6/6 | — | learns ? (as shipped) |
collision |
6/6 | — | ✓ |
furthest-sampling |
6/6 | — | ✓ |
gripper-limits |
6/6 | — | ✓ |
mesh-collision |
6/6 | — | ✓ |
nms |
6/6 | — | ✓ |
score-threshold |
6/6 | — | learns ? (as shipped) |
table-plane |
6/6 | — | learns ? (as shipped) |
to-base-frame |
6/6 | — | ✓ |
top-k |
6/6 | — | ✓ |
width-from-cloud |
6/6 | — | ✓ |
workspace |
6/6 | — | learns ? (as shipped) |
target-mask |
no record reads observation.masks, which no shipped dataset fills |
— | no record |
learns ? (as shipped): HGGD as shipped does not reach learns in a short run either (anchor_offset flat), so under HGGD that level says nothing about an option.
Trains like shipped: — (post-processing trains nothing: it changes predictions, not the training).
Training recipe: 37 options (optimizer, schedule, hooks, augmentation, recipe)
Optimizer, 17 options: --set optimizer=<option>. What each option is: the optimizer page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
adamw-no-decay-1d |
6/6 | 4/6 on a par · 2 worse worse under FineGrasp, HGGD |
✓ |
adamw |
6/6 | 3/6 on a par · 3 worse worse under Scale-Balanced-Grasp, FineGrasp, HGGD |
✓ |
ademamix |
6/6 | 4/6 on a par · 2 worse worse under FineGrasp, HGGD |
✓ |
prodigy |
6/6 | 4/6 on a par · 2 worse worse under Scale-Balanced-Grasp, FineGrasp |
✓ |
schedulefree-adamw |
6/6 | not compared | learns ? (as shipped) |
schedulefree-radam |
6/6 | not compared | learns ? (as shipped) |
schedulefree-sgd |
3/6 | not compared | ✓ |
soap |
5/6 | 4/5 on a par · 1 worse worse under FineGrasp |
not verified: one CUDA illegal memory access on a shared GPU |
stableadamw |
6/6 | 3/6 on a par · 3 worse worse under GraspNet-baseline, FineGrasp, HGGD |
✓ |
timm-adan |
6/6 | 2/6 on a par · 1 diverging · 3 worse | ✓ |
timm-adopt |
6/6 | 3/6 on a par · 3 worse worse under EconomicGrasp, FineGrasp, HGGD |
learns ? (as shipped) |
timm-lamb |
6/6 | 5/6 on a par · 1 diverging diverging under FineGrasp |
✓ |
timm-lion |
6/6 | 0/6 on a par · 1 diverging · 5 worse | ✓ |
timm-madgrad |
6/6 | 3/6 on a par · 1 diverging · 2 worse | ✓ |
timm-mars |
6/6 | 4/6 on a par · 2 worse worse under FineGrasp, HGGD |
learns ? (as shipped) |
encoder-lr-0.1 |
5/5 | 1/5 on a par · 1 diverging · 3 worse | refused (incompatible by design): it is written for the scene encoder of the seed-based skeleton (model.backbone), which HGGD does not have. |
layer-decay |
5/5 | 2/5 on a par · 1 diverging · 2 worse worse under GSNet, EconomicGrasp; diverging under FineGrasp |
refused (incompatible by design): it is written for the scene encoder of the seed-based skeleton (model.backbone), which HGGD does not have. |
learns ? (as shipped): HGGD as shipped does not reach learns in a short run either (anchor_offset flat), so under HGGD that level says nothing about an option.
Who is left out, and why:
schedulefree-adamw, trains like shipped: not compared under GraspNet-baseline, GSNet, Scale-Balanced-Grasp, EconomicGrasp, FineGrasp, HGGD: it trained on a schedule of its own, not on that of the method as shipped.schedulefree-radam, trains like shipped: not compared under GraspNet-baseline, GSNet, Scale-Balanced-Grasp, EconomicGrasp, FineGrasp, HGGD: it trained on a schedule of its own, not on that of the method as shipped.schedulefree-sgd, runs: not GSNet, EconomicGrasp, FineGrasp (unstable twice in the short probe).schedulefree-sgd, trains like shipped: not compared under GraspNet-baseline, Scale-Balanced-Grasp, HGGD: it trained on a schedule of its own, not on that of the method as shipped; not compared under GSNet, EconomicGrasp, FineGrasp: the swap did not run at level 1.soap, runs: not HGGD (not verified: one CUDA illegal memory access on a shared GPU).timm-adan, trains like shipped: worse under GSNet, EconomicGrasp, HGGD; diverging under FineGrasp.timm-lion, trains like shipped: worse under GraspNet-baseline, GSNet, EconomicGrasp, FineGrasp, HGGD; diverging under Scale-Balanced-Grasp.timm-madgrad, trains like shipped: diverging under GraspNet-baseline; worse under Scale-Balanced-Grasp, FineGrasp.encoder-lr-0.1, trains like shipped: worse under GraspNet-baseline, GSNet, EconomicGrasp; diverging under FineGrasp.
Schedule, 7 options: --set schedule=<option>. What each option is: the schedule page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
constant |
5/6 not FineGrasp (unstable twice in the short probe) |
— | ✓ |
cosine-restarts |
5/6 not FineGrasp (unstable twice in the short probe) |
— | ✓ |
cosine |
5/6 not FineGrasp (unstable twice in the short probe) |
— | ✓ |
multistep-warmup |
5/6 not FineGrasp (unstable twice in the short probe) |
— | learns ? (as shipped) |
onecycle |
6/6 | — | ✓ |
poly |
5/6 not FineGrasp (unstable twice in the short probe) |
— | ✓ |
warmup-cosine |
5/6 not FineGrasp (unstable twice in the short probe) |
— | learns ? (as shipped) |
Trains like shipped: — (level 2 holds the schedule of the method as shipped fixed (a constant rate; FineGrasp: its own warm-up), so a schedule swap is not compared).
Hooks, 7 options: --set hooks=<option>. What each option is: the hooks page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
accumulate-2 |
5/5 own in HGGD |
2/5 on a par · 3 worse worse under GraspNet-baseline, GSNet, EconomicGrasp |
shipped |
agc |
6/6 | 6/6 on a par | ✓ |
amp |
0/6 not supported yet |
not compared | refused (not supported yet): train.amp: mixed precision is not supported by HGGD yet: its loss is not written for half-precision tensors (the detector does not declare amp_ready = True). |
ema |
6/6 | 6/6 on a par | learns ? (as shipped) |
grad-clip |
6/6 | 5/6 on a par · 1 worse worse under FineGrasp |
✓ |
swa |
4/6 | 4/4 on a par | ✓ |
freeze-encoder |
4/5 not FineGrasp (unstable twice in the short probe) |
4/4 on a par | refused (incompatible by design): it is written for the scene encoder of the seed-based skeleton (model.backbone), which HGGD does not have. |
Who is left out, and why:
swa, runs: not GraspNet-baseline, Scale-Balanced-Grasp (not verified: the probe is shorter than the epoch at which averaging starts).freeze-encoder, trains like shipped: not compared under FineGrasp: the swap did not run at level 1.
Augmentation, 3 options: --set augment=<option>. What each option is: the augmentation page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
dropout |
5/6 | 5/5 on a par | learns ? (as shipped) |
jitter |
5/6 not HGGD (not supported yet) |
5/5 on a par | refused (not supported yet): data.train.dataset.transforms: RandomJitter moves the points, but this dataset section also serves image-space data (rgb, depth, view_grasps), which would stay where it was. |
shift |
5/6 not HGGD (not supported yet) |
3/5 on a par · 2 worse worse under EconomicGrasp, FineGrasp |
refused (not supported yet): data.train.dataset.transforms: RandomShift moves the points, but this dataset section also serves image-space data (rgb, depth, view_grasps), which would stay where it was. |
Who is left out, and why:
dropout, runs: not FineGrasp (fails: the transform order of the composed config is wrong (DepthNormals must run first)).
Recipe, 3 options: --set recipe=<option>. What each option is: the recipe page.
| Option | Runs | Trains like shipped | Under HGGD |
|---|---|---|---|
adamw-onecycle |
6/6 | not compared | ✓ |
finetune-encoder |
4/5 not FineGrasp (unstable twice in the short probe) |
not compared | refused (incompatible by design): it is written for the scene encoder of the seed-based skeleton (model.backbone), which HGGD does not have. |
ptv3-adamw-onecycle |
5/5 | not compared | refused (incompatible by design): it needs --set backbone=ptv3 in the same request, and HGGD has no slot backbone. |
Who is left out, and why:
adamw-onecycle, trains like shipped: not compared under GraspNet-baseline, GSNet, Scale-Balanced-Grasp, EconomicGrasp, FineGrasp, HGGD: it trained on a schedule of its own, not on that of the method as shipped.finetune-encoder, trains like shipped: not compared under GraspNet-baseline, GSNet, Scale-Balanced-Grasp, EconomicGrasp: it trained on a schedule of its own, not on that of the method as shipped; not compared under FineGrasp: the swap did not run at level 1.ptv3-adamw-onecycle, trains like shipped: not compared under GraspNet-baseline, GSNet, Scale-Balanced-Grasp, EconomicGrasp, FineGrasp: it trained on a schedule of its own, not on that of the method as shipped.
How to swap, and how to read these lists
Swap one option in with a single line, or list the options of a slot:
grasppanda compose hggd/hggd_r34w8_g1b-realsense_15e \
--set <slot>=<option> -o swap.yaml
grasppanda compose hggd/hggd_r34w8_g1b-realsense_15e --list <slot>
The summary table:
- Composes: the options the config check accepts under HGGD, the one it ships included. needs consent: an option it holds back until you accept the code it downloads (the row says how), neither accepted nor refused. no record: never composed; the row says why.
- Refused: the options the config check refuses under HGGD; each row gives the first sentence of the reason.
- Runs here: the swaps whose probe trained on real frames under HGGD without an error, out of every option tried there as a swap: a refusal counts, the option the method ships does not. Not counted either:
encoder-lr-0.1,layer-decay,freeze-encoder,finetune-encoderandptv3-adamw-onecycle, refused under HGGD with no probe record. Does it run? counts the same way.
The lists of each slot:
- Runs: the methods under which the swap trained on real frames without an error, out of every method it is a swap under; the methods that ship the option are own and not counted. Who is left out, and why, stands under the chip, or below the table when it is long. Measured: 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: trained 250 iterations beside the component the method ships, its losses fall as theirs do, out of the methods it was compared under; a method under which the swap did not run, or where it trained on a schedule of its own, is named and not counted. Level 2 needs runs, not learns: a term flat after 20 iterations can fall by 250. Measured: 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.
- Under HGGD: ✓ when it reached every level here; level ? (as shipped) when HGGD as shipped does not reach that level either (a note below the table says why), so the level says nothing about the option; else the level it missed and why (composes, runs, learns, predicts), or why it was refused.
The levels, the refusal kinds and the thresholds: How we measure; every record: Does it run?; every comparison at level 2: Does it train like the shipped component?.
How this port differs from the reference
- One model instance trains and predicts; the mode selects the proposal budget.
- Camera intrinsics come from the frame, not from per-camera constants rounded to two decimals.
- A frame without proposals, or whose regions all lack support, yields an explicit empty group (the reference writes no file, or fails). A training batch without regions still trains the image network (the reference skips the step).
- Gradient accumulation averages the two batches where the reference sums them, so the value clip is 0.5 instead of 1 (AdamW is invariant to the scale). The reference's first step of an epoch spans three batches and it drops the gradient of the last batch; neither is reproduced.
- In-training evaluation uses the
val_devscenes, not test scene 100. - The anchor label pool is per process: under
torchruneach process moves its own copy of the anchors. Train the reference recipe on one GPU.
How it was checked, stage by stage: tests/integration/test_hggd_parity.py and the README.
Next¶
- Swap a component: change one slot of HGGD with a single line.
- Open HGGD in the explorer: every option of every slot, with what was measured.
- All six methods side by side, and the model zoo.