| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| from torch import Tensor |
| from torch.nn.utils.parametrizations import weight_norm |
|
|
|
|
| def get_eps(data_type): |
| return torch.finfo(data_type).eps |
|
|
|
|
| EPS = get_eps(torch.float32) |
|
|
|
|
| def nn_wrapper(nn_class, norm_weight=True, init_weight=True): |
| def nn_builder(*args, **kwargs): |
| nn_instance = nn_class(*args, **kwargs) |
| if init_weight: |
| nn.init.trunc_normal_(nn_instance.weight, std=0.02) |
| nn.init.constant_(nn_instance.bias, 0) |
| if norm_weight: |
| nn_instance = weight_norm(nn_instance) |
| return nn_instance |
|
|
| return nn_builder |
|
|
|
|
| Conv1d = nn_wrapper(nn.Conv1d, norm_weight=True, init_weight=True) |
| Linear = nn_wrapper(nn.Linear, norm_weight=True, init_weight=True) |
|
|
|
|
| class Residual(nn.Module): |
| def __init__( |
| self, module: nn.Module, drop_prob: float = 0.0, scale_by_keep: bool = True |
| ): |
| super().__init__() |
| assert 0 <= drop_prob < 1 |
| self.module = module |
| self.drop_prob = drop_prob |
| self.scale_by_keep = scale_by_keep |
|
|
| def drop_path(self, x_side: Tensor): |
| if self.drop_prob == 0.0 or not self.training: |
| return x_side |
| keep_prob = 1 - self.drop_prob |
| shape = (x_side.shape[0],) + (1,) * (x_side.ndim - 1) |
| keep_mask = x_side.new_empty(shape).bernoulli_(keep_prob) |
| if self.scale_by_keep: |
| keep_mask.div_(keep_prob) |
| return x_side * keep_mask |
|
|
| def forward(self, x: Tensor): |
| x_side = self.module(x) |
| x_side = self.drop_path(x_side) |
| return x + x_side |
|
|
|
|
| class GRN(nn.Module): |
| """GRN (Global Response Normalization) layer |
| Which supports two data formats: channels_last (default) or channels_first. |
| Channels_last corresponds to inputs with shape (batch_size, Sequence, channels) |
| while channels_first corresponds to inputs with shape (batch_size, channels, Sequence). |
| """ |
|
|
| def __init__(self, n_channels, eps=EPS, data_format="channels_last"): |
| super().__init__() |
| self.n_channels = n_channels |
| self.data_format = data_format |
| if data_format == "channels_last": |
| self.gamma = nn.Parameter(torch.zeros(1, n_channels)) |
| self.beta = nn.Parameter(torch.zeros(1, n_channels)) |
| self.channel_dim = -1 |
| elif data_format == "channels_first": |
| self.gamma = nn.Parameter(torch.zeros(n_channels, 1)) |
| self.beta = nn.Parameter(torch.zeros(n_channels, 1)) |
| self.channel_dim = 1 |
| else: |
| raise ValueError(f"Unsupported data_format: {data_format}") |
| self.eps = torch.tensor(eps) |
|
|
| def forward(self, x): |
| g_x = torch.norm(x, p=2, dim=[1, 2], keepdim=True) |
| n_x = g_x / (g_x.mean(dim=self.channel_dim, keepdim=True) + self.eps) |
| return self.gamma * (x * n_x) + self.beta + x |
|
|
| def __repr__(self): |
| return f"{self.__class__.__name__}(n_channels={self.n_channels}, {self.data_format})" |
|
|
|
|
| |
| @torch.jit.script |
| def snake(x, alpha): |
| |
| eps = 1.1920928955078125e-07 |
| x = x + (alpha + eps).reciprocal() * torch.sin(alpha * x).pow(2) |
| return x |
|
|
|
|
| class Snake1d(nn.Module): |
| def __init__(self, channels, data_format="channels_first"): |
| super().__init__() |
| if data_format == "channels_first": |
| self.alpha = nn.Parameter(torch.ones(1, channels, 1)) |
| elif data_format == "channels_last": |
| self.alpha = nn.Parameter(torch.ones(1, 1, channels)) |
| else: |
| raise NotImplementedError |
|
|
| def forward(self, x): |
| return snake(x, self.alpha) |
|
|
|
|
| @torch.jit.script |
| def channel_norm(x, weight, bias, eps): |
| u = x.mean(1, keepdim=True) |
| s = (x - u).pow(2).mean(1, keepdim=True) |
| x = (x - u) / torch.sqrt(s + eps) |
| x = weight * x + bias |
| return x |
|
|
|
|
| class ChannelNorm(nn.Module): |
| """ChannelNorm that supports two data formats: channels_last (default) or channels_first. |
| Channels_last corresponds to inputs with shape (batch_size, ..., channels) |
| while channels_first corresponds to inputs with shape (batch_size, channels, ...). |
| """ |
|
|
| def __init__(self, n_channels, eps=EPS, data_format="channels_last"): |
| super().__init__() |
| self.n_channels = n_channels |
| self.data_format = data_format |
| self.weight = nn.Parameter(torch.ones(n_channels)) |
| self.bias = nn.Parameter(torch.zeros(n_channels)) |
| self.eps = torch.tensor(eps) |
|
|
| def forward(self, x): |
| if self.data_format == "channels_first": |
| extend_dims = (1,) * len(x.shape[2:]) |
| return channel_norm( |
| x, |
| self.weight.view(-1, *extend_dims), |
| self.bias.view(-1, *extend_dims), |
| self.eps, |
| ) |
|
|
| elif self.data_format == "channels_last": |
| return F.layer_norm( |
| x, (self.n_channels,), self.weight, self.bias, self.eps.item() |
| ) |
|
|
| else: |
| raise NotImplementedError |
|
|
| def __repr__(self): |
| return f"{self.__class__.__name__}(n_channels={self.n_channels}, {self.data_format})" |
|
|