Skip to content

GARfVDB - #308

Open
swahtz wants to merge 39 commits into
openvdb:mainfrom
swahtz:garfvdb
Open

GARfVDB#308
swahtz wants to merge 39 commits into
openvdb:mainfrom
swahtz:garfvdb

Conversation

@swahtz

@swahtz swahtz commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds GARfVDB scale-conditioned instance segmentation as a first-class fvdb-reality-capture method (Python API plus frgs segment-instances), where an existing Gaussian reconstruction is consumed as input and the learned scale-conditioned feature field is the product.
  • Introduces a portable, pickle-free .garfvdb bundle containing NanoVDBs (encoder grids and features), safetensors (dense network weights and scale-quantile buffers), and a PLY Gaussian model, with explicit schema versioning, checksums, and validation on load. This is the trained end-product of a GARfVDB model (i.e. the equivalent of a .ply file for the optimized Gaussian splat reconstruction scene), not a resumable checkpoint.
  • Adds shared, method-neutral infrastructure so GARfVDB and any future, non-Gaussian products fit cleanly:
    • versioned training-checkpoint container with a reader registry
    • a CLI resume-handler registry
    • a reusable scene-transform configuration
    • a namespaced scene attribute for per-image mask supervision

> frgs segment-instances DATASET --reconstruction-path scene.ply --out-path scene.garfvdb trains from an existing reconstruction and writes a portable bundle

Motivation

GARfVDB previously lived as a standalone project in fvdb-examples that was already coupled to fvdb-reality-capture for SfM loading and Gaussian reconstruction, but its deliverable is a second learned product (based on a filtered Gaussian scene) rather than more Gaussians. This is the first fvdb-reality-capture method whose product is not a Gaussian splat, so the integration deliberately separates shared workflow infrastructure from product-specific behavior instead of bolting a training script onto the Gaussian commands. The shared pieces are designed against a concrete second method (for example integrating the LangSplatV2 method that also uses SAM2) so they generalize rather than hard-coding GARfVDB.

Artifact contract

The .garfvdb/ bundle is the trained end-product of the instance segmentation method (equivalent to what the .ply file is to the reconstruct process).

  • A *.garfvdb/ bundle contains no PyTorch pickle files: manifest.json, encoder.nvdb, network.safetensors, and gaussians.ply.
  • encoder.nvdb stores all encoder grid topologies and their learned per-voxel features through fVDB NanoVDB I/O with compression; grids are named deterministically (encoder_00 ... encoder_NN) and that order is validated on load.
  • network.safetensors stores the MLP weights, optional sparse-convolution weights, maximum scale, and scale-quantile lookup buffers as named dense tensors.
  • gaussians.ply stores the exact filtered GaussianSplat3d model plus reconstruction and camera metadata.

Note: The manifest carries an explicit integer schema_version and per-payload SHA-256 checksums. Loading dispatches through a version-specific reader that validates canonical grid names and order, grid/voxel counts, voxel sizes and origins, feature shape and dtype, Gaussian count, and every payload checksum. Missing, renamed, reordered, corrupted, or incompatible payloads fail with clear errors, and newer-than-supported bundle versions fail before any payload is read.

Checkpoint and resume architecture

To accommodate checkpoints beyond the reconstruction method checkpoints being resumed (and without specific methods needed to be invoked by users resume-instance-segmentation, etc.), this method formalizes the checkpoint container concept.

  • New training checkpoints use a generic container: schema, schema_version, method, method_version, and method-owned state. Parsing first validates the container, selects an exact schema-version reader, and can consult registered legacy adapters for pre-container formats.
  • The container carries two independent versions on orthogonal axes.
    • schema/schema_version version the container format itself — the fixed top-level keys and how they are parsed; schema is a constant shared by every method and schema_version is owned centrally, bumped only when the wrapper structure changes (which affects all methods at once).
    • method/method_version version the method-owned payload in state: method is the stable id of the producing method and method_version, owned by the method's package as a single source of truth, versions that method's state layout and is bumped only when that one method's state changes. Everything method-specific — model weights, optimizer/scheduler state, config, global step, and method metadata — lives opaquely inside state; the container layer never interprets it.
  • The generic module contains no method names, CLI options, or product extensions. Method identity and legacy recognition are owned by their packages:
    • radiance_fields.checkpoint defines the Gaussian method id (radiance_fields.gaussian_splat) and a legacy adapter for released flat Gaussian checkpoints;
    • instance_segmentation.checkpoint defines the GARfVDB method id (instance_segmentation.garfvdb).
  • Each method exposes a single version constant that both its state_dict/from_state_dict and its disk writer container derive from, so the recorded container version and the method state version cannot drift.
  • frgs resume loads one validated container, resolves the stable method id, and invokes a CLI-owned resume handler that also owns the default output name. Unknown methods fail explicitly.
  • The Gaussian reconstruction writer and reader now use the same container, and previously released flat Gaussian checkpoints remain loadable through the legacy adapter.

Transform and scene-attribute integration

So that a second, non-Gaussian method can reuse the reconstruction's scene preprocessing without duplicating it or overwriting shared scene state, the standard transform stages are factored into a reusable SceneTransformConfig, and each method's per-image supervision is carried as a namespaced scene attribute rather than by replacing the scene cache.

  • A reusable SceneTransformConfig builds the standard alignment, point filtering, image downsampling, low-point image filtering, and cropping stages; both reconstruction and GARfVDB build on it. Reconstruction supplies normalization while GARfVDB injects the reconstruction's saved alignment transform.
  • SAM2 mask and scene-unit scale supervision is attached as a registered, namespaced GARfVDBMaskAttribute on SfmScene rather than replacing the scene cache, so existing caches and attributes are preserved and the dataset consumes only its named attribute.
  • Mask generation runs last and rejects later downsample, crop, or spatial transforms, because resizing or rescaling after generation would invalidate mask pixels or scene-unit scales. Other segmentation methods can attach their own attribute types and generators through the same generic mechanism without adopting the GARfVDB supervision format.

Interactive viewer

Updated the viewer to be able to visualize the segmentation mask output (using PCA to project the mask to a 3-channel RGB visualization) as an overlay with interactive parameters to control the visualization.

  • Adds GARfVDBOverlayViewer, which renders the GARfVDB feature field as a live overlay on the Gaussians in the fvdb viewer with interactive "Scene Params" widgets:
    • a normalized grouping-scale slider (mapped to the model's maximum grouping scale)
    • an overlay-opacity slider, a show/hide checkbox for the overlay
    • a "Lock PCA colors" checkbox that freezes the PCA-to-RGB transform so the feature coloring does not flicker during camera movement
  • A single shared core drives both the offline frgs show viewer and a new live training viewer enabled with frgs segment-instances --viewer, which pumps overlay renders from the training loop between steps so the in-progress feature field can be inspected while training runs.
  • The offline viewer renders continuously while the camera or any widget is changing

SAM2 mask-generation performance

In addition to porting the SAM2 mask-generation transforms from fvdb-examples, this PR also makes some performance improvements during the transition:

  • Vectorizes the two hottest per-image post-processing steps in mask generation: pixel_to_mask_id construction becomes a single cumulative-sum plus scatter instead of an O(masks * max_overlap) Python loop that forced a device synchronization on every inner iteration, and per-mask scale computation deduplicates on integer gaussian ids rather than sorting float3 world points. Both are equivalent to the originals.
  • Stops storing the per-pixel mask-selection CDF on disk (the largest field in the mask cache, a full [H, W, max_overlap] float32 tensor) and recomputes it from pixel_to_mask_id at load time via instance_segmentation.util.compute_mask_cdf. This roughly quarters both the on-disk artifact size and the disk-bound write time.
  • Overlaps cache writes with computation by handing each image's disk write to a background writer thread while the next image's SAM2 pass runs on the GPU. SfmCache's FileLock now only arms its SIGALRM-based timeout on the main thread and falls back to a plain blocking flock on worker threads, since signal-based timeouts cannot be used off the main thread.
  • Exposes and raises SAM2 points_per_batch so more point prompts are processed per mask-decoder forward pass.

Device defaults and import updates

  • Defaults the compute device to cuda:0 across the CLI, foundation models, config, and docs, because the current fvdb build requires an explicit device index and cuda alone raises "Device must specify an index".

Dependencies

  • Requires fvdb-core>=0.6.0 and adds safetensors.
  • The new fvdb.viz features that bring the API changes to add interactive, definable parameters require this PR to merge before this branch will work: Add viewer widgets fvdb-core#649
  • cuML clustering, NVOS evaluation, and discrete-instance export remain out of the core dependency set and stay in fvdb-examples for the moment.

Documentation

  • Adds an instance-segmentation tutorial and API pages, a checkpoints API page, and resume/show/transforms updates describing the bundle layout, grid naming, coordinate transforms, versioning, and how future readers or migrations are introduced.

Testing

  • Ported training math is at parity with the prototype for loss (including per-view pair-count normalization), mask-CDF sampling, scale interpolation, pixel sampling, encoder feature extraction, MLP forward paths, and SAM2 mask/scale preprocessing. The port additionally fixes the prototype's scheduler-resume gap by checkpointing and restoring scheduler state.
  • The interactive viewer is covered by unit/test_garfvdb_viewer.py (widget registration, normalized-to-raw scale mapping, camera/widget change detection and the render/idle contract, show/hide, and PCA lock), and the vectorized mask post-processing and recomputed mask CDF were checked for equivalence against the original implementations, including against a real on-disk cache file.

Backwards compatibility and follow-ups

  • Released flat Gaussian reconstruction checkpoints remain loadable and resumable through the registered legacy adapter; a Gaussian .ply remains an export product and is not resumable.
  • Standalone fvdb-examples GARfVDB checkpoints are intentionally not migrated; there is no importer for the prototype format, and old SAM2 mask caches must be regenerated because supervision is now a versioned scene attribute.
  • use_grid_conv=True remains experimental and is not exercised by the first-class path; the per-Gaussian affinity path references a grid attribute that does not exist and would fail if enabled. First-class training and products require use_grid=True, so this does not affect the supported configuration, but the option should be fixed or gated before it is advertised as supported.
  • The overlay-opacity slider depends on an upstream nanovdb-editor fix (its image2d.slang composited the image view opaquely and ignored per-pixel alpha) Fix compositing image2d over the scene using per-pixel alpha nanovdb-editor#217

swahtz and others added 7 commits July 9, 2026 16:03
…rtifacts

Integrate GARfVDB scale-conditioned instance segmentation as a first-class fvdb-reality-capture method, treating the Gaussian reconstruction as an input carrier and the learned scale-conditioned feature field as the product. This ports the model, loss, optimizer, datasets, SAM2 preprocessing, trainer, writer, and visualization out of the fvdb-examples prototype and into fvdb_reality_capture.instance_segmentation, and adds the shared infrastructure needed to support learned products that are not Gaussian splats.

Add a portable, pickle-free .garfvdb bundle (manifest.json, encoder.nvdb, network.safetensors, carrier.ply). The encoder grid topology and per-voxel features round-trip through fVDB NanoVDB I/O, dense network tensors go through safetensors, and the exact filtered Gaussian carrier is stored as PLY. Manifests carry an explicit integer schema_version and per-payload checksums, and loading dispatches through a version-specific reader that validates canonical grid names/order, topology, transforms, feature shape/dtype, carrier count, and checksums.

Add a method-neutral, versioned training-checkpoint envelope (schema, schema_version, method, method_version, state) with a schema-version reader registry and a legacy-adapter hook. Method identity and legacy recognition live in their owning packages (radiance_fields.checkpoint, instance_segmentation.checkpoint) rather than in the generic module, and each method exposes a single version constant that both its state and its writer envelope derive from so the two cannot drift. frgs resume now loads one validated envelope, resolves a stable method id, and invokes a CLI-owned resume handler; unknown methods fail explicitly instead of falling through to Gaussian reconstruction, and portable .garfvdb products are rejected as non-resumable.

Integrate GARfVDB preprocessing with the standard scene-transform pipeline via a shared SceneTransformConfig, and represent SAM2 mask/scale supervision as a registered, namespaced GARfVDBMaskAttribute on SfmScene instead of overwriting the scene cache. Mask generation is terminal in the pipeline and refuses later image/crop/spatial transforms, so other segmentation methods can attach their own attributes and generators without inheriting the GARfVDB supervision format.

Add frgs instance-segmentation, product-aware frgs show, and dispatched frgs resume; add safetensors and require fvdb-core>=0.5.0. Add API, CLI, artifact, scene-transform, and checkpoint tests, plus workflow and API documentation. Keep cuML clustering and NVOS evaluation out of the core dependency set.

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
…ttributes cache

Switch batch size default to 1

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Add GARfVDBOverlayViewer, which renders the GARfVDB feature field as an
overlay on top of the Gaussian carrier in the fvdb viewer with interactive
"Scene Params" widgets:

- Grouping scale (normalized 0..1, mapped to the model's max grouping scale)
- Overlay opacity
- Show/hide the segmentation overlay (removes the image view so the carrier
  shows through, since ImageView has no visibility toggle)
- Lock PCA colors: freeze the PCA->RGB transform (mean/basis/min-max) so the
  feature coloring does not flicker as the camera moves; refit on unlock or
  when the grouping scale changes

The overlay is driven by a shared core reused by both the offline `frgs show`
viewer and a new live training viewer (`frgs instance-segmentation --viewer`),
which pumps render_once() from the training loop between steps. render_once()
now reports whether anything changed so the offline loop renders continuously
while the camera moves and only idle-sleeps when nothing changed, tracking
camera motion in real time instead of waiting for the mouse to stop.

Add fit_pca_projection/apply_pca_projection helpers for the lockable PCA
transform and unit tests covering widget registration, normalized->raw scale
mapping, change detection, show/hide, lock behavior, and the render/idle
contract.

Default the compute device to "cuda:0" across the CLI, foundation models,
config, and docs: the rebuilt fvdb/nanovdb-editor requires an explicit device
index ("cuda" alone raised "Device must specify an index").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

@harrism harrism left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Submitting a partial review. Haven't reviewed the big files yet.

Comment thread docs/api/frgs/mesh_basic.rst Outdated
Comment thread docs/api/frgs/mesh_dlnr.rst Outdated
Comment thread docs/api/checkpoints.rst Outdated
Comment thread docs/api/frgs.rst Outdated
Comment thread docs/api/frgs.rst Outdated
Comment thread docs/api/frgs.rst Outdated
Comment thread docs/tutorials/instance_segmentation.rst Outdated
swahtz and others added 11 commits July 20, 2026 14:28
Co-authored-by: Mark Harris <mharris@nvidia.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Co-authored-by: Mark Harris <mharris@nvidia.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Co-authored-by: Mark Harris <mharris@nvidia.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Co-authored-by: Mark Harris <mharris@nvidia.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Co-authored-by: Mark Harris <mharris@nvidia.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Rename the underlying Gaussian model from "carrier" to "gaussians"
throughout the GARfVDB integration for clarity: the GARfVDB.gaussians
property, the add_gaussians viewer option, the "Gaussian Splats" viewer
label, and the associated variables, docstrings, messages, and docs.

Also rename the on-disk names since this feature has not shipped yet
(no compatibility to preserve and no ARTIFACT_SCHEMA_VERSION bump):
the bundle payload gaussians.ply and its manifest key "gaussians", and
the resume checkpoint keys gaussian_filter_threshold, num_gaussians, and
gaussian_means_sha256. Checkpoint write/read and manifest write/read keys
were updated together and verified consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Rename the versioned, method-neutral checkpoint structure from "envelope"
to "container" across docstrings, comments, the local variables in the
disk writers, test names, and the resume/checkpoints/tutorial docs. The
concept and its fields (schema, schema_version, method, method_version,
state) are unchanged; this is wording only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
"Validate an container" -> "Validate a container" (leftover from the
envelope -> container rename).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Add a "Container schema versus method" section to the training-checkpoints
docs explaining the two independent version axes: schema/schema_version
version the container format (owned centrally, bumped when the wrapper
structure changes), while method/method_version version the method-owned
state payload (owned per method). Clarifies what lives in state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates GARfVDB scale-conditioned instance segmentation into fvdb-reality-capture as a first-class method, including a portable .garfvdb inference bundle format, shared checkpoint/resume infrastructure, and viewer/transform updates to support non-Gaussian derived products alongside Gaussian reconstruction.

Changes:

  • Added GARfVDB training + inference product support (artifact I/O, CLI command, scene attribute/transforms, viewer overlay, and unit tests).
  • Introduced a method-neutral, versioned training checkpoint container plus a CLI resume-handler registry; migrated Gaussian checkpoints to the container while keeping legacy flat Gaussian checkpoints loadable.
  • Refactored common scene preprocessing into a reusable SceneTransformConfig and updated CLI/device defaults and docs accordingly.

Reviewed changes

Copilot reviewed 68 out of 69 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/unit/test_training_checkpoints.py Tests for checkpoint container parsing/loading and resume dispatch registry behavior.
tests/unit/test_garfvdb_viewer.py Unit tests for GARfVDB overlay viewer core behavior and widget-driven rerendering.
tests/unit/test_garfvdb_scene_transforms.py Tests for GARfVDB mask attribute + transform ordering and cache behaviors.
tests/unit/test_garfvdb_cli.py CLI contract tests for frgs instance-segmentation, frgs show, and frgs resume.
tests/unit/test_garfvdb_artifact.py Tests for .garfvdb bundle format, schema versioning, validation, and round-trips.
tests/benchmarks/test_3dgs.py Updated benchmark to load Gaussian checkpoints via the container loader.
tests/benchmarks/contract.py Contract bump + validation through container parsing and method ID checking.
README.md README updated to mention instance feature fields alongside radiance fields.
pyproject.toml Adds safetensors dependency.
fvdb_reality_capture/transforms/scene_transform_config.py New reusable scene transform configuration/pipeline builder.
fvdb_reality_capture/transforms/init.py Exposes SceneTransformConfig in transforms public API.
fvdb_reality_capture/sfm_scene/sfm_cache.py File lock updated to avoid SIGALRM timeout logic on worker threads.
fvdb_reality_capture/radiance_fields/io.py New helper to load splats from PLY or checkpoint container.
fvdb_reality_capture/radiance_fields/gaussian_splat_reconstruction.py Uses method version constant; default device updated to cuda:0.
fvdb_reality_capture/radiance_fields/gaussian_splat_reconstruction_writer.py Writes checkpoints as versioned containers.
fvdb_reality_capture/radiance_fields/checkpoint.py New Gaussian method ID/version constants + legacy adapter registration.
fvdb_reality_capture/radiance_fields/init.py Re-exports method ID/version constants and load_splats_from_file.
fvdb_reality_capture/instance_segmentation/viewer.py Interactive GARfVDB overlay viewer + show_garfvdb_bundle.
fvdb_reality_capture/instance_segmentation/util.py New utilities incl. PCA projection helpers and mask CDF computation.
fvdb_reality_capture/instance_segmentation/training/segmentation_writer.py New GARfVDB training writer (images/metrics/checkpoints).
fvdb_reality_capture/instance_segmentation/training/dataset.py Segmentation dataset that loads mask attribute and recomputes mask CDF.
fvdb_reality_capture/instance_segmentation/training/dataset_transforms.py Dataset transforms for mask selection, pixel sampling, resizing, etc.
fvdb_reality_capture/instance_segmentation/training/init.py Training package initializer.
fvdb_reality_capture/instance_segmentation/scene_transforms/init.py Exposes GenerateGARfVDBMasks.
fvdb_reality_capture/instance_segmentation/scene_attribute.py New namespaced scene attribute for per-image GARfVDB mask supervision.
fvdb_reality_capture/instance_segmentation/optim.py Adds Exponential LR scheduler with ramp-up for segmentation training.
fvdb_reality_capture/instance_segmentation/loss.py Adds GARfVDB contrastive loss implementation and per-view normalization.
fvdb_reality_capture/instance_segmentation/garfvdb.py Public GARfVDB inference product API (render, affinities, save/load).
fvdb_reality_capture/instance_segmentation/config.py GARfVDB model/training/transform configs leveraging shared transform config.
fvdb_reality_capture/instance_segmentation/checkpoint.py GARfVDB checkpoint method ID/version constants.
fvdb_reality_capture/instance_segmentation/artifact.py Portable .garfvdb bundle save/load with schema versioning + checksums.
fvdb_reality_capture/instance_segmentation/init.py Public instance-segmentation module exports.
fvdb_reality_capture/foundation_models/sam2.py Default device cuda:0 + points_per_batch applied in flat mode.
fvdb_reality_capture/foundation_models/sam1.py Default device updated to cuda:0.
fvdb_reality_capture/foundation_models/openclip.py Default device updated to cuda:0.
fvdb_reality_capture/foundation_models/dlnr.py Default device updated to cuda:0 and docstring updated.
fvdb_reality_capture/cli/frgs/_show.py frgs show now supports .garfvdb bundles and GARfVDB overlay controls.
fvdb_reality_capture/cli/frgs/_resume.py frgs resume now dispatches via checkpoint container + resume registry.
fvdb_reality_capture/cli/frgs/_resume_registry.py New CLI-owned resume-handler registry + method lookup.
fvdb_reality_capture/cli/frgs/_reconstruct.py CLI transform config now subclasses shared SceneTransformConfig; device default cuda:0.
fvdb_reality_capture/cli/frgs/_points.py Device default updated to cuda:0.
fvdb_reality_capture/cli/frgs/_mesh_dlnr.py Device default updated to cuda:0.
fvdb_reality_capture/cli/frgs/_mesh_basic.py Device default updated to cuda:0.
fvdb_reality_capture/cli/frgs/_instance_segmentation.py New frgs instance-segmentation command.
fvdb_reality_capture/cli/frgs/_evaluate.py Loads Gaussian checkpoints via container loader; device default cuda:0.
fvdb_reality_capture/cli/frgs/_convert.py Loads Gaussian checkpoints via container loader for conversion paths.
fvdb_reality_capture/cli/frgs/_common.py Switches to library-layer load_splats_from_file and re-exports it.
fvdb_reality_capture/cli/frgs/init.py Registers InstanceSegmentation command with CLI entrypoint.
fvdb_reality_capture/checkpoints.py New method-neutral, versioned training checkpoint container + legacy adapters.
fvdb_reality_capture/init.py Exposes new submodules (including checkpoints and instance_segmentation).
docs/tutorials/instance_segmentation.rst New tutorial covering training, artifact layout, viewing, and resume.
docs/index.rst Adds instance segmentation tutorial/API docs and checkpoints API page.
docs/api/transforms.rst Documents SceneTransformConfig in transforms API listing.
docs/api/instance_segmentation.rst New instance segmentation API page.
docs/api/frgs/show.rst Updates frgs show docs for .garfvdb support and device default.
docs/api/frgs/resume.rst Updates frgs resume docs for container dispatch and new options.
docs/api/frgs/reconstruct.rst Updates reconstruct docs for device default cuda:0.
docs/api/frgs/points.rst Updates points docs for device default cuda:0.
docs/api/frgs/mesh_dlnr.rst Updates mesh-dlnr docs for device default cuda:0.
docs/api/frgs/mesh_basic.rst Updates mesh-basic docs for device default cuda:0.
docs/api/frgs/instance_segmentation.rst New CLI doc snippet for frgs instance-segmentation.
docs/api/frgs/evaluate.rst Updates evaluate docs for device default cuda:0.
docs/api/frgs.rst Updates CLI overview and includes instance-segmentation docs.
docs/api/checkpoints.rst New documentation page for the training checkpoint container design.
CHANGES.md Adds an unreleased 0.6.0 changelog section describing GARfVDB + infra.
.gitignore Ignores .garfvdb bundles.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fvdb_reality_capture/instance_segmentation/util.py Outdated
Comment thread fvdb_reality_capture/instance_segmentation/training/dataset_transforms.py Outdated
Comment thread docs/api/transforms.rst
swahtz and others added 5 commits July 20, 2026 17:51
Change default max epochs in garfvdb

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
The ported prototype built the per-pixel mask-selection CDF by sorting the
per-mask areas by size and then indexing that sorted table by mask id. After
the sort the probability table no longer lined up with the mask ids, so each
pixel was weighted by the wrong mask's area, and `num_pix_per_mask[0] = 0`
zeroed the smallest-area mask instead of the -1 "no mask" padding (which was
left in with a nonzero probability).

Reimplement with a bincount indexed by (id + 1) that zeroes the -1 padding and
gathers each pixel's mask probability by id. Verified against an independent
reference over random inputs. Because mask_cdf is recomputed from
pixel_to_mask_id at load time, the fix applies to existing caches without
regenerating them; it does change the training mask-selection distribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
- save_image: the JPEG branch multiplied an already-uint8 image by 255 again,
  saturating saved JPEGs to white; drop the redundant rescale (matches the PNG
  branch).
- Resize: scale camera intrinsics with the image (multiply fx/fy/cx/cy by the
  scale factor) instead of dividing, so they stay consistent with the resized
  image. Resize is currently unused, so this was a latent bug.
- segmentation_writer: use max_attempts in the retry-loop condition instead of
  a hard-coded 50.
- docs/transforms.rst: align the inconsistent Sphinx option indentation on the
  Identity/SceneTransformConfig autoclass directives.

Addresses GitHub Copilot review comments on openvdb#308.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
…ssian affinities in the training feature space. Add regression coverage for each fix.

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
…image IDs for stable pose matching, and include camera parameters in mask-cache keys. Scale intrinsics using actual rounded resize dimensions and add regression coverage.

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 3 comments.

Comment thread fvdb_reality_capture/instance_segmentation/viewer.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

fvdb_reality_capture/instance_segmentation/training/dataset_transforms.py:82

  • RandomSelectMaskIDAndScale builds random tensors via torch.full(..., torch.rand(...).item()) without specifying a device. If this transform is ever applied to CUDA tensors (e.g. after moving a batch to GPU), it will create CPU random tensors and fail with a device-mismatch error in comparisons / indexing. It’s easy to keep the intended “one random value per image” behavior while allocating on per_pixel_index.device.

Comment thread fvdb_reality_capture/instance_segmentation/util.py Outdated
Comment thread fvdb_reality_capture/instance_segmentation/util.py Outdated
Two defects in instance_segmentation/util.py flagged by Copilot on PR openvdb#308:

- compute_mask_cdf weighted each mask by log(prob), which is <= 0. A pixel
  whose only mask has probability 1 (a lone mask, log(1) = 0) produced a
  per-pixel weight sum of 0, so the CDF was all zeros and the consumer
  (sum(u > cdf)) selected the -1 padding slot instead of the single valid
  mask -- that pixel got no supervision. Switch to -log(prob) (>= 0, same
  relative weighting so small masks stay favored) and fall back to a uniform
  distribution over a pixel's valid masks when the weight sum is 0, so the CDF
  always terminates at 1 on a real mask. Fully-unmasked pixels still resolve to
  padding, as before.

- unique_values_to_colors computed the HSV chroma/second-component/offset
  (c, x, m) but always assigned (R, G, B) = (c, x, m) regardless of hue sector.
  With s = v = 1 that collapses every color to (1, x, 0) -- only the red->yellow
  sixth of the wheel -- so generated colors were not distinct. Permute
  (c, x, 0) per 60-degree sector and add the achromatic offset to all channels,
  and drop the linspace endpoint so hue 0 and hue 1 (both red) don't collide.

Verified: lone-mask pixels now select the real mask, small masks remain favored,
and six values map to six evenly spaced hues spanning the full wheel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 3 comments.

Comment thread fvdb_reality_capture/instance_segmentation/optim.py
Comment thread fvdb_reality_capture/instance_segmentation/viewer.py
Comment thread fvdb_reality_capture/instance_segmentation/scene_attribute.py
swahtz and others added 2 commits July 22, 2026 15:14
…_steps == warmup_steps

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Load weights_only in GarfvdbMaskAttribute

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 2 comments.

Comment thread fvdb_reality_capture/instance_segmentation/training/dataset_transforms.py Outdated
Background pixels (those intersecting no mask) carry a -1 padding id in
mask_ids. Both mask-selection transforms indexed the per-image scales with that
id directly:

- RandomSelectMaskIDAndScale (CPU): scales[-1] silently selected the last mask's
  scale for every background pixel.

- GPURandomSelectMaskIDAndScale: batch_offsets + (-1) goes negative for batch
  element 0 and wraps into another image's scales -- a cross-image, batch-order-
  dependent read.

These pixels are already excluded from every loss term (loss.py masks pairs
where mask_ids == -1), so there was no training-correctness impact, but the
lookups were fragile. Clamp the lookup index to >= 0 in both paths and zero the
resulting scale for background pixels, while keeping mask_ids as -1 so
downstream loss masking is unchanged.

Verified: background pixels now receive a zero scale (CPU and GPU), the GPU path
no longer reads a neighbouring image's scale, and valid pixels are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 3 comments.

Comment thread fvdb_reality_capture/instance_segmentation/viewer.py Outdated
Comment thread fvdb_reality_capture/instance_segmentation/util.py Outdated
Comment thread fvdb_reality_capture/instance_segmentation/util.py Outdated
…review)

- viewer.py _camera_tuple_to_c2w computed the camera position from the raw
  eye_direction (center - eye_direction * radius), so a non-unit eye_direction
  made the effective orbit radius depend on its magnitude. Offset by the
  normalized forward instead, so the radius is exactly `radius`. Identical when
  eye_direction is already unit-length.

- pca_projection_fast and apply_pca_projection docstrings claimed the result is
  always [B, H, W, n_components], but the mask-less path returns the flattened
  [B*H*W, n_components] projection. Document the conditional shape so callers
  don't assume the 4D form. (Both in-repo callers pass a mask, so behavior is
  unchanged; docs only.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 1 comment.

Comment thread fvdb_reality_capture/sfm_scene/sfm_cache.py Outdated
FileLock's SIGALRM-based timeout only works on the main thread, so worker
threads (e.g. the background SfM cache writer) fell back to a blocking flock
with no timeout. A lock held indefinitely by a crashed or deadlocked writer
would hang that thread forever and stall training/shutdown.

Worker threads now acquire the lock by polling a non-blocking flock (LOCK_NB)
until it succeeds or timeout_seconds elapses, raising TimeoutError on expiry --
mirroring the main-thread timeout behavior. The acquire paths are split into
_acquire_with_signal_timeout (main thread) and _acquire_with_polling_timeout
(worker threads). Non-EAGAIN/EWOULDBLOCK errors (e.g. ENOSYS) still propagate
and map to NotImplementedError as before; other OSErrors are now re-raised
instead of being silently swallowed.

Verified: with the lock held, a worker thread raises TimeoutError after
~timeout_seconds instead of hanging; once released it acquires immediately; the
main-thread path is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 72 out of 73 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

docs/api/frgs/show.rst:28

  • The frgs show help snippet appears incomplete: the CLI now exposes GARfVDB-specific flags (e.g. --scale-fraction, --mask-blend, --lock-pca-colors, overlay sizing), but they are not reflected here. This documentation will be out of sync with the actual CLI interface.
    │ -v, --verbose, --no-verbose                                                                  │
    │                         If True, then the viewer will log verbosely. (default: False)        │
    │ --device STR|DEVICE     Device to use for computation (default is "cuda:0"). (default: cuda:0) │
    ╰──────────────────────────────────────────────────────────────────────────────────────────────╯

Comment thread docs/api/frgs/show.rst Outdated
The help for --viewer-ip-address was a copy-paste from --viewer-port and
described "The port to expose the viewer server on." tyro derives the help
string from the comment above the field, so both the CLI and the captured docs
showed the wrong description for an IP-address option.

Correct the source comment in _show.py and _show_data.py (the frgs resume,
reconstruct, and instance-segmentation variants already read "IP address") and
update the captured show.rst / show_data.rst help snippets to match, preserving
the box-drawing column width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
@swahtz
swahtz marked this pull request as ready for review August 19, 2026 23:59
@swahtz
swahtz requested a review from a team as a code owner August 19, 2026 23:59
@swahtz
swahtz requested review from matthewdcong and phapalova and removed request for a team August 19, 2026 23:59
swahtz and others added 2 commits August 20, 2026 12:10
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Per PR review (harrism), rename the CLI method to `frgs segment-instances`.
tyro derives the subcommand name from the command class, so:

- Rename cli/frgs/_instance_segmentation.py -> _segment_instances.py and the
  classes InstanceSegmentation -> SegmentInstances and
  InstanceSegmentationWriterConfig -> SegmentInstancesWriterConfig, matching the
  repo's _<command>.py convention.
- Update the frgs command union, the docstring example, and the use-grid error.
- Update tests/unit/test_garfvdb_cli.py import, target, and test name.
- Rename docs/api/frgs/instance_segmentation.rst -> segment_instances.rst,
  update its usage/options/example text, and update the frgs.rst section header
  and include path.
- Update the tutorial command example and CHANGES.md.

The instance_segmentation Python package, the instance_segmentation.garfvdb
checkpoint method ID, and prose describing the concept are unchanged -- only the
user-facing command name is renamed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants