Skip to content

Commit 5923849

Browse files
Correct the model retrieval
1 parent 70ea28e commit 5923849

3 files changed

Lines changed: 82 additions & 36 deletions

File tree

gsplatInterface/trainer.py

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
from typing import Literal, assert_never
4040
from utils import AppearanceOptModule, CameraOptModule, knn, rgb_to_sh, set_random_seed
4141

42+
from numpy.core.multiarray import scalar as npscalar
43+
from numpy.dtypes import Float64DType as npFloat64DType
44+
from numpy import dtype as npdtype
45+
4246
from gsplat import export_splats
4347
from gsplat.distributed import cli
4448
from gsplat.optimizers import SelectiveAdam
@@ -58,6 +62,9 @@ class Config:
5862
# Path to the .pt files to load and resume training
5963
resume_ckpt: Optional[str] = ""
6064

65+
# Whether to retrieve optimizer state from the checkpoint
66+
retrieve_optimizer_state: bool = True
67+
6168
# Path to the dataset
6269
sfm_file: str = "sfm.json"
6370
image_alpha: bool = False
@@ -127,6 +134,9 @@ class Config:
127134
# Use random background for training to discourage transparency
128135
random_bkgd: bool = False
129136

137+
# Whether to use schedulers for the learning rates (only for MCMC)
138+
use_scheduler: bool = True
139+
130140
# LR for 3D point positions
131141
means_lr: float = 1.6e-4
132142
# LR for Gaussian scale factors
@@ -222,6 +232,7 @@ def create_splats_with_optimizers(
222232
device: str = "cuda",
223233
world_rank: int = 0,
224234
world_size: int = 1,
235+
strategy: Union[DefaultStrategy, MCMCStrategy] = DefaultStrategy,
225236
) -> Tuple[torch.nn.ParameterDict, Dict[str, torch.optim.Optimizer]]:
226237

227238
#initialize from sfm
@@ -328,6 +339,12 @@ def __init__(
328339

329340
logging.info(f"Scene scale: {self.scene_scale}")
330341

342+
retrieve_optimizer_state = cfg.retrieve_optimizer_state and cfg.resume_ckpt != ""
343+
if retrieve_optimizer_state and isinstance(cfg.strategy, MCMCStrategy):
344+
# In case of MCMC, the scheduler reduces the effective learning rate by 100
345+
# This line updates the learning rate accordingly
346+
cfg.means_lr = 0.01 * cfg.means_lr
347+
331348
# Model
332349
feature_dim = 32 if cfg.app_opt else None
333350
self.splats, self.optimizers = create_splats_with_optimizers(
@@ -349,6 +366,7 @@ def __init__(
349366
device=self.device,
350367
world_rank=world_rank,
351368
world_size=world_size,
369+
strategy=cfg.strategy,
352370
)
353371
logging.info(f"Model initialized. Number of GS: {len(self.splats['means'])}")
354372

@@ -517,37 +535,42 @@ def train(self):
517535
#Compute effective steps
518536
max_steps = cfg.max_epochs * len(self.trainset)
519537

520-
schedulers = [
521-
# means has a learning rate schedule, that end at 0.01 of the initial value
522-
torch.optim.lr_scheduler.ExponentialLR(
523-
self.optimizers["means"], gamma=0.01 ** (1.0 / max_steps)
524-
),
525-
]
538+
schedulers = []
539+
if isinstance(cfg.strategy, MCMCStrategy) and cfg.use_scheduler:
526540

527-
if cfg.pose_opt:
528-
# pose optimization has a learning rate schedule
529-
schedulers.append(
541+
logging.info("Create schedulers")
542+
543+
schedulers = [
544+
# means has a learning rate schedule that ends at 0.01 of the initial value
530545
torch.optim.lr_scheduler.ExponentialLR(
531-
self.pose_optimizers[0], gamma=0.01 ** (1.0 / max_steps)
546+
self.optimizers["means"], gamma=0.01 ** (1.0 / max_steps)
547+
),
548+
]
549+
550+
if cfg.pose_opt:
551+
# pose optimization has a learning rate schedule
552+
schedulers.append(
553+
torch.optim.lr_scheduler.ExponentialLR(
554+
self.pose_optimizers[0], gamma=0.01 ** (1.0 / max_steps)
555+
)
532556
)
533-
)
534557

535-
if cfg.use_bilateral_grid:
536-
# bilateral grid has a learning rate schedule. Linear warmup for 1000 steps.
537-
schedulers.append(
538-
torch.optim.lr_scheduler.ChainedScheduler(
539-
[
540-
torch.optim.lr_scheduler.LinearLR(
541-
self.bil_grid_optimizers[0],
542-
start_factor=0.01,
543-
total_iters=1000,
544-
),
545-
torch.optim.lr_scheduler.ExponentialLR(
546-
self.bil_grid_optimizers[0], gamma=0.01 ** (1.0 / max_steps)
547-
),
548-
]
558+
if cfg.use_bilateral_grid:
559+
# bilateral grid has a learning rate schedule. Linear warmup for 1000 steps.
560+
schedulers.append(
561+
torch.optim.lr_scheduler.ChainedScheduler(
562+
[
563+
torch.optim.lr_scheduler.LinearLR(
564+
self.bil_grid_optimizers[0],
565+
start_factor=0.01,
566+
total_iters=1000,
567+
),
568+
torch.optim.lr_scheduler.ExponentialLR(
569+
self.bil_grid_optimizers[0], gamma=0.01 ** (1.0 / max_steps)
570+
),
571+
]
572+
)
549573
)
550-
)
551574

552575
trainloader = torch.utils.data.DataLoader(
553576
self.trainset,
@@ -560,6 +583,19 @@ def train(self):
560583

561584
step = -1
562585

586+
if cfg.resume_ckpt != "":
587+
torch.serialization.add_safe_globals([npscalar, npdtype, npFloat64DType])
588+
logging.info("Loading Gaussians from checkpoint")
589+
ckpt = torch.load(cfg.resume_ckpt, map_location=device, weights_only=True)
590+
for k in self.splats.keys():
591+
self.splats[k].data = torch.cat([ckpt["splats"][k]])
592+
if cfg.retrieve_optimizer_state:
593+
logging.info("Loading optimizer state from checkpoint")
594+
self.strategy_state = ckpt["strategy_state"]
595+
for name, opt_state_dict in ckpt["optimizer_state_dicts"].items():
596+
self.optimizers[name].load_state_dict(opt_state_dict)
597+
step = ckpt["step"] - 1
598+
563599
if not cfg.use_progress_bar:
564600
logging.info("Training started")
565601

@@ -763,7 +799,10 @@ def train(self):
763799
if epoch in [i - 1 for i in cfg.save_epochs] or epoch == cfg.max_epochs - 1:
764800

765801
path = f"{self.ckpt_dir}/ckpt_{epoch}_rank{self.world_rank}.pt"
766-
data = {"step": step, "splats": self.splats.state_dict()}
802+
data = {"step": step,
803+
"splats": self.splats.state_dict(),
804+
"strategy_state": self.strategy_state,
805+
"optimizer_state_dicts": {name: opt.state_dict() for name, opt in self.optimizers.items()}}
767806

768807
if cfg.pose_opt:
769808
if world_size > 1:
@@ -784,13 +823,6 @@ def main(local_rank: int, world_rank, world_size: int, cfg: Config):
784823
#Create object for computation
785824
runner = Runner(local_rank, world_rank, world_size, cfg)
786825

787-
#if a checkpoint was passed, will load the gaussians from there
788-
if cfg.resume_ckpt != "":
789-
logging.info("Loading from checkpoint")
790-
ckpt = torch.load(cfg.resume_ckpt, map_location=runner.device, weights_only=True)
791-
for k in runner.splats.keys():
792-
runner.splats[k].data = torch.cat([ckpt["splats"][k]])
793-
794826
#Launch training
795827
runner.train()
796828

gsplatInterface/viewer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
from datasets.sfm.sceneManager import PoseParser
2020
# from cameraPosesParser import CameraParser
21+
from numpy.core.multiarray import scalar as npscalar
22+
from numpy.dtypes import Float64DType as npFloat64DType
23+
from numpy import dtype as npdtype
2124

2225

2326
def get_cameras_from_sfm(sfmFile):
@@ -56,7 +59,8 @@ def get_cameras_from_sfm(sfmFile):
5659
def main(local_rank: int, world_rank, world_size: int, args):
5760
torch.manual_seed(42)
5861
device = torch.device("cuda", local_rank)
59-
62+
torch.serialization.add_safe_globals([npscalar, npdtype, npFloat64DType])
63+
6064
means, quats, scales, opacities, sh0, shN = [], [], [], [], [], []
6165
for ckpt_path in args.ckpt:
6266
ckpt = torch.load(ckpt_path, map_location=device, weights_only=True)["splats"]

meshroom/mrGSplat/GaussianSplattingOptim.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,14 @@ def buildCommandLine(self, chunk):
7373
if node.revisedOpacity.value:
7474
cmdLine += " --revised_opacity"
7575

76+
if not node.retrieveOptimState.value:
77+
cmdLine += " --no-retrieve_optimizer_state"
78+
7679
if node.useProgressBar.value:
7780
cmdLine += f" --use_progress_bar"
7881

7982
node.nodeDesc.commandLine = cmdLine
8083

81-
8284
return super().buildCommandLine(chunk)
8385

8486
inputs = [
@@ -101,6 +103,14 @@ def buildCommandLine(self, chunk):
101103
description="Resume from Model",
102104
value="",
103105
),
106+
desc.BoolParam(
107+
name="retrieveOptimState",
108+
label="Retrieve Optimizer State",
109+
description="Whether to retrieve optimizer state from the checkpoint.",
110+
value=True,
111+
commandLineGroup=None,
112+
enabled=lambda node: node.resume_ckpt.value != ""
113+
),
104114
desc.ChoiceParam(
105115
name='strategy',
106116
label='Densification Strategy',

0 commit comments

Comments
 (0)