| ''' |
| ----------------------------------------------------------------------------- |
| 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 '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 |
| |
| |
| |
| |
| self._averaged_model = copy.deepcopy(self.module).to('cuda') |
| self.stream = torch.cuda.Stream() |
|
|
| self.beta = beta |
|
|
| self.start_iteration = start_iteration |
| |
| |
| |
| 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() |
|
|
| |
| 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__() |
|
|