nerf / neuralangelo-main /imaginaire /models /utils /model_average.py
asmadeyi's picture
Upload 72 files
c29de8d
Raw
History Blame Contribute Delete
4.1 kB
'''
-----------------------------------------------------------------------------
Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
NVIDIA CORPORATION and its licensors retain all intellectual property
and proprietary rights in and to this software, related documentation
and any modifications thereto. Any use, reproduction, disclosure or
distribution of this software and related documentation without an express
license agreement from NVIDIA CORPORATION is strictly prohibited.
-----------------------------------------------------------------------------
'''
import copy
import torch
from torch import nn
from imaginaire.utils.misc import requires_grad
def reset_batch_norm(m):
r"""Reset batch norm statistics
Args:
m: Pytorch module
"""
if hasattr(m, 'reset_running_stats'):
m.reset_running_stats()
def calibrate_batch_norm_momentum(m):
r"""Calibrate batch norm momentum
Args:
m: Pytorch module
"""
if hasattr(m, 'reset_running_stats'):
# if m._get_name() == 'SyncBatchNorm':
if 'BatchNorm' in m._get_name():
m.momentum = 1.0 / float(m.num_batches_tracked + 1)
class ModelAverage(nn.Module):
r"""In this model average implementation, the spectral layers are
absorbed in the model parameter by default. If such options are
turned on, be careful with how you do the training. Remember to
re-estimate the batch norm parameters before using the model.
Args:
module (torch nn module): Torch network.
beta (float): Moving average weights. How much we weight the past.
start_iteration (int): From which iteration, we start the update.
"""
def __init__(self, module, beta=0.9999, start_iteration=0):
super(ModelAverage, self).__init__()
self.module = module
# A shallow copy creates a new object which stores the reference of
# the original elements.
# A deep copy creates a new object and recursively adds the copies of
# nested objects present in the original elements.
self._averaged_model = copy.deepcopy(self.module).to('cuda')
self.stream = torch.cuda.Stream()
self.beta = beta
self.start_iteration = start_iteration
# This buffer is to track how many iterations has the model been
# trained for. We will ignore the first $(start_iterations) and start
# the averaging after.
self.register_buffer('num_updates_tracked',
torch.tensor(0, dtype=torch.long))
self.num_updates_tracked = self.num_updates_tracked.to('cuda')
self.averaged_model.eval()
# Averaged model does not require grad.
requires_grad(self.averaged_model, False)
@property
def averaged_model(self):
self.stream.synchronize()
return self._averaged_model
def forward(self, *inputs, **kwargs):
r"""PyTorch module forward function overload."""
return self.module(*inputs, **kwargs)
@torch.no_grad()
def update_average(self):
r"""Update the moving average."""
self.stream.wait_stream(torch.cuda.current_stream())
with torch.cuda.stream(self.stream):
self.num_updates_tracked += 1
if self.num_updates_tracked <= self.start_iteration:
beta = 0.
else:
beta = self.beta
source_dict = self.module.state_dict()
target_dict = self._averaged_model.state_dict()
source_list = []
target_list = []
for key in target_dict:
if 'num_batches_tracked' in key:
continue
source_list.append(source_dict[key].data)
target_list.append(target_dict[key].data.float())
torch._foreach_mul_(target_list, beta)
torch._foreach_add_(target_list, source_list, alpha=1 - beta)
def __repr__(self):
r"""Returns a string that holds a printable representation of an
object"""
return self.module.__repr__()