mirror of
https://github.com/nerfstudio-project/nerfstudio.git
synced 2026-11-14 03:44:02 +08:00
add gradient accumulation support (#2049)
* add gradient accumulation support * fix 2 blank lines * fix possibly unbound variable * update gradient accumulation step with for loop * add seert and ignore pyright check --------- Co-authored-by: Zhang Jian <zhangjian49@lenovo.com>
This commit is contained in:
1 parent
b17268e83b
commit
c55f5d36b9
1 file changed
+16
-8
@@ -33,8 +33,8 @@ from rich.table import Table
|
||||
from torch.cuda.amp.grad_scaler import GradScaler
|
||||
|
||||
from nerfstudio.configs.experiment_config import ExperimentConfig
|
||||
from nerfstudio.engine.callbacks import TrainingCallback, TrainingCallbackAttributes, TrainingCallbackLocation
|
||||
from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager
|
||||
from nerfstudio.engine.callbacks import TrainingCallback, TrainingCallbackAttributes, TrainingCallbackLocation
|
||||
from nerfstudio.engine.optimizers import Optimizers
|
||||
from nerfstudio.pipelines.base_pipeline import VanillaPipeline
|
||||
from nerfstudio.utils import profiler, writer
|
||||
@@ -82,6 +82,8 @@ class TrainerConfig(ExperimentConfig):
|
||||
"""Path to checkpoint file."""
|
||||
log_gradients: bool = False
|
||||
"""Optionally log gradients during training"""
|
||||
gradient_accumulation_steps: int = 1
|
||||
"""Number of steps to accumulate gradients over."""
|
||||
|
||||
|
||||
class Trainer:
|
||||
@@ -118,6 +120,7 @@ class Trainer:
|
||||
self.mixed_precision: bool = self.config.mixed_precision
|
||||
self.use_grad_scaler: bool = self.mixed_precision or self.config.use_grad_scaler
|
||||
self.training_state: Literal["training", "paused", "completed"] = "training"
|
||||
self.gradient_accumulation_steps: int = self.config.gradient_accumulation_steps
|
||||
|
||||
if self.device == "cpu":
|
||||
self.mixed_precision = False
|
||||
@@ -457,10 +460,15 @@ class Trainer:
|
||||
|
||||
self.optimizers.zero_grad_all()
|
||||
cpu_or_cuda_str: str = self.device.split(":")[0]
|
||||
with torch.autocast(device_type=cpu_or_cuda_str, enabled=self.mixed_precision):
|
||||
_, loss_dict, metrics_dict = self.pipeline.get_train_loss_dict(step=step)
|
||||
loss = functools.reduce(torch.add, loss_dict.values())
|
||||
self.grad_scaler.scale(loss).backward() # type: ignore
|
||||
assert (
|
||||
self.gradient_accumulation_steps > 0
|
||||
), f"gradient_accumulation_steps must be > 0, not {self.gradient_accumulation_steps}"
|
||||
for _ in range(self.gradient_accumulation_steps):
|
||||
with torch.autocast(device_type=cpu_or_cuda_str, enabled=self.mixed_precision):
|
||||
_, loss_dict, metrics_dict = self.pipeline.get_train_loss_dict(step=step)
|
||||
loss = functools.reduce(torch.add, loss_dict.values())
|
||||
loss /= self.gradient_accumulation_steps
|
||||
self.grad_scaler.scale(loss).backward() # type: ignore
|
||||
self.optimizers.optimizer_scaler_step_all(self.grad_scaler)
|
||||
|
||||
if self.config.log_gradients:
|
||||
@@ -469,10 +477,10 @@ class Trainer:
|
||||
assert tag != "Total"
|
||||
if value.grad is not None:
|
||||
grad = value.grad.norm()
|
||||
metrics_dict[f"Gradients/{tag}"] = grad
|
||||
metrics_dict[f"Gradients/{tag}"] = grad # type: ignore
|
||||
total_grad += grad
|
||||
|
||||
metrics_dict["Gradients/Total"] = cast(torch.Tensor, total_grad)
|
||||
metrics_dict["Gradients/Total"] = cast(torch.Tensor, total_grad) # type: ignore
|
||||
|
||||
scale = self.grad_scaler.get_scale()
|
||||
self.grad_scaler.update()
|
||||
@@ -481,7 +489,7 @@ class Trainer:
|
||||
self.optimizers.scheduler_step_all(step)
|
||||
|
||||
# Merging loss and metrics dict into a single output.
|
||||
return loss, loss_dict, metrics_dict
|
||||
return loss, loss_dict, metrics_dict # type: ignore
|
||||
|
||||
@check_eval_enabled
|
||||
@profiler.time_function
|
||||
|
||||
Reference in new issue
Block a user