- Bundle VoiceFixer locally to avoid cache downloads - Create voice_fixer_downloader for TTS/voicefixer/ model management - Implement Voice Fixer node with 3 restoration modes (original, high-freq removal, train mode) - Register node in nodes.py with proper error handling - Patch bundled VoiceFixer hardcoded paths to use TTS/voicefixer/ directory - Disable auto-download in restorer/__init__.py, handled by node instead - Support lazy loading and CUDA acceleration - All models download to organized TTS/ folder, never to cache
181 lines
5.2 KiB
Python
181 lines
5.2 KiB
Python
import torch
|
|
import torch.nn as nn
|
|
import numpy as np
|
|
|
|
|
|
def check_cuda_availability(cuda):
|
|
if cuda and not torch.cuda.is_available():
|
|
raise RuntimeError("Error: You set cuda=True but no cuda device found.")
|
|
|
|
|
|
def try_tensor_cuda(tensor, cuda):
|
|
if cuda and torch.cuda.is_available():
|
|
return tensor.cuda()
|
|
else:
|
|
return tensor.cpu()
|
|
|
|
|
|
def to_log(input):
|
|
assert torch.sum(input < 0) == 0, (
|
|
str(input) + " has negative values counts " + str(torch.sum(input < 0))
|
|
)
|
|
return torch.log10(torch.clip(input, min=1e-8))
|
|
|
|
|
|
def from_log(input):
|
|
input = torch.clip(input, min=-np.inf, max=5)
|
|
return 10**input
|
|
|
|
|
|
def move_data_to_device(x, device):
|
|
if "float" in str(x.dtype):
|
|
x = torch.Tensor(x)
|
|
elif "int" in str(x.dtype):
|
|
x = torch.LongTensor(x)
|
|
else:
|
|
return x
|
|
return x.to(device)
|
|
|
|
|
|
def tensor2numpy(tensor):
|
|
if "cuda" in str(tensor.device):
|
|
return tensor.detach().cpu().numpy()
|
|
else:
|
|
return tensor.detach().numpy()
|
|
|
|
|
|
def count_parameters(model):
|
|
for p in model.parameters():
|
|
if p.requires_grad:
|
|
print(p.shape)
|
|
return sum(p.numel() for p in model.parameters() if p.requires_grad)
|
|
|
|
|
|
def count_flops(model, audio_length):
|
|
multiply_adds = False
|
|
list_conv2d = []
|
|
|
|
def conv2d_hook(self, input, output):
|
|
batch_size, input_channels, input_height, input_width = input[0].size()
|
|
output_channels, output_height, output_width = output[0].size()
|
|
|
|
kernel_ops = (
|
|
self.kernel_size[0]
|
|
* self.kernel_size[1]
|
|
* (self.in_channels / self.groups)
|
|
* (2 if multiply_adds else 1)
|
|
)
|
|
bias_ops = 1 if self.bias is not None else 0
|
|
|
|
params = output_channels * (kernel_ops + bias_ops)
|
|
flops = batch_size * params * output_height * output_width
|
|
|
|
list_conv2d.append(flops)
|
|
|
|
list_conv1d = []
|
|
|
|
def conv1d_hook(self, input, output):
|
|
batch_size, input_channels, input_length = input[0].size()
|
|
output_channels, output_length = output[0].size()
|
|
|
|
kernel_ops = (
|
|
self.kernel_size[0]
|
|
* (self.in_channels / self.groups)
|
|
* (2 if multiply_adds else 1)
|
|
)
|
|
bias_ops = 1 if self.bias is not None else 0
|
|
|
|
params = output_channels * (kernel_ops + bias_ops)
|
|
flops = batch_size * params * output_length
|
|
|
|
list_conv1d.append(flops)
|
|
|
|
list_linear = []
|
|
|
|
def linear_hook(self, input, output):
|
|
batch_size = input[0].size(0) if input[0].dim() == 2 else 1
|
|
|
|
weight_ops = self.weight.nelement() * (2 if multiply_adds else 1)
|
|
bias_ops = self.bias.nelement()
|
|
|
|
flops = batch_size * (weight_ops + bias_ops)
|
|
list_linear.append(flops)
|
|
|
|
list_bn = []
|
|
|
|
def bn_hook(self, input, output):
|
|
list_bn.append(input[0].nelement())
|
|
|
|
list_relu = []
|
|
|
|
def relu_hook(self, input, output):
|
|
list_relu.append(input[0].nelement())
|
|
|
|
list_pooling2d = []
|
|
|
|
def pooling2d_hook(self, input, output):
|
|
batch_size, input_channels, input_height, input_width = input[0].size()
|
|
output_channels, output_height, output_width = output[0].size()
|
|
|
|
kernel_ops = self.kernel_size * self.kernel_size
|
|
bias_ops = 0
|
|
params = output_channels * (kernel_ops + bias_ops)
|
|
flops = batch_size * params * output_height * output_width
|
|
|
|
list_pooling2d.append(flops)
|
|
|
|
list_pooling1d = []
|
|
|
|
def pooling1d_hook(self, input, output):
|
|
batch_size, input_channels, input_length = input[0].size()
|
|
output_channels, output_length = output[0].size()
|
|
|
|
kernel_ops = self.kernel_size
|
|
bias_ops = 0
|
|
params = output_channels * (kernel_ops + bias_ops)
|
|
flops = batch_size * params * output_length
|
|
|
|
list_pooling2d.append(flops)
|
|
|
|
def foo(net):
|
|
childrens = list(net.children())
|
|
if not childrens:
|
|
if isinstance(net, nn.Conv2d):
|
|
net.register_forward_hook(conv2d_hook)
|
|
elif isinstance(net, nn.ConvTranspose2d):
|
|
net.register_forward_hook(conv2d_hook)
|
|
elif isinstance(net, nn.Conv1d):
|
|
net.register_forward_hook(conv1d_hook)
|
|
elif isinstance(net, nn.Linear):
|
|
net.register_forward_hook(linear_hook)
|
|
elif isinstance(net, nn.BatchNorm2d) or isinstance(net, nn.BatchNorm1d):
|
|
net.register_forward_hook(bn_hook)
|
|
elif isinstance(net, nn.ReLU):
|
|
net.register_forward_hook(relu_hook)
|
|
elif isinstance(net, nn.AvgPool2d) or isinstance(net, nn.MaxPool2d):
|
|
net.register_forward_hook(pooling2d_hook)
|
|
elif isinstance(net, nn.AvgPool1d) or isinstance(net, nn.MaxPool1d):
|
|
net.register_forward_hook(pooling1d_hook)
|
|
else:
|
|
print("Warning: flop of module {} is not counted!".format(net))
|
|
return
|
|
for c in childrens:
|
|
foo(c)
|
|
|
|
foo(model)
|
|
|
|
input = torch.rand(1, audio_length, 2)
|
|
out = model(input)
|
|
|
|
total_flops = (
|
|
sum(list_conv2d)
|
|
+ sum(list_conv1d)
|
|
+ sum(list_linear)
|
|
+ sum(list_bn)
|
|
+ sum(list_relu)
|
|
+ sum(list_pooling2d)
|
|
+ sum(list_pooling1d)
|
|
)
|
|
|
|
return total_flops
|