""" Copyright (c) Facebook, Inc. and its affiliates. Copyright (c) Microsoft Corporation. Licensed under the MIT License. Adapted from https://github.com/FAIR-Chem/fairchem/blob/main/src/fairchem/core/models/gemnet/initializers.py. """ import torch # This function is not type annotated because mypy complains that axis could be either an integer or a tuple of integers, # even though this is precicely how torch.var_mean works def _standardize(kernel): """ Makes sure that N*Var(W) = 1 and E[W] = 0 """ eps = 1e-6 if len(kernel.shape) == 3: axis = (0, 1) # last dimension is output dimension else: axis = 1 var, mean = torch.var_mean(kernel, dim=axis, unbiased=True, keepdim=True) kernel = (kernel - mean) / (var + eps) ** 0.5 return kernel def he_orthogonal_init(tensor: torch.Tensor) -> torch.Tensor: """ Generate a weight matrix with variance according to He (Kaiming) initialization. Based on a random (semi-)orthogonal matrix neural networks are expected to learn better when features are decorrelated (stated by eg. "Reducing overfitting in deep networks by decorrelating representations", "Dropout: a simple way to prevent neural networks from overfitting", "Exact solutions to the nonlinear dynamics of learning in deep linear neural networks") """ tensor = torch.nn.init.orthogonal_(tensor) if len(tensor.shape) == 3: fan_in = tensor.shape[:-1].numel() else: fan_in = tensor.shape[1] with torch.no_grad(): tensor.data = _standardize(tensor.data) tensor.data *= (1 / fan_in) ** 0.5 return tensor