# coding=utf-8
# Adapted from
# https://github.com/nerfstudio-project/gsplat/blob/main/examples/simple_trainer.py
# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
from dataclasses import dataclass, field
from typing import List, Optional
from typing_extensions import Literal
@dataclass
class Config:
# Path to the .pt files. If provide, it will skip training and run evaluation only.
ckpt: Optional[List[str]] = None
# Path to the Mip-NeRF 360 dataset
data_dir: str = "data/360_v2/garden"
# Downsample factor for the dataset
data_factor: int = 4
# Directory to save results
result_dir: str = "results/garden"
# Every N images there is a test image
test_every: int = 8
# Random crop size for training (experimental)
patch_size: Optional[int] = None
# A global scaler that applies to the scene size related parameters
global_scale: float = 1.0
# Normalize the world space
normalize_world_space: bool = True
# Camera model
camera_model: Literal["pinhole", "ortho", "fisheye"] = "pinhole"
# Port for the viewer server
port: int = 8080
# tile size: 32 or 64
tile_size: int = 32
# Batch size for training. Learning rates are scaled automatically
batch_size: int = 1
# A global factor to scale the number of training steps
steps_scaler: float = 1.0
# Number of training steps
max_steps: int = 30_000
# Steps to evaluate the model
eval_steps: List[int] = field(default_factory=lambda: [500, 7_000, 30_000])
# Steps to save the model
save_steps: List[int] = field(default_factory=lambda: [7_000, 30_000])
# Whether to save ply file (storage size can be large)
save_ply: bool = False
# Steps to save the model as ply
ply_steps: List[int] = field(default_factory=lambda: [7_000, 30_000])
# Initialization strategy
init_type: str = "sfm"
# Initial number of GSs. Ignored if using sfm
init_num_pts: int = 100_000
# Initial extent of GSs as a multiple of the camera extent. Ignored if using sfm
init_extent: float = 3.0
# Degree of spherical harmonics
sh_degree: int = 3
# Turn on another SH degree every this steps
sh_degree_interval: int = 1000
# Initial opacity of GS
init_opa: float = 0.1
# Initial scale of GS
init_scale: float = 1.0
# Weight for SSIM loss
ssim_lambda: float = 0.2
# Near plane clipping distance
near_plane: float = 0.01
# Far plane clipping distance
far_plane: float = 1e10
# Strategy for GS densification
strategy: Optional = None
# Use sparse gradients for optimization. (experimental)
sparse_grad: bool = False
# Opacity regularization
opacity_reg: float = 0.0
# Scale regularization
scale_reg: float = 0.0
# Enable depth loss. (experimental)
depth_loss: bool = False
# Weight for depth loss
depth_lambda: float = 1e-2
# Dump information to tensorboard every this steps
tb_every: int = 100
# Save training images to tensorboard
tb_save_image: bool = False
lpips_net: Literal["vgg", "alex"] = "alex"
# === Densification (gsplat DefaultStrategy) ===
densify: bool = False
prune_opa: float = 0.005
grow_grad2d: float = 0.0002
refine_start_iter: int = 500
refine_stop_iter: int = 15000
refine_every: int = 100
reset_every: int = 3000
def adjust_steps(self, factor: float):
self.eval_steps = [int(i * factor) for i in self.eval_steps]
self.save_steps = [int(i * factor) for i in self.save_steps]
self.ply_steps = [int(i * factor) for i in self.ply_steps]
self.max_steps = int(self.max_steps * factor)
self.sh_degree_interval = int(self.sh_degree_interval * factor)
self.refine_start_iter = int(self.refine_start_iter * factor)
self.refine_stop_iter = int(self.refine_stop_iter * factor)
self.refine_every = int(self.refine_every * factor)
self.reset_every = int(self.reset_every * factor)