CoolFace
Apppublic

Shellbrady/LivePortrait5

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
util.py442 linesDownload Raw Back to modules
1# coding: utf-82 3"""4This file defines various neural network modules and utility functions, including convolutional and residual blocks,5normalizations, and functions for spatial transformation and tensor manipulation.6"""7 8from torch import nn9import torch.nn.functional as F10import torch11import torch.nn.utils.spectral_norm as spectral_norm12import math13import warnings14 15 16def kp2gaussian(kp, spatial_size, kp_variance):17    """18    Transform a keypoint into gaussian like representation19    """20    mean = kp21 22    coordinate_grid = make_coordinate_grid(spatial_size, mean)23    number_of_leading_dimensions = len(mean.shape) - 124    shape = (1,) * number_of_leading_dimensions + coordinate_grid.shape25    coordinate_grid = coordinate_grid.view(*shape)26    repeats = mean.shape[:number_of_leading_dimensions] + (1, 1, 1, 1)27    coordinate_grid = coordinate_grid.repeat(*repeats)28 29    # Preprocess kp shape30    shape = mean.shape[:number_of_leading_dimensions] + (1, 1, 1, 3)31    mean = mean.view(*shape)32 33    mean_sub = (coordinate_grid - mean)34 35    out = torch.exp(-0.5 * (mean_sub ** 2).sum(-1) / kp_variance)36 37    return out38 39 40def make_coordinate_grid(spatial_size, ref, **kwargs):41    d, h, w = spatial_size42    x = torch.arange(w).type(ref.dtype).to(ref.device)43    y = torch.arange(h).type(ref.dtype).to(ref.device)44    z = torch.arange(d).type(ref.dtype).to(ref.device)45 46    # NOTE: must be right-down-in47    x = (2 * (x / (w - 1)) - 1)  # the x axis faces to the right48    y = (2 * (y / (h - 1)) - 1)  # the y axis faces to the bottom49    z = (2 * (z / (d - 1)) - 1)  # the z axis faces to the inner50 51    yy = y.view(1, -1, 1).repeat(d, 1, w)52    xx = x.view(1, 1, -1).repeat(d, h, 1)53    zz = z.view(-1, 1, 1).repeat(1, h, w)54 55    meshed = torch.cat([xx.unsqueeze_(3), yy.unsqueeze_(3), zz.unsqueeze_(3)], 3)56 57    return meshed58 59 60class ConvT2d(nn.Module):61    """62    Upsampling block for use in decoder.63    """64 65    def __init__(self, in_features, out_features, kernel_size=3, stride=2, padding=1, output_padding=1):66        super(ConvT2d, self).__init__()67 68        self.convT = nn.ConvTranspose2d(in_features, out_features, kernel_size=kernel_size, stride=stride,69                                        padding=padding, output_padding=output_padding)70        self.norm = nn.InstanceNorm2d(out_features)71 72    def forward(self, x):73        out = self.convT(x)74        out = self.norm(out)75        out = F.leaky_relu(out)76        return out77 78 79class ResBlock3d(nn.Module):80    """81    Res block, preserve spatial resolution.82    """83 84    def __init__(self, in_features, kernel_size, padding):85        super(ResBlock3d, self).__init__()86        self.conv1 = nn.Conv3d(in_channels=in_features, out_channels=in_features, kernel_size=kernel_size, padding=padding)87        self.conv2 = nn.Conv3d(in_channels=in_features, out_channels=in_features, kernel_size=kernel_size, padding=padding)88        self.norm1 = nn.BatchNorm3d(in_features, affine=True)89        self.norm2 = nn.BatchNorm3d(in_features, affine=True)90 91    def forward(self, x):92        out = self.norm1(x)93        out = F.relu(out)94        out = self.conv1(out)95        out = self.norm2(out)96        out = F.relu(out)97        out = self.conv2(out)98        out += x99        return out100 101 102class UpBlock3d(nn.Module):103    """104    Upsampling block for use in decoder.105    """106 107    def __init__(self, in_features, out_features, kernel_size=3, padding=1, groups=1):108        super(UpBlock3d, self).__init__()109 110        self.conv = nn.Conv3d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size,111                              padding=padding, groups=groups)112        self.norm = nn.BatchNorm3d(out_features, affine=True)113 114    def forward(self, x):115        out = F.interpolate(x, scale_factor=(1, 2, 2))116        out = self.conv(out)117        out = self.norm(out)118        out = F.relu(out)119        return out120 121 122class DownBlock2d(nn.Module):123    """124    Downsampling block for use in encoder.125    """126 127    def __init__(self, in_features, out_features, kernel_size=3, padding=1, groups=1):128        super(DownBlock2d, self).__init__()129        self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size, padding=padding, groups=groups)130        self.norm = nn.BatchNorm2d(out_features, affine=True)131        self.pool = nn.AvgPool2d(kernel_size=(2, 2))132 133    def forward(self, x):134        out = self.conv(x)135        out = self.norm(out)136        out = F.relu(out)137        out = self.pool(out)138        return out139 140 141class DownBlock3d(nn.Module):142    """143    Downsampling block for use in encoder.144    """145 146    def __init__(self, in_features, out_features, kernel_size=3, padding=1, groups=1):147        super(DownBlock3d, self).__init__()148        '''149        self.conv = nn.Conv3d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size,150                                padding=padding, groups=groups, stride=(1, 2, 2))151        '''152        self.conv = nn.Conv3d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size,153                              padding=padding, groups=groups)154        self.norm = nn.BatchNorm3d(out_features, affine=True)155        self.pool = nn.AvgPool3d(kernel_size=(1, 2, 2))156 157    def forward(self, x):158        out = self.conv(x)159        out = self.norm(out)160        out = F.relu(out)161        out = self.pool(out)162        return out163 164 165class SameBlock2d(nn.Module):166    """167    Simple block, preserve spatial resolution.168    """169 170    def __init__(self, in_features, out_features, groups=1, kernel_size=3, padding=1, lrelu=False):171        super(SameBlock2d, self).__init__()172        self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size, padding=padding, groups=groups)173        self.norm = nn.BatchNorm2d(out_features, affine=True)174        if lrelu:175            self.ac = nn.LeakyReLU()176        else:177            self.ac = nn.ReLU()178 179    def forward(self, x):180        out = self.conv(x)181        out = self.norm(out)182        out = self.ac(out)183        return out184 185 186class Encoder(nn.Module):187    """188    Hourglass Encoder189    """190 191    def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):192        super(Encoder, self).__init__()193 194        down_blocks = []195        for i in range(num_blocks):196            down_blocks.append(DownBlock3d(in_features if i == 0 else min(max_features, block_expansion * (2 ** i)), min(max_features, block_expansion * (2 ** (i + 1))), kernel_size=3, padding=1))197        self.down_blocks = nn.ModuleList(down_blocks)198 199    def forward(self, x):200        outs = [x]201        for down_block in self.down_blocks:202            outs.append(down_block(outs[-1]))203        return outs204 205 206class Decoder(nn.Module):207    """208    Hourglass Decoder209    """210 211    def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):212        super(Decoder, self).__init__()213 214        up_blocks = []215 216        for i in range(num_blocks)[::-1]:217            in_filters = (1 if i == num_blocks - 1 else 2) * min(max_features, block_expansion * (2 ** (i + 1)))218            out_filters = min(max_features, block_expansion * (2 ** i))219            up_blocks.append(UpBlock3d(in_filters, out_filters, kernel_size=3, padding=1))220 221        self.up_blocks = nn.ModuleList(up_blocks)222        self.out_filters = block_expansion + in_features223 224        self.conv = nn.Conv3d(in_channels=self.out_filters, out_channels=self.out_filters, kernel_size=3, padding=1)225        self.norm = nn.BatchNorm3d(self.out_filters, affine=True)226 227    def forward(self, x):228        out = x.pop()229        for up_block in self.up_blocks:230            out = up_block(out)231            skip = x.pop()232            out = torch.cat([out, skip], dim=1)233        out = self.conv(out)234        out = self.norm(out)235        out = F.relu(out)236        return out237 238 239class Hourglass(nn.Module):240    """241    Hourglass architecture.242    """243 244    def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):245        super(Hourglass, self).__init__()246        self.encoder = Encoder(block_expansion, in_features, num_blocks, max_features)247        self.decoder = Decoder(block_expansion, in_features, num_blocks, max_features)248        self.out_filters = self.decoder.out_filters249 250    def forward(self, x):251        return self.decoder(self.encoder(x))252 253 254class SPADE(nn.Module):255    def __init__(self, norm_nc, label_nc):256        super().__init__()257 258        self.param_free_norm = nn.InstanceNorm2d(norm_nc, affine=False)259        nhidden = 128260 261        self.mlp_shared = nn.Sequential(262            nn.Conv2d(label_nc, nhidden, kernel_size=3, padding=1),263            nn.ReLU())264        self.mlp_gamma = nn.Conv2d(nhidden, norm_nc, kernel_size=3, padding=1)265        self.mlp_beta = nn.Conv2d(nhidden, norm_nc, kernel_size=3, padding=1)266 267    def forward(self, x, segmap):268        normalized = self.param_free_norm(x)269        segmap = F.interpolate(segmap, size=x.size()[2:], mode='nearest')270        actv = self.mlp_shared(segmap)271        gamma = self.mlp_gamma(actv)272        beta = self.mlp_beta(actv)273        out = normalized * (1 + gamma) + beta274        return out275 276 277class SPADEResnetBlock(nn.Module):278    def __init__(self, fin, fout, norm_G, label_nc, use_se=False, dilation=1):279        super().__init__()280        # Attributes281        self.learned_shortcut = (fin != fout)282        fmiddle = min(fin, fout)283        self.use_se = use_se284        # create conv layers285        self.conv_0 = nn.Conv2d(fin, fmiddle, kernel_size=3, padding=dilation, dilation=dilation)286        self.conv_1 = nn.Conv2d(fmiddle, fout, kernel_size=3, padding=dilation, dilation=dilation)287        if self.learned_shortcut:288            self.conv_s = nn.Conv2d(fin, fout, kernel_size=1, bias=False)289        # apply spectral norm if specified290        if 'spectral' in norm_G:291            self.conv_0 = spectral_norm(self.conv_0)292            self.conv_1 = spectral_norm(self.conv_1)293            if self.learned_shortcut:294                self.conv_s = spectral_norm(self.conv_s)295        # define normalization layers296        self.norm_0 = SPADE(fin, label_nc)297        self.norm_1 = SPADE(fmiddle, label_nc)298        if self.learned_shortcut:299            self.norm_s = SPADE(fin, label_nc)300 301    def forward(self, x, seg1):302        x_s = self.shortcut(x, seg1)303        dx = self.conv_0(self.actvn(self.norm_0(x, seg1)))304        dx = self.conv_1(self.actvn(self.norm_1(dx, seg1)))305        out = x_s + dx306        return out307 308    def shortcut(self, x, seg1):309        if self.learned_shortcut:310            x_s = self.conv_s(self.norm_s(x, seg1))311        else:312            x_s = x313        return x_s314 315    def actvn(self, x):316        return F.leaky_relu(x, 2e-1)317 318 319def filter_state_dict(state_dict, remove_name='fc'):320    new_state_dict = {}321    for key in state_dict:322        if remove_name in key:323            continue324        new_state_dict[key] = state_dict[key]325    return new_state_dict326 327 328class GRN(nn.Module):329    """ GRN (Global Response Normalization) layer330    """331 332    def __init__(self, dim):333        super().__init__()334        self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))335        self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))336 337    def forward(self, x):338        Gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)339        Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)340        return self.gamma * (x * Nx) + self.beta + x341 342 343class LayerNorm(nn.Module):344    r""" LayerNorm that supports two data formats: channels_last (default) or channels_first.345    The ordering of the dimensions in the inputs. channels_last corresponds to inputs with346    shape (batch_size, height, width, channels) while channels_first corresponds to inputs347    with shape (batch_size, channels, height, width).348    """349 350    def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"):351        super().__init__()352        self.weight = nn.Parameter(torch.ones(normalized_shape))353        self.bias = nn.Parameter(torch.zeros(normalized_shape))354        self.eps = eps355        self.data_format = data_format356        if self.data_format not in ["channels_last", "channels_first"]:357            raise NotImplementedError358        self.normalized_shape = (normalized_shape, )359 360    def forward(self, x):361        if self.data_format == "channels_last":362            return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)363        elif self.data_format == "channels_first":364            u = x.mean(1, keepdim=True)365            s = (x - u).pow(2).mean(1, keepdim=True)366            x = (x - u) / torch.sqrt(s + self.eps)367            x = self.weight[:, None, None] * x + self.bias[:, None, None]368            return x369 370 371def _no_grad_trunc_normal_(tensor, mean, std, a, b):372    # Cut & paste from PyTorch official master until it's in a few official releases - RW373    # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf374    def norm_cdf(x):375        # Computes standard normal cumulative distribution function376        return (1. + math.erf(x / math.sqrt(2.))) / 2.377 378    if (mean < a - 2 * std) or (mean > b + 2 * std):379        warnings.warn("mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "380                      "The distribution of values may be incorrect.",381                      stacklevel=2)382 383    with torch.no_grad():384        # Values are generated by using a truncated uniform distribution and385        # then using the inverse CDF for the normal distribution.386        # Get upper and lower cdf values387        l = norm_cdf((a - mean) / std)388        u = norm_cdf((b - mean) / std)389 390        # Uniformly fill tensor with values from [l, u], then translate to391        # [2l-1, 2u-1].392        tensor.uniform_(2 * l - 1, 2 * u - 1)393 394        # Use inverse cdf transform for normal distribution to get truncated395        # standard normal396        tensor.erfinv_()397 398        # Transform to proper mean, std399        tensor.mul_(std * math.sqrt(2.))400        tensor.add_(mean)401 402        # Clamp to ensure it's in the proper range403        tensor.clamp_(min=a, max=b)404        return tensor405 406 407def drop_path(x, drop_prob=0., training=False, scale_by_keep=True):408    """ Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).409 410    This is the same as the DropConnect impl I created for EfficientNet, etc networks, however,411    the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...412    See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for413    changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use414    'survival rate' as the argument.415 416    """417    if drop_prob == 0. or not training:418        return x419    keep_prob = 1 - drop_prob420    shape = (x.shape[0],) + (1,) * (x.ndim - 1)  # work with diff dim tensors, not just 2D ConvNets421    random_tensor = x.new_empty(shape).bernoulli_(keep_prob)422    if keep_prob > 0.0 and scale_by_keep:423        random_tensor.div_(keep_prob)424    return x * random_tensor425 426 427class DropPath(nn.Module):428    """ Drop paths (Stochastic Depth) per sample  (when applied in main path of residual blocks).429    """430 431    def __init__(self, drop_prob=None, scale_by_keep=True):432        super(DropPath, self).__init__()433        self.drop_prob = drop_prob434        self.scale_by_keep = scale_by_keep435 436    def forward(self, x):437        return drop_path(x, self.drop_prob, self.training, self.scale_by_keep)438 439 440def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):441    return _no_grad_trunc_normal_(tensor, mean, std, a, b)442