# -*- coding: utf-8 -*-
""" gtorch_utils/nns/layers/regularizers """

import torch
import torch.nn as nn


class GaussianNoise(nn.Module):
    """
    Gaussian noise regularizer.

    Args:
        sigma (float, optional): relative standard deviation used to generate the
            noise. Relative means that it will be multiplied by the magnitude of
            the value your are adding the noise to. This means that sigma can be
            the same regardless of the scale of the vector.
        is_relative_detach (bool, optional): whether to detach the variable before
            computing the scale of the noise. If `False` then the scale of the noise
            won't be seen as a constant but something to optimize: this will bias the
            network to generate vectors with smaller values.

    Source:
        https://discuss.pytorch.org/t/writing-a-simple-gaussian-noise-layer-in-pytorch/4694/8

    Usage:

       GaussianNoise()
    """

    def __init__(self, sigma=0.1, is_relative_detach=True):
        super().__init__()
        self.sigma = sigma
        self.is_relative_detach = is_relative_detach
        self.register_buffer('noise', torch.tensor(0))

    def forward(self, x):
        if self.training and self.sigma != 0:
            scale = self.sigma * x.detach() if self.is_relative_detach else self.sigma * x
            sampled_noise = self.noise.expand(*x.size()).float().normal_() * scale
            x = x + sampled_noise
        return x

# -*- coding: utf-8 -*-
""" gtorch_utils/nns/layers/regularizers """

import torch
import torch.nn as nn


class GaussianNoise(nn.Module):
    """
    Gaussian noise regularizer.

    Args:
        sigma (float, optional): relative standard deviation used to generate the
            noise. Relative means that it will be multiplied by the magnitude of
            the value your are adding the noise to. This means that sigma can be
            the same regardless of the scale of the vector.
        is_relative_detach (bool, optional): whether to detach the variable before
            computing the scale of the noise. If `False` then the scale of the noise
            won't be seen as a constant but something to optimize: this will bias the
            network to generate vectors with smaller values.

    Source:
        https://discuss.pytorch.org/t/writing-a-simple-gaussian-noise-layer-in-pytorch/4694/8

    Usage:

       GaussianNoise()
    """

    def __init__(self, sigma=0.1, is_relative_detach=True):
        super().__init__()
        self.sigma = sigma
        self.is_relative_detach = is_relative_detach
        self.register_buffer('noise', torch.tensor(0))

    def forward(self, x):
        if self.training and self.sigma != 0:
            scale = self.sigma * x.detach() if self.is_relative_detach else self.sigma * x
            sampled_noise = self.noise.expand(*x.size()).float().normal_() * scale
            x = x + sampled_noise
        return x

# -*- coding: utf-8 -*- gtorch_utils/nns/layers/regularizers Gaussian noise regularizer.      Args:         sigma (float, optional): relative standard deviation used to generate the             noise. Relative means that it will be multiplied by the magnitude of             the value your are adding the noise to. This means that sigma can be             the same regardless of the scale of the vector.         is_relative_detach (bool, optional): whether to detach the variable before             computing the scale of the noise. If `False` then the scale of the noise             won't be seen as a constant but something to optimize: this will bias the             network to generate vectors with smaller values.      Source:         https://discuss.pytorch.org/t/writing-a-simple-gaussian-noise-layer-in-pytorch/4694/8      Usage:         GaussianNoise()