Config System#

The wisp configuration system aims for a flexible, minimalist api through building on tyro and hydra-zen.

The following example illustrates the usage:

from wisp.config import configure, autoconfig, parse_config, instantiate
from wisp.models.nefs import NeuralRadianceField
from wisp.models.grids import HashGrid, TriplanarGrid
import torch
from typing import Union, Tuple

# For classes and functions which don't use python typing annotations,
# the best practice is to create a config class, which specifies which args are configurable
# and what their types are:
@configure(target=torch.optim.Adam)     # This config can build torch.optim.Adam
class ConfigAdam:
    lr: float
    betas: Tuple[float, float] = (0.9, 0.999)
    eps: float = 1e-8
    weight_decay: float = 0.0

@configure(target=torch.optim.RMSprop)  # This config can build torch.optim.RMSprop
class ConfigRMSprop:
    lr: float = 1e-2
    alpha: float = 0.99
    eps: float = 1e-8
    weight_decay: float = 0.0
    momentum: float = 0.0

# @configure without a target is equivalent to a @dataclass.
@configure
class AppConfig:
    """  AppConfig is a dataclass holding all configuration fields. """
    # autoconfig() scans the classes for all available constructors, and generate a config dataclass for each.
    # This is useful for classes like grids, which have many types and constructors.
    # The resulting configs are similar to ConfigAdam and ConfigRMSprop above.
    # autoconfig() requires functions to annotate args with typings.
    grid: autoconfig(TriplanarGrid, HashGrid)    # type: Union[ConfigTriplanarGrid, ConfigHashGrid, ConfigHashGridFromGeometric, ...]
    
    # You can also use autoconfig() with a single class or function
    nerf: autoconfig(NeuralRadianceField)        # type: ConfigNeuralRadianceField
    
    # Explicit config set. This is useful, i.e., because the type annotations of torch are incomplete.
    # We specify we want to use the config classes we manually defined above with @configure(target=...)
    optimizer: Union[ConfigAdam, ConfigRMSprop] 
    
# parse_config will read arg values from the CLI to create an AppConfig instance.
# If `--config <path>.yaml` is given, it will also read values from it.
cfg = parse_config(AppConfig, yaml_arg='--config')

grid = instantiate(cfg.grid)                # Build grid instance directly from config
nerf = instantiate(cfg.nerf, grid=grid)     # Build nerf instance from config and grid
optimizer = instantiate(cfg.optimizer, params=nerf.decoder.parameters())      # Build optimizer from config

Running the program above and specifying args from CLI:

python main.py grid:HashGrid.from-geometric optimizer:adam --lr 0.001 --optimizer.eps 0.000001

or with a config file:

grid:
   constructor: 'HashGrid.from_geometric'
   ...
nerf:
   ...
optimizer:
   constructor: 'Adam'
   lr: 1e-3
   eps: 1e-8

Config Presets#

Premade configs for common modules, such as torch optimizers, are included in wisp.config.presets. For example:

from wisp.config.presets import ConfigAdam, ConfigRMSprop, ConfigDataloader

Converting older configs (up to wisp v1.0.2)#

The following is a summary of the previous argparse definitions, mapped to the new config system.

Common args#

--epochs -> --max-epochs
--render-tb-every -> --render-every
--optimizer-type adam -> trainer.optimizer:Adam
--optimizer-type rmsprop -> trainer.optimizer:RMSProp
--multiview-dataset-format standard -> dataset:NeRFSyntheticDataset
--multiview-dataset-format rtmv -> dataset:RTMVDataset

NeRF App#

Arg groups:#

Previously, these are were used to single out multiple choices. These args are now replaced with Unions of configs, which appear in the CLI as subcommands and in the yaml as constructor field.

--multiview-dataset-format -> dataset:NeRFSyntheticDataset or dataset:RTMVDataset
--grid-type -> grid:OctreeGrid, grid:TriplanarGrid, grid:CodebookOctreeGrid, grid:HashGrid.from-geometric
--blas-type -> blas:OctreeAS.make-dense or blas:AxisAlignedBBoxAS
--optimizer-type -> trainer.optimizer:Adam or trainer.optimizer:RMSprop

Args renamed:#

The following args have been renamed to better match the new config hierarchy.

logging:
--profile -> --trainer.profile_nvtx

dataset:
--dataloader-num-workers -> --trainer.dataloader.num_workers
--bg-color -> --dataset.bg-color, --tracer.bg-color (two configs use this arg, with an identical name)
--num-rays-sampled-per-img -> dataset-transform.num_samples

grid:
--blas-levels -> --blas.level

trainer:
--epochs -> --trainer.max_epochs
--render-tb-every -> --trainer.render-every
--valid-only -> --trainer.mode (arg is now a string literal, not a bool, with values 'train', 'validate')
--rgb-loss --> --trainer.rgb-lambda

--wandb-project -> --tracker.wandb.project
--wandb-run-name -> --tracker.wandb.run-name
--wandb-entity -> --tracker.wandb.entity
--wandb-viz-nerf-angles -> --tracker.vis_camera.viz360-num-angles
--wandb-viz-nerf-distance -> --tracker.vis_camera.viz360-radius
See also new arg: --tracker.vis_camera.viz360-render-all-lods

Args removed:#

The following arguments have been deprecated and removed.

--perf (PerfTimer exists but is unused)

--tree-type 
Before: For HashGrids only: how the resolution of the grid is determined.
        "geometric" uses the geometric sequence initialization from InstantNGP,
        "quad" uses an octree sampling pattern.
Now   : Use autoconfig(HashGrid.from_geometric, HashGrid.from_octree) to choose between those two hashgrid constructors.
        For brevity, HashGrid.from_octree was dropped from the default config. 

--blas-level
Before: For HashGrids only: Determines the number of levels in the acceleration structure
        used to track the occupancy status (bottom level acceleration structure).
Now   : This arg was redundant, and is now supported through the new blas arg, see: blas.level

--resample, --resample-every (Resampling datasets is supported, but removed from this script as it's unused by default)
--only-last (unused, removed)
--log-tb-every (unused, removed)
--grow-every (unused, removed)
--growth-strategy (unused, removed)
--camera-proj (unused, removed)

Args unchanged (by old category):#

The following arguments are unchanged. Here we specify their complete prefix, e.g. which config they belong in.

Note: when specifying those args via CLI, if an arg name is unique, specifying the arg name without the full prefix is enough (i.e. --exp-name rather than --trainer.exp-name).

logging:
--exp-name -> --trainer.exp-name
--log-level -> --log-level

dataset:
--dataset-path -> --dataset.dataset-path
--dataset_num_workers -> --dataset.dataset-num-workers 
--mip -> --dataset.mip

grid:
--interpolation-type -> --grid.interpolation-type
--multiscale-type -> --grid.multiscale-type
--feature-dim -> --grid.feature-dim
--feature-std -> --grid.feature-std
--feature-bias -> --grid.feature-bias 
--log-base-resolution -> --grid.log-base-resolution (only for grid:TriplanarGrid)
--num-lods -> --grid.num-lods (only for grid:OctreeGrid, grid:CodebookGrid)
--codebook-bitwidth -> --grid.codebook-bitwidth (only for grid:CodebookOctreeGrid, grid:HashGrid)
--min-grid-res -> --grid.min_grid_res (only for grid:HashGrid.from-geometric)
--max-grid-res -> --grid.max_grid_res (only for grid:HashGrid.from-geometric)
--prune-min-density -> --nef.prune-min-density      (used with grids which support pruning)
--prune-density-decay -> --nef.prune_density_decay  (used with grids which support pruning)

nef:
--pos-embedder -> --nef.pos-embedder
--view-embedder -> --nef.view-embedder
--position-input -> --nef.position-input
--pos-multires -> --nef.pos-multires
--view-multires -> --nef.view-multires
--layer-type -> --nef.layer-type
--activation-type -> --nef.activation-type
--hidden-dim -> --nef.hidden-dim
--num-layers -> --nef.num-layers

tracer:
--raymarch-type -> --tracer.raymarch-type    (default changed from 'voxel' to 'ray')
--num-steps -> --tracer.num-steps            (default changed from 128 to 1024)

trainer:
# General
--pretrained -> --pretrained
--batch-size -> --trainer.dataloader.batch-size
--model-format -> --trainer.model-format 
--save-as-new -> --trainer.save-as-new
--save_every -> --trainer.save-every
--log-dir -> --tracker.log-dir               (default changed from '_results/logs/runs/' to '_results/logs/'
--prune-every -> --trainer.prune-every       (default changed from -1 to every 100 iterations)
--valid-every -> --trainer.valid-every
--random-lod -> --trainer.random-lod
# Visualizations
--render-res -> --tracker.visualizer.render-res (default set to [512, 512])
--render-batch -> --tracker.visualizer.render-batch (default set to -1)
--camera-origin -> --tracker.vis_camera.camera-origin
--camera-lookat -> --tracker.vis_camera.camera-lookat
--camera-fov -> --tracker.vis_camera.camera-fov
--camera-clamp -> --tracker.vis_camera.camera-clamp
# Optimization
--grid-lr-weight -> --trainer.grid-lr-weight   (see also new arg: feat_lr_weight)
--lr -> --trainer.optimizer.lr        (all optimizer args are now exposed via wisp.config.presets.torch)
--eps -> --trainer.optimizer.eps
--weight-decay -> --trainer.optimizer.weight-decay

NGLOD / SDF App#

In addition to the args listed under the NeRF app, the NGLOD (SDF) app changes other specialized args.

Arg groups:#

Previously, these are were used to single out multiple choices. These args are now replaced with Unions of configs, which appear in the CLI as subcommands and in the yaml as constructor field.

dataset:MeshSampledSDFDataset or dataset:OctreeSampledSDFDataset
Before: the dataset was selected automatically based on OctreeSampledSDFDataset.supports_blas
(if blas is an OctreeAS initialized from a mesh, OctreeSampledSDFDataset was used).
Now: The dataset used is configurable. OctreeSampledSDFDataset.supports_blas is used for validation only.
 
--grid-type -> grid:OctreeGrid, grid:HashGrid.from-geometric, HashGrid.from-geometric, grid:TriplanarGrid 
--blas-type -> blas:OctreeAS.from-mesh or blas:AxisAlignedBBoxAS
--optimizer-type -> trainer.optimizer:Adam or trainer.optimizer:RMSprop

Args renamed:#

The following args have been renamed to better match the new config hierarchy.

dataset:
--dataset-path -> --blas.mesh-path (OctreeSampledSDFDataset only)
--dataset-path -> --dataset.mesh-path (MeshSampledSDFDataset only)
--num_samples_on_mesh -> --blas.num_samples_on_mesh (OctreeAS.from_mesh only)
--num-samples -> --dataset.num-samples
--mode-mesh-norm -> --dataset.mode_norm (MeshSampledSDFDataset only)

Arg defaults:#

The following default args were updated in the core library, to match the previous argparse defaults:

nef:
pos_embedder = 'positional' # previously: 'none'
pos_multires = 4            # previously: 10

tracer:
num_steps = 1024            # previously: 128
step_size = 0.8             # previously: 1.0

Args unchanged (by old category):#

The following arguments are unchanged. Here we specify their complete prefix, e.g. which config they belong in.

Note: when specifying those args via CLI, if an arg name is unique, specifying the arg name without the full prefix is enough (i.e. --exp-name rather than --trainer.exp-name).

dataset:
--sample-mode -> --dataset.sample-mode
--sample-tex -> --dataset.sample-tex
--get_normals -> --dataset.get_normals (MeshSampledSDFDataset only)
--samples-per-voxel --> --dataset.samples-per-voxel (OctreeSampledSDFDataset only)

trainer:
--log_2d -> --trainer.log_2d
--only_last -> --trainer.only-last
--resample -> --trainer.resample
--matcap-path -> --tracker.visualizer.matcap-path
--ao -> --tracker.visualizer.ao
--shadow -> --tracker.visualizer.shadow
--shading-mode -> --tracker.visualizer.shading-mode