def init_weights(layer, name='kaiming_uniform',
                 uniform_a=0.0, uniform_b=1.0,
                 normal_mean=0.0, normal_std=1.0,
                 constant_val=0.0,
                 xavier_gain=1.0,
                 kaiming_a=0, kaiming_mode='fan_in',
                 kaiming_nonlinearity='leaky_relu',
                 trunc_mean=0.0, trunc_std=1.0, trunc_a=-2, trunc_b=2,
                 orthogonal_gain=1.0,
                 sparse_sparsity=None, sparse_std=0.01, sparse_generator=None):
    """
    Initialize weights for a layer

    Parameters
    ----------
    layer : torch.nn.Module
        Layer to be initialized.

    name : str, optional (default='kaiming_uniform')
        Initialization type.
        Available types: 'uniform', 'normal', 'constant', 'ones', 'zeros', 'eye', 'dirac',
        'xavier_uniform', 'xavier_normal', 'kaiming_uniform', 'kaiming_normal', 'trunc_normal',
        'orthogonal', 'sparse'.
        See https://pytorch.org/docs/stable/nn.init.html for details.

    uniform_a : float, optional (default=0.0)
        The lower bound for the uniform distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.uniform_ for details.

    uniform_b : float, optional (default=1.0)
        The upper bound for the uniform distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.uniform_ for details.

    normal_mean : float, optional (default=0.0)
        The mean of the normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.normal_ for details.

    normal_std : float, optional (default=1.0)
        The standard deviation of the normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.normal_ for details.

    constant_val : float, optional (default=0.0)
        The value to fill the tensor with.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.constant_ for details.

    xavier_gain : float, optional (default=1.0)
        An optional scaling factor.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.xavier_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.xavier_normal_ for details.

    kaiming_a : float, optional (default=0)
        The negative slope of the rectifier used after this layer (only used with 'leaky_relu')
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    kaiming_mode : str, optional (default='fan_in')
        The mode for kaiming initialization. Available modes: 'fan_in', 'fan_out'.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    kaiming_nonlinearity : str, optional (default='leaky_relu')
        The non-linear function (nn.functional name), recommended to use only with 'relu' or 'leaky_relu'.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    trunc_mean : float, optional (default=0.0)
        The mean value of the truncated normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_std : float, optional (default=1.0)
        The standard deviation of the truncated normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_a : float, optional (default=-2)
        The minimum cutoff value.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_b : float, optional (default=2)
        The maximum cutoff value.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    orthogonal_gain : float, optional (default=1.0)
        The optional scaling factor
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.orthogonal_ for details.

    sparse_sparsity : float, optional (default=None)
        This parameter must be provided if used!
        The fraction of elements in each column to be set to zero.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.

    sparse_std : float, optional (default=0.01)
        The standard deviation of the normal distribution used to generate the non-zero values
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.

    sparse_generator : Optional[Generator] (default=None)
        The torch Generator to sample from.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.
    """
    init_name_dict = {
        'uniform': nn.init.uniform_,
        'normal': nn.init.normal_,
        'constant': nn.init.constant_,
        'ones': nn.init.ones_,
        'zeros': nn.init.zeros_,
        'eye': nn.init.eye_,
        'xavier_uniform': nn.init.xavier_uniform_,
        'xavier_normal': nn.init.xavier_normal_,
        'kaiming_uniform': nn.init.kaiming_uniform_,
        'kaiming_normal': nn.init.kaiming_normal_,
        'trunc_normal': nn.init.trunc_normal_,
        'orthogonal': nn.init.orthogonal_,
        'sparse': nn.init.sparse_
    }

    if name in init_name_dict.keys():
        if name == 'uniform':
            init_name_dict[name](layer.weight, a=uniform_a, b=uniform_b)
        elif name == 'normal':
            init_name_dict[name](layer.weight, mean=normal_mean,
                                 std=normal_std)
        elif name == 'constant':
            init_name_dict[name](layer.weight, val=constant_val)
        elif name == 'ones':
            init_name_dict[name](layer.weight)
        elif name == 'zeros':
            init_name_dict[name](layer.weight)
        elif name == 'eye':
            init_name_dict[name](layer.weight)
        elif name == 'xavier_uniform':
            init_name_dict[name](layer.weight, gain=xavier_gain)
        elif name == 'xavier_normal':
            init_name_dict[name](layer.weight, gain=xavier_gain)
        elif name == 'kaiming_uniform':
            init_name_dict[name](layer.weight, a=kaiming_a, mode=kaiming_mode,
                                 nonlinearity=kaiming_nonlinearity)
        elif name == 'kaiming_normal':
            init_name_dict[name](layer.weight, a=kaiming_a, mode=kaiming_mode,
                                 nonlinearity=kaiming_nonlinearity)
        elif name == 'trunc_normal':
            init_name_dict[name](layer.weight, mean=trunc_mean, std=trunc_std,
                                 a=trunc_a, b=trunc_b)
        elif name == 'orthogonal':
            init_name_dict[name](layer.weight, gain=orthogonal_gain)
        elif name == 'sparse':
            init_name_dict[name](layer.weight, sparsity=sparse_sparsity,
                                 std=sparse_std)
    else:
        raise ValueError(f"{name} is not a valid initialization type.")

    Initialize weights for a layer

    Parameters
    ----------
    layer : torch.nn.Module
        Layer to be initialized.

    name : str, optional (default='kaiming_uniform')
        Initialization type.
        Available types: 'uniform', 'normal', 'constant', 'ones', 'zeros', 'eye', 'dirac',
        'xavier_uniform', 'xavier_normal', 'kaiming_uniform', 'kaiming_normal', 'trunc_normal',
        'orthogonal', 'sparse'.
        See https://pytorch.org/docs/stable/nn.init.html for details.

    uniform_a : float, optional (default=0.0)
        The lower bound for the uniform distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.uniform_ for details.

    uniform_b : float, optional (default=1.0)
        The upper bound for the uniform distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.uniform_ for details.

    normal_mean : float, optional (default=0.0)
        The mean of the normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.normal_ for details.

    normal_std : float, optional (default=1.0)
        The standard deviation of the normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.normal_ for details.

    constant_val : float, optional (default=0.0)
        The value to fill the tensor with.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.constant_ for details.

    xavier_gain : float, optional (default=1.0)
        An optional scaling factor.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.xavier_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.xavier_normal_ for details.

    kaiming_a : float, optional (default=0)
        The negative slope of the rectifier used after this layer (only used with 'leaky_relu')
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    kaiming_mode : str, optional (default='fan_in')
        The mode for kaiming initialization. Available modes: 'fan_in', 'fan_out'.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    kaiming_nonlinearity : str, optional (default='leaky_relu')
        The non-linear function (nn.functional name), recommended to use only with 'relu' or 'leaky_relu'.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_uniform_ 
        and https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.kaiming_normal_ for details.

    trunc_mean : float, optional (default=0.0)
        The mean value of the truncated normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_std : float, optional (default=1.0)
        The standard deviation of the truncated normal distribution.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_a : float, optional (default=-2)
        The minimum cutoff value.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    trunc_b : float, optional (default=2)
        The maximum cutoff value.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.trunc_normal_ for details.

    orthogonal_gain : float, optional (default=1.0)
        The optional scaling factor
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.orthogonal_ for details.

    sparse_sparsity : float, optional (default=None)
        This parameter must be provided if used!
        The fraction of elements in each column to be set to zero.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.

    sparse_std : float, optional (default=0.01)
        The standard deviation of the normal distribution used to generate the non-zero values
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.

    sparse_generator : Optional[Generator] (default=None)
        The torch Generator to sample from.
        See https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.sparse_ for details.
    
pyod/utils/torch_utility.py