Spaces:
Running on Zero
Running on Zero
For music on the Las Vegas beef
#3
by Ivanct702 - opened
This view is limited to 50 files because it contains too many changes. See the raw diff here.
- .gitignore +1 -4
- README.md +1 -2
- app.py +5 -3
- requirements.txt +1 -17
- resemble_enhance/__init__.py +0 -0
- resemble_enhance/common.py +0 -55
- resemble_enhance/data/__init__.py +0 -48
- resemble_enhance/data/dataset.py +0 -171
- resemble_enhance/data/distorter/__init__.py +0 -1
- resemble_enhance/data/distorter/base.py +0 -104
- resemble_enhance/data/distorter/custom.py +0 -85
- resemble_enhance/data/distorter/distorter.py +0 -32
- resemble_enhance/data/distorter/sox.py +0 -176
- resemble_enhance/data/utils.py +0 -43
- resemble_enhance/denoiser/__init__.py +0 -0
- resemble_enhance/denoiser/__main__.py +0 -30
- resemble_enhance/denoiser/denoiser.py +0 -181
- resemble_enhance/denoiser/hparams.py +0 -9
- resemble_enhance/denoiser/inference.py +0 -30
- resemble_enhance/denoiser/train.py +0 -112
- resemble_enhance/denoiser/unet.py +0 -144
- resemble_enhance/enhancer/__init__.py +0 -0
- resemble_enhance/enhancer/__main__.py +0 -123
- resemble_enhance/enhancer/download.py +0 -44
- resemble_enhance/enhancer/enhancer.py +0 -177
- resemble_enhance/enhancer/hparams.py +0 -23
- resemble_enhance/enhancer/inference.py +0 -42
- resemble_enhance/enhancer/lcfm/__init__.py +0 -2
- resemble_enhance/enhancer/lcfm/cfm.py +0 -372
- resemble_enhance/enhancer/lcfm/irmae.py +0 -123
- resemble_enhance/enhancer/lcfm/lcfm.py +0 -152
- resemble_enhance/enhancer/lcfm/wn.py +0 -147
- resemble_enhance/enhancer/train.py +0 -143
- resemble_enhance/enhancer/univnet/__init__.py +0 -1
- resemble_enhance/enhancer/univnet/alias_free_torch/__init__.py +0 -5
- resemble_enhance/enhancer/univnet/alias_free_torch/filter.py +0 -95
- resemble_enhance/enhancer/univnet/alias_free_torch/resample.py +0 -49
- resemble_enhance/enhancer/univnet/amp.py +0 -101
- resemble_enhance/enhancer/univnet/discriminator.py +0 -210
- resemble_enhance/enhancer/univnet/lvcnet.py +0 -281
- resemble_enhance/enhancer/univnet/mrstft.py +0 -128
- resemble_enhance/enhancer/univnet/univnet.py +0 -94
- resemble_enhance/hparams.py +0 -128
- resemble_enhance/inference.py +0 -163
- resemble_enhance/melspec.py +0 -61
- resemble_enhance/utils/__init__.py +0 -5
- resemble_enhance/utils/control.py +0 -26
- resemble_enhance/utils/distributed.py +0 -96
- resemble_enhance/utils/engine.py +0 -145
- resemble_enhance/utils/logging.py +0 -38
.gitignore
CHANGED
|
@@ -5,8 +5,5 @@
|
|
| 5 |
/build
|
| 6 |
/*.egg-info
|
| 7 |
/flagged
|
| 8 |
-
|
| 9 |
__pycache__
|
| 10 |
-
*.py[cod]
|
| 11 |
-
/.cache
|
| 12 |
-
/resemble_enhance/model_repo
|
|
|
|
| 5 |
/build
|
| 6 |
/*.egg-info
|
| 7 |
/flagged
|
| 8 |
+
version.py
|
| 9 |
__pycache__
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -4,8 +4,7 @@ emoji: 🚀
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: pink
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: "3.10"
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
license: mit
|
|
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: pink
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 4.8.0
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: mit
|
app.py
CHANGED
|
@@ -2,14 +2,17 @@ import argparse
|
|
| 2 |
from functools import partial
|
| 3 |
|
| 4 |
import gradio as gr
|
| 5 |
-
import spaces
|
| 6 |
import torch
|
| 7 |
import torchaudio
|
| 8 |
|
| 9 |
from resemble_enhance.enhancer.inference import denoise, enhance
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
@spaces.GPU(duration=300)
|
| 13 |
def _fn(path, solver, nfe, tau, denoising, unlimited):
|
| 14 |
if path is None:
|
| 15 |
gr.Warning("Please upload an audio file.")
|
|
@@ -27,7 +30,6 @@ def _fn(path, solver, nfe, tau, denoising, unlimited):
|
|
| 27 |
dwav, sr = torchaudio.load(path)
|
| 28 |
dwav = dwav.mean(dim=0)
|
| 29 |
|
| 30 |
-
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 31 |
wav1, new_sr = denoise(dwav, sr, device)
|
| 32 |
wav2, new_sr = enhance(dwav, sr, device, nfe=nfe, solver=solver, lambd=lambd, tau=tau)
|
| 33 |
|
|
|
|
| 2 |
from functools import partial
|
| 3 |
|
| 4 |
import gradio as gr
|
|
|
|
| 5 |
import torch
|
| 6 |
import torchaudio
|
| 7 |
|
| 8 |
from resemble_enhance.enhancer.inference import denoise, enhance
|
| 9 |
|
| 10 |
+
if torch.cuda.is_available():
|
| 11 |
+
device = "cuda"
|
| 12 |
+
else:
|
| 13 |
+
device = "cpu"
|
| 14 |
+
|
| 15 |
|
|
|
|
| 16 |
def _fn(path, solver, nfe, tau, denoising, unlimited):
|
| 17 |
if path is None:
|
| 18 |
gr.Warning("Please upload an audio file.")
|
|
|
|
| 30 |
dwav, sr = torchaudio.load(path)
|
| 31 |
dwav = dwav.mean(dim=0)
|
| 32 |
|
|
|
|
| 33 |
wav1, new_sr = denoise(dwav, sr, device)
|
| 34 |
wav2, new_sr = enhance(dwav, sr, device, nfe=nfe, solver=solver, lambd=lambd, tau=tau)
|
| 35 |
|
requirements.txt
CHANGED
|
@@ -1,17 +1 @@
|
|
| 1 |
-
|
| 2 |
-
librosa==0.10.1
|
| 3 |
-
matplotlib==3.8.1
|
| 4 |
-
numpy==1.26.2
|
| 5 |
-
omegaconf==2.3.0
|
| 6 |
-
pandas==2.1.3
|
| 7 |
-
ptflops==0.7.1.2
|
| 8 |
-
rich==13.7.0
|
| 9 |
-
scipy==1.11.4
|
| 10 |
-
soundfile==0.12.1
|
| 11 |
-
spaces==0.50.4
|
| 12 |
-
torch==2.8.0
|
| 13 |
-
torchaudio==2.8.0
|
| 14 |
-
torchvision==0.23.0
|
| 15 |
-
tqdm==4.66.1
|
| 16 |
-
resampy==0.4.2
|
| 17 |
-
tabulate==0.8.10
|
|
|
|
| 1 |
+
resemble-enhance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/__init__.py
DELETED
|
File without changes
|
resemble_enhance/common.py
DELETED
|
@@ -1,55 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
from torch import Tensor, nn
|
| 5 |
-
|
| 6 |
-
logger = logging.getLogger(__name__)
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
class Normalizer(nn.Module):
|
| 10 |
-
def __init__(self, momentum=0.01, eps=1e-9):
|
| 11 |
-
super().__init__()
|
| 12 |
-
self.momentum = momentum
|
| 13 |
-
self.eps = eps
|
| 14 |
-
self.running_mean_unsafe: Tensor
|
| 15 |
-
self.running_var_unsafe: Tensor
|
| 16 |
-
self.register_buffer("running_mean_unsafe", torch.full([], torch.nan))
|
| 17 |
-
self.register_buffer("running_var_unsafe", torch.full([], torch.nan))
|
| 18 |
-
|
| 19 |
-
@property
|
| 20 |
-
def started(self):
|
| 21 |
-
return not torch.isnan(self.running_mean_unsafe)
|
| 22 |
-
|
| 23 |
-
@property
|
| 24 |
-
def running_mean(self):
|
| 25 |
-
if not self.started:
|
| 26 |
-
return torch.zeros_like(self.running_mean_unsafe)
|
| 27 |
-
return self.running_mean_unsafe
|
| 28 |
-
|
| 29 |
-
@property
|
| 30 |
-
def running_std(self):
|
| 31 |
-
if not self.started:
|
| 32 |
-
return torch.ones_like(self.running_var_unsafe)
|
| 33 |
-
return (self.running_var_unsafe + self.eps).sqrt()
|
| 34 |
-
|
| 35 |
-
@torch.no_grad()
|
| 36 |
-
def _ema(self, a: Tensor, x: Tensor):
|
| 37 |
-
return (1 - self.momentum) * a + self.momentum * x
|
| 38 |
-
|
| 39 |
-
def update_(self, x):
|
| 40 |
-
if not self.started:
|
| 41 |
-
self.running_mean_unsafe = x.mean()
|
| 42 |
-
self.running_var_unsafe = x.var()
|
| 43 |
-
else:
|
| 44 |
-
self.running_mean_unsafe = self._ema(self.running_mean_unsafe, x.mean())
|
| 45 |
-
self.running_var_unsafe = self._ema(self.running_var_unsafe, (x - self.running_mean).pow(2).mean())
|
| 46 |
-
|
| 47 |
-
def forward(self, x: Tensor, update=True):
|
| 48 |
-
if self.training and update:
|
| 49 |
-
self.update_(x)
|
| 50 |
-
self.stats = dict(mean=self.running_mean.item(), std=self.running_std.item())
|
| 51 |
-
x = (x - self.running_mean) / self.running_std
|
| 52 |
-
return x
|
| 53 |
-
|
| 54 |
-
def inverse(self, x: Tensor):
|
| 55 |
-
return x * self.running_std + self.running_mean
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/__init__.py
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import random
|
| 3 |
-
|
| 4 |
-
from torch.utils.data import DataLoader
|
| 5 |
-
|
| 6 |
-
from ..hparams import HParams
|
| 7 |
-
from .dataset import Dataset
|
| 8 |
-
from .utils import mix_fg_bg, rglob_audio_files
|
| 9 |
-
|
| 10 |
-
logger = logging.getLogger(__name__)
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def _create_datasets(hp: HParams, mode, val_size=10, seed=123):
|
| 14 |
-
paths = rglob_audio_files(hp.fg_dir)
|
| 15 |
-
logger.info(f"Found {len(paths)} audio files in {hp.fg_dir}")
|
| 16 |
-
|
| 17 |
-
random.Random(seed).shuffle(paths)
|
| 18 |
-
train_paths = paths[:-val_size]
|
| 19 |
-
val_paths = paths[-val_size:]
|
| 20 |
-
|
| 21 |
-
train_ds = Dataset(train_paths, hp, training=True, mode=mode)
|
| 22 |
-
val_ds = Dataset(val_paths, hp, training=False, mode=mode)
|
| 23 |
-
|
| 24 |
-
logger.info(f"Train set: {len(train_ds)} samples - Val set: {len(val_ds)} samples")
|
| 25 |
-
|
| 26 |
-
return train_ds, val_ds
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
def create_dataloaders(hp: HParams, mode):
|
| 30 |
-
train_ds, val_ds = _create_datasets(hp=hp, mode=mode)
|
| 31 |
-
|
| 32 |
-
train_dl = DataLoader(
|
| 33 |
-
train_ds,
|
| 34 |
-
batch_size=hp.batch_size_per_gpu,
|
| 35 |
-
shuffle=True,
|
| 36 |
-
num_workers=hp.nj,
|
| 37 |
-
drop_last=True,
|
| 38 |
-
collate_fn=train_ds.collate_fn,
|
| 39 |
-
)
|
| 40 |
-
val_dl = DataLoader(
|
| 41 |
-
val_ds,
|
| 42 |
-
batch_size=1,
|
| 43 |
-
shuffle=False,
|
| 44 |
-
num_workers=hp.nj,
|
| 45 |
-
drop_last=False,
|
| 46 |
-
collate_fn=val_ds.collate_fn,
|
| 47 |
-
)
|
| 48 |
-
return train_dl, val_dl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/dataset.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import random
|
| 3 |
-
from pathlib import Path
|
| 4 |
-
|
| 5 |
-
import numpy as np
|
| 6 |
-
import torch
|
| 7 |
-
import torchaudio
|
| 8 |
-
import torchaudio.functional as AF
|
| 9 |
-
from torch.nn.utils.rnn import pad_sequence
|
| 10 |
-
from torch.utils.data import Dataset as DatasetBase
|
| 11 |
-
|
| 12 |
-
from ..hparams import HParams
|
| 13 |
-
from .distorter import Distorter
|
| 14 |
-
from .utils import rglob_audio_files
|
| 15 |
-
|
| 16 |
-
logger = logging.getLogger(__name__)
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def _normalize(x):
|
| 20 |
-
return x / (np.abs(x).max() + 1e-7)
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def _collate(batch, key, tensor=True, pad=True):
|
| 24 |
-
l = [d[key] for d in batch]
|
| 25 |
-
if l[0] is None:
|
| 26 |
-
return None
|
| 27 |
-
if tensor:
|
| 28 |
-
l = [torch.from_numpy(x) for x in l]
|
| 29 |
-
if pad:
|
| 30 |
-
assert tensor, "Can't pad non-tensor"
|
| 31 |
-
l = pad_sequence(l, batch_first=True)
|
| 32 |
-
return l
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
def praat_augment(wav, sr):
|
| 36 |
-
try:
|
| 37 |
-
import parselmouth
|
| 38 |
-
except ImportError:
|
| 39 |
-
raise ImportError("Please install parselmouth>=0.5.0 to use Praat augmentation")
|
| 40 |
-
# "praat-parselmouth @ git+https://github.com/YannickJadoul/Parselmouth@0bbcca69705ed73322f3712b19d71bb3694b2540",
|
| 41 |
-
# https://github.com/YannickJadoul/Parselmouth/issues/68
|
| 42 |
-
# note that this function may hang if the praat version is 0.4.3
|
| 43 |
-
assert wav.ndim == 1, f"wav.ndim must be 1 but got {wav.ndim}"
|
| 44 |
-
sound = parselmouth.Sound(wav, sr)
|
| 45 |
-
formant_shift_ratio = random.uniform(1.1, 1.5)
|
| 46 |
-
pitch_range_factor = random.uniform(0.5, 2.0)
|
| 47 |
-
sound = parselmouth.praat.call(sound, "Change gender", 75, 600, formant_shift_ratio, 0, pitch_range_factor, 1.0)
|
| 48 |
-
wav = np.array(sound.values)[0].astype(np.float32)
|
| 49 |
-
return wav
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
class Dataset(DatasetBase):
|
| 53 |
-
def __init__(
|
| 54 |
-
self,
|
| 55 |
-
fg_paths: list[Path],
|
| 56 |
-
hp: HParams,
|
| 57 |
-
training=True,
|
| 58 |
-
max_retries=100,
|
| 59 |
-
silent_fg_prob=0.01,
|
| 60 |
-
mode=False,
|
| 61 |
-
):
|
| 62 |
-
super().__init__()
|
| 63 |
-
|
| 64 |
-
assert mode in ("enhancer", "denoiser"), f"Invalid mode: {mode}"
|
| 65 |
-
|
| 66 |
-
self.hp = hp
|
| 67 |
-
self.fg_paths = fg_paths
|
| 68 |
-
self.bg_paths = rglob_audio_files(hp.bg_dir)
|
| 69 |
-
|
| 70 |
-
if len(self.fg_paths) == 0:
|
| 71 |
-
raise ValueError(f"No foreground audio files found in {hp.fg_dir}")
|
| 72 |
-
|
| 73 |
-
if len(self.bg_paths) == 0:
|
| 74 |
-
raise ValueError(f"No background audio files found in {hp.bg_dir}")
|
| 75 |
-
|
| 76 |
-
logger.info(f"Found {len(self.fg_paths)} foreground files and {len(self.bg_paths)} background files")
|
| 77 |
-
|
| 78 |
-
self.training = training
|
| 79 |
-
self.max_retries = max_retries
|
| 80 |
-
self.silent_fg_prob = silent_fg_prob
|
| 81 |
-
|
| 82 |
-
self.mode = mode
|
| 83 |
-
self.distorter = Distorter(hp, training=training, mode=mode)
|
| 84 |
-
|
| 85 |
-
def _load_wav(self, path, length=None, random_crop=True):
|
| 86 |
-
wav, sr = torchaudio.load(path)
|
| 87 |
-
|
| 88 |
-
wav = AF.resample(
|
| 89 |
-
waveform=wav,
|
| 90 |
-
orig_freq=sr,
|
| 91 |
-
new_freq=self.hp.wav_rate,
|
| 92 |
-
lowpass_filter_width=64,
|
| 93 |
-
rolloff=0.9475937167399596,
|
| 94 |
-
resampling_method="sinc_interp_kaiser",
|
| 95 |
-
beta=14.769656459379492,
|
| 96 |
-
)
|
| 97 |
-
|
| 98 |
-
wav = wav.float().numpy()
|
| 99 |
-
|
| 100 |
-
if wav.ndim == 2:
|
| 101 |
-
wav = np.mean(wav, axis=0)
|
| 102 |
-
|
| 103 |
-
if length is None and self.training:
|
| 104 |
-
length = int(self.hp.training_seconds * self.hp.wav_rate)
|
| 105 |
-
|
| 106 |
-
if length is not None:
|
| 107 |
-
if random_crop:
|
| 108 |
-
start = random.randint(0, max(0, len(wav) - length))
|
| 109 |
-
wav = wav[start : start + length]
|
| 110 |
-
else:
|
| 111 |
-
wav = wav[:length]
|
| 112 |
-
|
| 113 |
-
if length is not None and len(wav) < length:
|
| 114 |
-
wav = np.pad(wav, (0, length - len(wav)))
|
| 115 |
-
|
| 116 |
-
wav = _normalize(wav)
|
| 117 |
-
|
| 118 |
-
return wav
|
| 119 |
-
|
| 120 |
-
def _getitem_unsafe(self, index: int):
|
| 121 |
-
fg_path = self.fg_paths[index]
|
| 122 |
-
|
| 123 |
-
if self.training and random.random() < self.silent_fg_prob:
|
| 124 |
-
fg_wav = np.zeros(int(self.hp.training_seconds * self.hp.wav_rate), dtype=np.float32)
|
| 125 |
-
else:
|
| 126 |
-
fg_wav = self._load_wav(fg_path)
|
| 127 |
-
if random.random() < self.hp.praat_augment_prob and self.training:
|
| 128 |
-
fg_wav = praat_augment(fg_wav, self.hp.wav_rate)
|
| 129 |
-
|
| 130 |
-
if self.hp.load_fg_only:
|
| 131 |
-
bg_wav = None
|
| 132 |
-
fg_dwav = None
|
| 133 |
-
bg_dwav = None
|
| 134 |
-
else:
|
| 135 |
-
fg_dwav = _normalize(self.distorter(fg_wav, self.hp.wav_rate)).astype(np.float32)
|
| 136 |
-
if self.training:
|
| 137 |
-
bg_path = random.choice(self.bg_paths)
|
| 138 |
-
else:
|
| 139 |
-
# Deterministic for validation
|
| 140 |
-
bg_path = self.bg_paths[index % len(self.bg_paths)]
|
| 141 |
-
bg_wav = self._load_wav(bg_path, length=len(fg_wav), random_crop=self.training)
|
| 142 |
-
bg_dwav = _normalize(self.distorter(bg_wav, self.hp.wav_rate)).astype(np.float32)
|
| 143 |
-
|
| 144 |
-
return dict(
|
| 145 |
-
fg_wav=fg_wav,
|
| 146 |
-
bg_wav=bg_wav,
|
| 147 |
-
fg_dwav=fg_dwav,
|
| 148 |
-
bg_dwav=bg_dwav,
|
| 149 |
-
)
|
| 150 |
-
|
| 151 |
-
def __getitem__(self, index: int):
|
| 152 |
-
for i in range(self.max_retries):
|
| 153 |
-
try:
|
| 154 |
-
return self._getitem_unsafe(index)
|
| 155 |
-
except Exception as e:
|
| 156 |
-
if i == self.max_retries - 1:
|
| 157 |
-
raise RuntimeError(f"Failed to load {self.fg_paths[index]} after {self.max_retries} retries") from e
|
| 158 |
-
logger.debug(f"Error loading {self.fg_paths[index]}: {e}, skipping")
|
| 159 |
-
index = np.random.randint(0, len(self))
|
| 160 |
-
|
| 161 |
-
def __len__(self):
|
| 162 |
-
return len(self.fg_paths)
|
| 163 |
-
|
| 164 |
-
@staticmethod
|
| 165 |
-
def collate_fn(batch):
|
| 166 |
-
return dict(
|
| 167 |
-
fg_wavs=_collate(batch, "fg_wav"),
|
| 168 |
-
bg_wavs=_collate(batch, "bg_wav"),
|
| 169 |
-
fg_dwavs=_collate(batch, "fg_dwav"),
|
| 170 |
-
bg_dwavs=_collate(batch, "bg_dwav"),
|
| 171 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/distorter/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
from .distorter import Distorter
|
|
|
|
|
|
resemble_enhance/data/distorter/base.py
DELETED
|
@@ -1,104 +0,0 @@
|
|
| 1 |
-
import itertools
|
| 2 |
-
import os
|
| 3 |
-
import random
|
| 4 |
-
import time
|
| 5 |
-
import warnings
|
| 6 |
-
|
| 7 |
-
import numpy as np
|
| 8 |
-
|
| 9 |
-
_DEBUG = bool(os.environ.get("DEBUG", False))
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
class Effect:
|
| 13 |
-
def apply(self, wav: np.ndarray, sr: int):
|
| 14 |
-
"""
|
| 15 |
-
Args:
|
| 16 |
-
wav: (T)
|
| 17 |
-
sr: sample rate
|
| 18 |
-
Returns:
|
| 19 |
-
wav: (T) with the same sample rate of `sr`
|
| 20 |
-
"""
|
| 21 |
-
raise NotImplementedError
|
| 22 |
-
|
| 23 |
-
def __call__(self, wav: np.ndarray, sr: int):
|
| 24 |
-
"""
|
| 25 |
-
Args:
|
| 26 |
-
wav: (T)
|
| 27 |
-
sr: sample rate
|
| 28 |
-
Returns:
|
| 29 |
-
wav: (T) with the same sample rate of `sr`
|
| 30 |
-
"""
|
| 31 |
-
assert len(wav.shape) == 1, wav.shape
|
| 32 |
-
|
| 33 |
-
if _DEBUG:
|
| 34 |
-
start = time.time()
|
| 35 |
-
else:
|
| 36 |
-
start = None
|
| 37 |
-
|
| 38 |
-
shape = wav.shape
|
| 39 |
-
assert wav.ndim == 1, f"{self}: Expected wav.ndim == 1, got {wav.ndim}."
|
| 40 |
-
wav = self.apply(wav, sr)
|
| 41 |
-
assert shape == wav.shape, f"{self}: {shape} != {wav.shape}."
|
| 42 |
-
|
| 43 |
-
if start is not None:
|
| 44 |
-
end = time.time()
|
| 45 |
-
print(f"{self.__class__.__name__}: {end - start:.3f} sec")
|
| 46 |
-
|
| 47 |
-
return wav
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
class Chain(Effect):
|
| 51 |
-
def __init__(self, *effects):
|
| 52 |
-
super().__init__()
|
| 53 |
-
|
| 54 |
-
self.effects = effects
|
| 55 |
-
|
| 56 |
-
def apply(self, wav, sr):
|
| 57 |
-
for effect in self.effects:
|
| 58 |
-
wav = effect(wav, sr)
|
| 59 |
-
return wav
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
class Maybe(Effect):
|
| 63 |
-
def __init__(self, prob, effect):
|
| 64 |
-
super().__init__()
|
| 65 |
-
|
| 66 |
-
self.prob = prob
|
| 67 |
-
self.effect = effect
|
| 68 |
-
|
| 69 |
-
if _DEBUG:
|
| 70 |
-
warnings.warn("DEBUG mode is on. Maybe -> Must.")
|
| 71 |
-
self.prob = 1
|
| 72 |
-
|
| 73 |
-
def apply(self, wav, sr):
|
| 74 |
-
if random.random() > self.prob:
|
| 75 |
-
return wav
|
| 76 |
-
return self.effect(wav, sr)
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
class Choice(Effect):
|
| 80 |
-
def __init__(self, *effects, **kwargs):
|
| 81 |
-
super().__init__()
|
| 82 |
-
self.effects = effects
|
| 83 |
-
self.kwargs = kwargs
|
| 84 |
-
|
| 85 |
-
def apply(self, wav, sr):
|
| 86 |
-
return np.random.choice(self.effects, **self.kwargs)(wav, sr)
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
class Permutation(Effect):
|
| 90 |
-
def __init__(self, *effects, n: int | None = None):
|
| 91 |
-
super().__init__()
|
| 92 |
-
self.effects = effects
|
| 93 |
-
self.n = n
|
| 94 |
-
|
| 95 |
-
def apply(self, wav, sr):
|
| 96 |
-
if self.n is None:
|
| 97 |
-
n = np.random.binomial(len(self.effects), 0.5)
|
| 98 |
-
else:
|
| 99 |
-
n = self.n
|
| 100 |
-
if n == 0:
|
| 101 |
-
return wav
|
| 102 |
-
perms = itertools.permutations(self.effects, n)
|
| 103 |
-
effects = random.choice(list(perms))
|
| 104 |
-
return Chain(*effects)(wav, sr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/distorter/custom.py
DELETED
|
@@ -1,85 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import random
|
| 3 |
-
from dataclasses import dataclass
|
| 4 |
-
from functools import cached_property
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
|
| 7 |
-
import librosa
|
| 8 |
-
import numpy as np
|
| 9 |
-
from scipy import signal
|
| 10 |
-
|
| 11 |
-
from ..utils import walk_paths
|
| 12 |
-
from .base import Effect
|
| 13 |
-
|
| 14 |
-
_logger = logging.getLogger(__name__)
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
@dataclass
|
| 18 |
-
class RandomRIR(Effect):
|
| 19 |
-
rir_dir: Path | None
|
| 20 |
-
rir_rate: int = 44_000
|
| 21 |
-
rir_suffix: str = ".npy"
|
| 22 |
-
deterministic: bool = False
|
| 23 |
-
|
| 24 |
-
@cached_property
|
| 25 |
-
def rir_paths(self):
|
| 26 |
-
if self.rir_dir is None:
|
| 27 |
-
return []
|
| 28 |
-
return list(walk_paths(self.rir_dir, self.rir_suffix))
|
| 29 |
-
|
| 30 |
-
def _sample_rir(self):
|
| 31 |
-
if len(self.rir_paths) == 0:
|
| 32 |
-
return None
|
| 33 |
-
|
| 34 |
-
if self.deterministic:
|
| 35 |
-
rir_path = self.rir_paths[0]
|
| 36 |
-
else:
|
| 37 |
-
rir_path = random.choice(self.rir_paths)
|
| 38 |
-
|
| 39 |
-
rir = np.squeeze(np.load(rir_path))
|
| 40 |
-
assert isinstance(rir, np.ndarray)
|
| 41 |
-
|
| 42 |
-
return rir
|
| 43 |
-
|
| 44 |
-
def apply(self, wav, sr):
|
| 45 |
-
# ref: https://github.com/haoheliu/voicefixer_main/blob/b06e07c945ac1d309b8a57ddcd599ca376b98cd9/dataloaders/augmentation/magical_effects.py#L158
|
| 46 |
-
|
| 47 |
-
if len(self.rir_paths) == 0:
|
| 48 |
-
return wav
|
| 49 |
-
|
| 50 |
-
length = len(wav)
|
| 51 |
-
|
| 52 |
-
wav = librosa.resample(wav, orig_sr=sr, target_sr=self.rir_rate, res_type="kaiser_fast")
|
| 53 |
-
rir = self._sample_rir()
|
| 54 |
-
|
| 55 |
-
wav = signal.convolve(wav, rir, mode="same")
|
| 56 |
-
|
| 57 |
-
actlev = np.max(np.abs(wav))
|
| 58 |
-
if actlev > 0.99:
|
| 59 |
-
wav = (wav / actlev) * 0.98
|
| 60 |
-
|
| 61 |
-
wav = librosa.resample(wav, orig_sr=self.rir_rate, target_sr=sr, res_type="kaiser_fast")
|
| 62 |
-
|
| 63 |
-
if abs(length - len(wav)) > 10:
|
| 64 |
-
_logger.warning(f"length mismatch: {length} vs {len(wav)}")
|
| 65 |
-
|
| 66 |
-
if length > len(wav):
|
| 67 |
-
wav = np.pad(wav, (0, length - len(wav)))
|
| 68 |
-
elif length < len(wav):
|
| 69 |
-
wav = wav[:length]
|
| 70 |
-
|
| 71 |
-
return wav
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
class RandomGaussianNoise(Effect):
|
| 75 |
-
def __init__(self, alpha_range=(0.8, 1)):
|
| 76 |
-
super().__init__()
|
| 77 |
-
self.alpha_range = alpha_range
|
| 78 |
-
|
| 79 |
-
def apply(self, wav, sr):
|
| 80 |
-
noise = np.random.randn(*wav.shape)
|
| 81 |
-
noise_energy = np.sum(noise**2)
|
| 82 |
-
wav_energy = np.sum(wav**2)
|
| 83 |
-
noise = noise * np.sqrt(wav_energy / noise_energy)
|
| 84 |
-
alpha = random.uniform(*self.alpha_range)
|
| 85 |
-
return wav * alpha + noise * (1 - alpha)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/distorter/distorter.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
| 1 |
-
from ...hparams import HParams
|
| 2 |
-
from .base import Chain, Choice, Permutation
|
| 3 |
-
from .custom import RandomGaussianNoise, RandomRIR
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class Distorter(Chain):
|
| 7 |
-
def __init__(self, hp: HParams, training: bool = False, mode: str = "enhancer"):
|
| 8 |
-
# Lazy import
|
| 9 |
-
from .sox import RandomBandpassDistorter, RandomEqualizer, RandomLowpassDistorter, RandomOverdrive, RandomReverb
|
| 10 |
-
|
| 11 |
-
if training:
|
| 12 |
-
permutation = Permutation(
|
| 13 |
-
RandomRIR(hp.rir_dir),
|
| 14 |
-
RandomReverb(),
|
| 15 |
-
RandomGaussianNoise(),
|
| 16 |
-
RandomOverdrive(),
|
| 17 |
-
RandomEqualizer(),
|
| 18 |
-
Choice(
|
| 19 |
-
RandomLowpassDistorter(),
|
| 20 |
-
RandomBandpassDistorter(),
|
| 21 |
-
),
|
| 22 |
-
)
|
| 23 |
-
if mode == "denoiser":
|
| 24 |
-
super().__init__(permutation)
|
| 25 |
-
else:
|
| 26 |
-
# 80%: distortion, 20%: clean
|
| 27 |
-
super().__init__(Choice(permutation, Chain(), p=[0.8, 0.2]))
|
| 28 |
-
else:
|
| 29 |
-
super().__init__(
|
| 30 |
-
RandomRIR(hp.rir_dir, deterministic=True),
|
| 31 |
-
RandomReverb(deterministic=True),
|
| 32 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/distorter/sox.py
DELETED
|
@@ -1,176 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import os
|
| 3 |
-
import random
|
| 4 |
-
import warnings
|
| 5 |
-
from functools import partial
|
| 6 |
-
|
| 7 |
-
import numpy as np
|
| 8 |
-
import torch
|
| 9 |
-
|
| 10 |
-
try:
|
| 11 |
-
import augment
|
| 12 |
-
except ImportError:
|
| 13 |
-
raise ImportError(
|
| 14 |
-
"augment is not installed, please install it first using:"
|
| 15 |
-
"\npip install git+https://github.com/facebookresearch/WavAugment@54afcdb00ccc852c2f030f239f8532c9562b550e"
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
from .base import Effect
|
| 19 |
-
|
| 20 |
-
_logger = logging.getLogger(__name__)
|
| 21 |
-
_DEBUG = bool(os.environ.get("DEBUG", False))
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
class AttachableEffect(Effect):
|
| 25 |
-
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
| 26 |
-
raise NotImplementedError
|
| 27 |
-
|
| 28 |
-
def apply(self, wav: np.ndarray, sr: int):
|
| 29 |
-
chain = augment.EffectChain()
|
| 30 |
-
chain = self.attach(chain)
|
| 31 |
-
tensor = torch.from_numpy(wav)[None].float() # (1, T)
|
| 32 |
-
tensor = chain.apply(tensor, src_info={"rate": sr}, target_info={"channels": 1, "rate": sr})
|
| 33 |
-
wav = tensor.numpy()[0] # (T,)
|
| 34 |
-
return wav
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
class SoxEffect(AttachableEffect):
|
| 38 |
-
def __init__(self, effect_name: str, *args, **kwargs):
|
| 39 |
-
self.effect_name = effect_name
|
| 40 |
-
self.args = args
|
| 41 |
-
self.kwargs = kwargs
|
| 42 |
-
|
| 43 |
-
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
| 44 |
-
_logger.debug(f"Attaching {self.effect_name} with {self.args} and {self.kwargs}")
|
| 45 |
-
if not hasattr(chain, self.effect_name):
|
| 46 |
-
raise ValueError(f"EffectChain has no attribute {self.effect_name}")
|
| 47 |
-
return getattr(chain, self.effect_name)(*self.args, **self.kwargs)
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
class Maybe(AttachableEffect):
|
| 51 |
-
"""
|
| 52 |
-
Attach an effect with a probability.
|
| 53 |
-
"""
|
| 54 |
-
|
| 55 |
-
def __init__(self, prob: float, effect: AttachableEffect):
|
| 56 |
-
self.prob = prob
|
| 57 |
-
self.effect = effect
|
| 58 |
-
if _DEBUG:
|
| 59 |
-
warnings.warn("DEBUG mode is on. Maybe -> Must.")
|
| 60 |
-
self.prob = 1
|
| 61 |
-
|
| 62 |
-
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
| 63 |
-
if random.random() > self.prob:
|
| 64 |
-
return chain
|
| 65 |
-
return self.effect.attach(chain)
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
class Chain(AttachableEffect):
|
| 69 |
-
"""
|
| 70 |
-
Attach a chain of effects.
|
| 71 |
-
"""
|
| 72 |
-
|
| 73 |
-
def __init__(self, *effects: AttachableEffect):
|
| 74 |
-
self.effects = effects
|
| 75 |
-
|
| 76 |
-
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
| 77 |
-
for effect in self.effects:
|
| 78 |
-
chain = effect.attach(chain)
|
| 79 |
-
return chain
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
class Choice(AttachableEffect):
|
| 83 |
-
"""
|
| 84 |
-
Attach one of the effects randomly.
|
| 85 |
-
"""
|
| 86 |
-
|
| 87 |
-
def __init__(self, *effects: AttachableEffect):
|
| 88 |
-
self.effects = effects
|
| 89 |
-
|
| 90 |
-
def attach(self, chain: augment.EffectChain) -> augment.EffectChain:
|
| 91 |
-
return random.choice(self.effects).attach(chain)
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
class Generator:
|
| 95 |
-
def __call__(self) -> str:
|
| 96 |
-
raise NotImplementedError
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
class Uniform(Generator):
|
| 100 |
-
def __init__(self, low, high):
|
| 101 |
-
self.low = low
|
| 102 |
-
self.high = high
|
| 103 |
-
|
| 104 |
-
def __call__(self) -> str:
|
| 105 |
-
return str(random.uniform(self.low, self.high))
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
class Randint(Generator):
|
| 109 |
-
def __init__(self, low, high):
|
| 110 |
-
self.low = low
|
| 111 |
-
self.high = high
|
| 112 |
-
|
| 113 |
-
def __call__(self) -> str:
|
| 114 |
-
return str(random.randint(self.low, self.high))
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
class Concat(Generator):
|
| 118 |
-
def __init__(self, *parts: Generator | str):
|
| 119 |
-
self.parts = parts
|
| 120 |
-
|
| 121 |
-
def __call__(self):
|
| 122 |
-
return "".join([part if isinstance(part, str) else part() for part in self.parts])
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
class RandomLowpassDistorter(SoxEffect):
|
| 126 |
-
def __init__(self, low=2000, high=16000):
|
| 127 |
-
super().__init__("sinc", "-n", Randint(50, 200), Concat("-", Uniform(low, high)))
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
class RandomBandpassDistorter(SoxEffect):
|
| 131 |
-
def __init__(self, low=100, high=1000, min_width=2000, max_width=4000):
|
| 132 |
-
super().__init__("sinc", "-n", Randint(50, 200), partial(self._fn, low, high, min_width, max_width))
|
| 133 |
-
|
| 134 |
-
@staticmethod
|
| 135 |
-
def _fn(low, high, min_width, max_width):
|
| 136 |
-
start = random.randint(low, high)
|
| 137 |
-
stop = start + random.randint(min_width, max_width)
|
| 138 |
-
return f"{start}-{stop}"
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
class RandomEqualizer(SoxEffect):
|
| 142 |
-
def __init__(self, low=100, high=4000, q_low=1, q_high=5, db_low: int = -30, db_high: int = 30):
|
| 143 |
-
super().__init__(
|
| 144 |
-
"equalizer",
|
| 145 |
-
Uniform(low, high),
|
| 146 |
-
lambda: f"{random.randint(q_low, q_high)}q",
|
| 147 |
-
lambda: random.randint(db_low, db_high),
|
| 148 |
-
)
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
class RandomOverdrive(SoxEffect):
|
| 152 |
-
def __init__(self, gain_low=5, gain_high=40, colour_low=20, colour_high=80):
|
| 153 |
-
super().__init__("overdrive", Uniform(gain_low, gain_high), Uniform(colour_low, colour_high))
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
class RandomReverb(Chain):
|
| 157 |
-
def __init__(self, deterministic=False):
|
| 158 |
-
super().__init__(
|
| 159 |
-
SoxEffect(
|
| 160 |
-
"reverb",
|
| 161 |
-
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
| 162 |
-
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
| 163 |
-
Uniform(50, 50) if deterministic else Uniform(0, 100),
|
| 164 |
-
),
|
| 165 |
-
SoxEffect("channels", 1),
|
| 166 |
-
)
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
class Flanger(SoxEffect):
|
| 170 |
-
def __init__(self):
|
| 171 |
-
super().__init__("flanger")
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
class Phaser(SoxEffect):
|
| 175 |
-
def __init__(self):
|
| 176 |
-
super().__init__("phaser")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/data/utils.py
DELETED
|
@@ -1,43 +0,0 @@
|
|
| 1 |
-
from pathlib import Path
|
| 2 |
-
from typing import Callable
|
| 3 |
-
|
| 4 |
-
from torch import Tensor
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
def walk_paths(root, suffix):
|
| 8 |
-
for path in Path(root).iterdir():
|
| 9 |
-
if path.is_dir():
|
| 10 |
-
yield from walk_paths(path, suffix)
|
| 11 |
-
elif path.suffix == suffix:
|
| 12 |
-
yield path
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
def rglob_audio_files(path: Path):
|
| 16 |
-
return list(walk_paths(path, ".wav")) + list(walk_paths(path, ".flac"))
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def mix_fg_bg(fg: Tensor, bg: Tensor, alpha: float | Callable[..., float] = 0.5, eps=1e-7):
|
| 20 |
-
"""
|
| 21 |
-
Args:
|
| 22 |
-
fg: (b, t)
|
| 23 |
-
bg: (b, t)
|
| 24 |
-
"""
|
| 25 |
-
assert bg.shape == fg.shape, f"bg.shape != fg.shape: {bg.shape} != {fg.shape}"
|
| 26 |
-
fg = fg / (fg.abs().max(dim=-1, keepdim=True).values + eps)
|
| 27 |
-
bg = bg / (bg.abs().max(dim=-1, keepdim=True).values + eps)
|
| 28 |
-
|
| 29 |
-
fg_energy = fg.pow(2).sum(dim=-1, keepdim=True)
|
| 30 |
-
bg_energy = bg.pow(2).sum(dim=-1, keepdim=True)
|
| 31 |
-
|
| 32 |
-
fg = fg / (fg_energy + eps).sqrt()
|
| 33 |
-
bg = bg / (bg_energy + eps).sqrt()
|
| 34 |
-
|
| 35 |
-
if callable(alpha):
|
| 36 |
-
alpha = alpha()
|
| 37 |
-
|
| 38 |
-
assert 0 <= alpha <= 1, f"alpha must be between 0 and 1: {alpha}"
|
| 39 |
-
|
| 40 |
-
mx = alpha * fg + (1 - alpha) * bg
|
| 41 |
-
mx = mx / (mx.abs().max(dim=-1, keepdim=True).values + eps)
|
| 42 |
-
|
| 43 |
-
return mx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/__init__.py
DELETED
|
File without changes
|
resemble_enhance/denoiser/__main__.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
from pathlib import Path
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
import torchaudio
|
| 6 |
-
|
| 7 |
-
from .inference import denoise
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
@torch.inference_mode()
|
| 11 |
-
def main():
|
| 12 |
-
parser = argparse.ArgumentParser()
|
| 13 |
-
parser.add_argument("in_dir", type=Path, help="Path to input audio folder")
|
| 14 |
-
parser.add_argument("out_dir", type=Path, help="Output folder")
|
| 15 |
-
parser.add_argument("--run_dir", type=Path, default="runs/denoiser", help="Path to run folder")
|
| 16 |
-
parser.add_argument("--suffix", type=str, default=".wav", help="File suffix")
|
| 17 |
-
parser.add_argument("--device", type=str, default="cuda", help="Device")
|
| 18 |
-
args = parser.parse_args()
|
| 19 |
-
|
| 20 |
-
for path in args.in_dir.glob(f"**/*{args.suffix}"):
|
| 21 |
-
print(f"Processing {path} ..")
|
| 22 |
-
dwav, sr = torchaudio.load(path)
|
| 23 |
-
hwav, sr = denoise(dwav[0], sr, args.run_dir, args.device)
|
| 24 |
-
out_path = args.out_dir / path.relative_to(args.in_dir)
|
| 25 |
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 26 |
-
torchaudio.save(out_path, hwav[None], sr)
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
if __name__ == "__main__":
|
| 30 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/denoiser.py
DELETED
|
@@ -1,181 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
import torch.nn.functional as F
|
| 5 |
-
from torch import Tensor, nn
|
| 6 |
-
|
| 7 |
-
from ..melspec import MelSpectrogram
|
| 8 |
-
from .hparams import HParams
|
| 9 |
-
from .unet import UNet
|
| 10 |
-
|
| 11 |
-
logger = logging.getLogger(__name__)
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def _normalize(x: Tensor) -> Tensor:
|
| 15 |
-
return x / (x.abs().max(dim=-1, keepdim=True).values + 1e-7)
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
class Denoiser(nn.Module):
|
| 19 |
-
@property
|
| 20 |
-
def stft_cfg(self) -> dict:
|
| 21 |
-
hop_size = self.hp.hop_size
|
| 22 |
-
return dict(hop_length=hop_size, n_fft=hop_size * 4, win_length=hop_size * 4)
|
| 23 |
-
|
| 24 |
-
@property
|
| 25 |
-
def n_fft(self):
|
| 26 |
-
return self.stft_cfg["n_fft"]
|
| 27 |
-
|
| 28 |
-
@property
|
| 29 |
-
def eps(self):
|
| 30 |
-
return 1e-7
|
| 31 |
-
|
| 32 |
-
def __init__(self, hp: HParams):
|
| 33 |
-
super().__init__()
|
| 34 |
-
self.hp = hp
|
| 35 |
-
self.net = UNet(input_dim=3, output_dim=3)
|
| 36 |
-
self.mel_fn = MelSpectrogram(hp)
|
| 37 |
-
|
| 38 |
-
self.dummy: Tensor
|
| 39 |
-
self.register_buffer("dummy", torch.zeros(1), persistent=False)
|
| 40 |
-
|
| 41 |
-
def to_mel(self, x: Tensor, drop_last=True):
|
| 42 |
-
"""
|
| 43 |
-
Args:
|
| 44 |
-
x: (b t), wavs
|
| 45 |
-
Returns:
|
| 46 |
-
o: (b c t), mels
|
| 47 |
-
"""
|
| 48 |
-
if drop_last:
|
| 49 |
-
return self.mel_fn(x)[..., :-1] # (b d t)
|
| 50 |
-
return self.mel_fn(x)
|
| 51 |
-
|
| 52 |
-
def _stft(self, x):
|
| 53 |
-
"""
|
| 54 |
-
Args:
|
| 55 |
-
x: (b t)
|
| 56 |
-
Returns:
|
| 57 |
-
mag: (b f t) in [0, inf)
|
| 58 |
-
cos: (b f t) in [-1, 1]
|
| 59 |
-
sin: (b f t) in [-1, 1]
|
| 60 |
-
"""
|
| 61 |
-
dtype = x.dtype
|
| 62 |
-
device = x.device
|
| 63 |
-
|
| 64 |
-
if x.is_mps:
|
| 65 |
-
x = x.cpu()
|
| 66 |
-
|
| 67 |
-
window = torch.hann_window(self.stft_cfg["win_length"], device=x.device)
|
| 68 |
-
s = torch.stft(x.float(), **self.stft_cfg, window=window, return_complex=True) # (b f t+1)
|
| 69 |
-
|
| 70 |
-
s = s[..., :-1] # (b f t)
|
| 71 |
-
|
| 72 |
-
mag = s.abs() # (b f t)
|
| 73 |
-
|
| 74 |
-
phi = s.angle() # (b f t)
|
| 75 |
-
cos = phi.cos() # (b f t)
|
| 76 |
-
sin = phi.sin() # (b f t)
|
| 77 |
-
|
| 78 |
-
mag = mag.to(dtype=dtype, device=device)
|
| 79 |
-
cos = cos.to(dtype=dtype, device=device)
|
| 80 |
-
sin = sin.to(dtype=dtype, device=device)
|
| 81 |
-
|
| 82 |
-
return mag, cos, sin
|
| 83 |
-
|
| 84 |
-
def _istft(self, mag: Tensor, cos: Tensor, sin: Tensor):
|
| 85 |
-
"""
|
| 86 |
-
Args:
|
| 87 |
-
mag: (b f t) in [0, inf)
|
| 88 |
-
cos: (b f t) in [-1, 1]
|
| 89 |
-
sin: (b f t) in [-1, 1]
|
| 90 |
-
Returns:
|
| 91 |
-
x: (b t)
|
| 92 |
-
"""
|
| 93 |
-
device = mag.device
|
| 94 |
-
dtype = mag.dtype
|
| 95 |
-
|
| 96 |
-
if mag.is_mps:
|
| 97 |
-
mag = mag.cpu()
|
| 98 |
-
cos = cos.cpu()
|
| 99 |
-
sin = sin.cpu()
|
| 100 |
-
|
| 101 |
-
real = mag * cos # (b f t)
|
| 102 |
-
imag = mag * sin # (b f t)
|
| 103 |
-
|
| 104 |
-
s = torch.complex(real, imag) # (b f t)
|
| 105 |
-
|
| 106 |
-
if s.isnan().any():
|
| 107 |
-
logger.warning("NaN detected in ISTFT input.")
|
| 108 |
-
|
| 109 |
-
s = F.pad(s, (0, 1), "replicate") # (b f t+1)
|
| 110 |
-
|
| 111 |
-
window = torch.hann_window(self.stft_cfg["win_length"], device=s.device)
|
| 112 |
-
x = torch.istft(s, **self.stft_cfg, window=window, return_complex=False)
|
| 113 |
-
|
| 114 |
-
if x.isnan().any():
|
| 115 |
-
logger.warning("NaN detected in ISTFT output, set to zero.")
|
| 116 |
-
x = torch.where(x.isnan(), torch.zeros_like(x), x)
|
| 117 |
-
|
| 118 |
-
x = x.to(dtype=dtype, device=device)
|
| 119 |
-
|
| 120 |
-
return x
|
| 121 |
-
|
| 122 |
-
def _magphase(self, real, imag):
|
| 123 |
-
mag = (real.pow(2) + imag.pow(2) + self.eps).sqrt()
|
| 124 |
-
cos = real / mag
|
| 125 |
-
sin = imag / mag
|
| 126 |
-
return mag, cos, sin
|
| 127 |
-
|
| 128 |
-
def _predict(self, mag: Tensor, cos: Tensor, sin: Tensor):
|
| 129 |
-
"""
|
| 130 |
-
Args:
|
| 131 |
-
mag: (b f t)
|
| 132 |
-
cos: (b f t)
|
| 133 |
-
sin: (b f t)
|
| 134 |
-
Returns:
|
| 135 |
-
mag_mask: (b f t) in [0, 1], magnitude mask
|
| 136 |
-
cos_res: (b f t) in [-1, 1], phase residual
|
| 137 |
-
sin_res: (b f t) in [-1, 1], phase residual
|
| 138 |
-
"""
|
| 139 |
-
x = torch.stack([mag, cos, sin], dim=1) # (b 3 f t)
|
| 140 |
-
mag_mask, real, imag = self.net(x).unbind(1) # (b 3 f t)
|
| 141 |
-
mag_mask = mag_mask.sigmoid() # (b f t)
|
| 142 |
-
real = real.tanh() # (b f t)
|
| 143 |
-
imag = imag.tanh() # (b f t)
|
| 144 |
-
_, cos_res, sin_res = self._magphase(real, imag) # (b f t)
|
| 145 |
-
return mag_mask, sin_res, cos_res
|
| 146 |
-
|
| 147 |
-
def _separate(self, mag, cos, sin, mag_mask, cos_res, sin_res):
|
| 148 |
-
"""Ref: https://audio-agi.github.io/Separate-Anything-You-Describe/AudioSep_arXiv.pdf"""
|
| 149 |
-
sep_mag = F.relu(mag * mag_mask)
|
| 150 |
-
sep_cos = cos * cos_res - sin * sin_res
|
| 151 |
-
sep_sin = sin * cos_res + cos * sin_res
|
| 152 |
-
return sep_mag, sep_cos, sep_sin
|
| 153 |
-
|
| 154 |
-
def forward(self, x: Tensor, y: Tensor | None = None):
|
| 155 |
-
"""
|
| 156 |
-
Args:
|
| 157 |
-
x: (b t), a mixed audio
|
| 158 |
-
y: (b t), a fg audio
|
| 159 |
-
"""
|
| 160 |
-
assert x.dim() == 2, f"Expected (b t), got {x.size()}"
|
| 161 |
-
x = x.to(self.dummy)
|
| 162 |
-
x = _normalize(x)
|
| 163 |
-
|
| 164 |
-
if y is not None:
|
| 165 |
-
assert y.dim() == 2, f"Expected (b t), got {y.size()}"
|
| 166 |
-
y = y.to(self.dummy)
|
| 167 |
-
y = _normalize(y)
|
| 168 |
-
|
| 169 |
-
mag, cos, sin = self._stft(x) # (b 2f t)
|
| 170 |
-
mag_mask, sin_res, cos_res = self._predict(mag, cos, sin)
|
| 171 |
-
sep_mag, sep_cos, sep_sin = self._separate(mag, cos, sin, mag_mask, cos_res, sin_res)
|
| 172 |
-
|
| 173 |
-
o = self._istft(sep_mag, sep_cos, sep_sin)
|
| 174 |
-
|
| 175 |
-
npad = x.shape[-1] - o.shape[-1]
|
| 176 |
-
o = F.pad(o, (0, npad))
|
| 177 |
-
|
| 178 |
-
if y is not None:
|
| 179 |
-
self.losses = dict(l1=F.l1_loss(o, y))
|
| 180 |
-
|
| 181 |
-
return o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/hparams.py
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
from dataclasses import dataclass
|
| 2 |
-
|
| 3 |
-
from ..hparams import HParams as HParamsBase
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
@dataclass(frozen=True)
|
| 7 |
-
class HParams(HParamsBase):
|
| 8 |
-
batch_size_per_gpu: int = 128
|
| 9 |
-
distort_prob: float = 0.5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/inference.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from functools import cache
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
|
| 6 |
-
from ..inference import inference
|
| 7 |
-
from .denoiser import Denoiser
|
| 8 |
-
from .hparams import HParams
|
| 9 |
-
|
| 10 |
-
logger = logging.getLogger(__name__)
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
@cache
|
| 14 |
-
def load_denoiser(run_dir, device):
|
| 15 |
-
if run_dir is None:
|
| 16 |
-
return Denoiser(HParams())
|
| 17 |
-
hp = HParams.load(run_dir)
|
| 18 |
-
denoiser = Denoiser(hp)
|
| 19 |
-
path = run_dir / "ds" / "G" / "default" / "mp_rank_00_model_states.pt"
|
| 20 |
-
state_dict = torch.load(path, map_location="cpu")["module"]
|
| 21 |
-
denoiser.load_state_dict(state_dict)
|
| 22 |
-
denoiser.eval()
|
| 23 |
-
denoiser.to(device)
|
| 24 |
-
return denoiser
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
@torch.inference_mode()
|
| 28 |
-
def denoise(dwav, sr, run_dir, device):
|
| 29 |
-
denoiser = load_denoiser(run_dir, device)
|
| 30 |
-
return inference(model=denoiser, dwav=dwav, sr=sr, device=device)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/train.py
DELETED
|
@@ -1,112 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
import random
|
| 3 |
-
from functools import partial
|
| 4 |
-
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
import soundfile
|
| 7 |
-
import torch
|
| 8 |
-
from deepspeed import DeepSpeedConfig
|
| 9 |
-
from torch import Tensor
|
| 10 |
-
from tqdm import tqdm
|
| 11 |
-
|
| 12 |
-
from ..data import create_dataloaders, mix_fg_bg
|
| 13 |
-
from ..utils import Engine, TrainLoop, save_mels, setup_logging, tree_map
|
| 14 |
-
from ..utils.distributed import is_local_leader
|
| 15 |
-
from .denoiser import Denoiser
|
| 16 |
-
from .hparams import HParams
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def load_G(run_dir: Path, hp: HParams | None = None, training=True):
|
| 20 |
-
if hp is None:
|
| 21 |
-
hp = HParams.load(run_dir)
|
| 22 |
-
assert isinstance(hp, HParams)
|
| 23 |
-
model = Denoiser(hp)
|
| 24 |
-
engine = Engine(model=model, config_class=DeepSpeedConfig(hp.deepspeed_config), ckpt_dir=run_dir / "ds" / "G")
|
| 25 |
-
if training:
|
| 26 |
-
engine.load_checkpoint()
|
| 27 |
-
else:
|
| 28 |
-
engine.load_checkpoint(load_optimizer_states=False, load_lr_scheduler_states=False)
|
| 29 |
-
return engine
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
def save_wav(path: Path, wav: Tensor, rate: int):
|
| 33 |
-
wav = wav.detach().cpu().numpy()
|
| 34 |
-
soundfile.write(path, wav, samplerate=rate)
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def main():
|
| 38 |
-
parser = argparse.ArgumentParser()
|
| 39 |
-
parser.add_argument("run_dir", type=Path)
|
| 40 |
-
parser.add_argument("--yaml", type=Path, default=None)
|
| 41 |
-
parser.add_argument("--device", type=str, default="cuda")
|
| 42 |
-
args = parser.parse_args()
|
| 43 |
-
|
| 44 |
-
setup_logging(args.run_dir)
|
| 45 |
-
hp = HParams.load(args.run_dir, yaml=args.yaml)
|
| 46 |
-
|
| 47 |
-
if is_local_leader():
|
| 48 |
-
hp.save_if_not_exists(args.run_dir)
|
| 49 |
-
hp.print()
|
| 50 |
-
|
| 51 |
-
train_dl, val_dl = create_dataloaders(hp, mode="denoiser")
|
| 52 |
-
|
| 53 |
-
def feed_G(engine: Engine, batch: dict[str, Tensor]):
|
| 54 |
-
alpha_fn = lambda: random.uniform(*hp.mix_alpha_range)
|
| 55 |
-
if random.random() < hp.distort_prob:
|
| 56 |
-
fg_wavs = batch["fg_dwavs"]
|
| 57 |
-
else:
|
| 58 |
-
fg_wavs = batch["fg_wavs"]
|
| 59 |
-
mx_dwavs = mix_fg_bg(fg_wavs, batch["bg_dwavs"], alpha=alpha_fn)
|
| 60 |
-
pred = engine(mx_dwavs, fg_wavs)
|
| 61 |
-
losses = engine.gather_attribute("losses", prefix="losses")
|
| 62 |
-
return pred, losses
|
| 63 |
-
|
| 64 |
-
@torch.no_grad()
|
| 65 |
-
def eval_fn(engine: Engine, eval_dir, n_saved=10):
|
| 66 |
-
model = engine.module
|
| 67 |
-
model.eval()
|
| 68 |
-
|
| 69 |
-
step = engine.global_step
|
| 70 |
-
|
| 71 |
-
for i, batch in enumerate(tqdm(val_dl), 1):
|
| 72 |
-
batch = tree_map(lambda x: x.to(args.device) if isinstance(x, Tensor) else x, batch)
|
| 73 |
-
|
| 74 |
-
fg_dwavs = batch["fg_dwavs"] # 1 t
|
| 75 |
-
mx_dwavs = mix_fg_bg(fg_dwavs, batch["bg_dwavs"])
|
| 76 |
-
pred_fg_dwavs = model(mx_dwavs) # 1 t
|
| 77 |
-
|
| 78 |
-
mx_mels = model.to_mel(mx_dwavs) # 1 c t
|
| 79 |
-
fg_mels = model.to_mel(fg_dwavs) # 1 c t
|
| 80 |
-
pred_fg_mels = model.to_mel(pred_fg_dwavs) # 1 c t
|
| 81 |
-
|
| 82 |
-
rate = model.hp.wav_rate
|
| 83 |
-
get_path = lambda suffix: eval_dir / f"step_{step:08}_{i:03}{suffix}"
|
| 84 |
-
|
| 85 |
-
save_wav(get_path("_input.wav"), mx_dwavs[0], rate=rate)
|
| 86 |
-
save_wav(get_path("_predict.wav"), pred_fg_dwavs[0], rate=rate)
|
| 87 |
-
save_wav(get_path("_target.wav"), fg_dwavs[0], rate=rate)
|
| 88 |
-
|
| 89 |
-
save_mels(
|
| 90 |
-
get_path(".png"),
|
| 91 |
-
cond_mel=mx_mels[0].cpu().numpy(),
|
| 92 |
-
pred_mel=pred_fg_mels[0].cpu().numpy(),
|
| 93 |
-
targ_mel=fg_mels[0].cpu().numpy(),
|
| 94 |
-
)
|
| 95 |
-
|
| 96 |
-
if i >= n_saved:
|
| 97 |
-
break
|
| 98 |
-
|
| 99 |
-
train_loop = TrainLoop(
|
| 100 |
-
run_dir=args.run_dir,
|
| 101 |
-
train_dl=train_dl,
|
| 102 |
-
load_G=partial(load_G, hp=hp),
|
| 103 |
-
device=args.device,
|
| 104 |
-
feed_G=feed_G,
|
| 105 |
-
eval_fn=eval_fn,
|
| 106 |
-
)
|
| 107 |
-
|
| 108 |
-
train_loop.run(max_steps=hp.max_steps)
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
if __name__ == "__main__":
|
| 112 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/denoiser/unet.py
DELETED
|
@@ -1,144 +0,0 @@
|
|
| 1 |
-
import torch.nn.functional as F
|
| 2 |
-
from torch import nn
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class PreactResBlock(nn.Sequential):
|
| 6 |
-
def __init__(self, dim):
|
| 7 |
-
super().__init__(
|
| 8 |
-
nn.GroupNorm(dim // 16, dim),
|
| 9 |
-
nn.GELU(),
|
| 10 |
-
nn.Conv2d(dim, dim, 3, padding=1),
|
| 11 |
-
nn.GroupNorm(dim // 16, dim),
|
| 12 |
-
nn.GELU(),
|
| 13 |
-
nn.Conv2d(dim, dim, 3, padding=1),
|
| 14 |
-
)
|
| 15 |
-
|
| 16 |
-
def forward(self, x):
|
| 17 |
-
return x + super().forward(x)
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
class UNetBlock(nn.Module):
|
| 21 |
-
def __init__(self, input_dim, output_dim=None, scale_factor=1.0):
|
| 22 |
-
super().__init__()
|
| 23 |
-
if output_dim is None:
|
| 24 |
-
output_dim = input_dim
|
| 25 |
-
self.pre_conv = nn.Conv2d(input_dim, output_dim, 3, padding=1)
|
| 26 |
-
self.res_block1 = PreactResBlock(output_dim)
|
| 27 |
-
self.res_block2 = PreactResBlock(output_dim)
|
| 28 |
-
self.downsample = self.upsample = nn.Identity()
|
| 29 |
-
if scale_factor > 1:
|
| 30 |
-
self.upsample = nn.Upsample(scale_factor=scale_factor)
|
| 31 |
-
elif scale_factor < 1:
|
| 32 |
-
self.downsample = nn.Upsample(scale_factor=scale_factor)
|
| 33 |
-
|
| 34 |
-
def forward(self, x, h=None):
|
| 35 |
-
"""
|
| 36 |
-
Args:
|
| 37 |
-
x: (b c h w), last output
|
| 38 |
-
h: (b c h w), skip output
|
| 39 |
-
Returns:
|
| 40 |
-
o: (b c h w), output
|
| 41 |
-
s: (b c h w), skip output
|
| 42 |
-
"""
|
| 43 |
-
x = self.upsample(x)
|
| 44 |
-
if h is not None:
|
| 45 |
-
assert x.shape == h.shape, f"{x.shape} != {h.shape}"
|
| 46 |
-
x = x + h
|
| 47 |
-
x = self.pre_conv(x)
|
| 48 |
-
x = self.res_block1(x)
|
| 49 |
-
x = self.res_block2(x)
|
| 50 |
-
return self.downsample(x), x
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
class UNet(nn.Module):
|
| 54 |
-
def __init__(self, input_dim, output_dim, hidden_dim=16, num_blocks=4, num_middle_blocks=2):
|
| 55 |
-
super().__init__()
|
| 56 |
-
self.input_dim = input_dim
|
| 57 |
-
self.output_dim = output_dim
|
| 58 |
-
self.input_proj = nn.Conv2d(input_dim, hidden_dim, 3, padding=1)
|
| 59 |
-
self.encoder_blocks = nn.ModuleList(
|
| 60 |
-
[
|
| 61 |
-
UNetBlock(input_dim=hidden_dim * 2**i, output_dim=hidden_dim * 2 ** (i + 1), scale_factor=0.5)
|
| 62 |
-
for i in range(num_blocks)
|
| 63 |
-
]
|
| 64 |
-
)
|
| 65 |
-
self.middle_blocks = nn.ModuleList(
|
| 66 |
-
[UNetBlock(input_dim=hidden_dim * 2**num_blocks) for _ in range(num_middle_blocks)]
|
| 67 |
-
)
|
| 68 |
-
self.decoder_blocks = nn.ModuleList(
|
| 69 |
-
[
|
| 70 |
-
UNetBlock(input_dim=hidden_dim * 2 ** (i + 1), output_dim=hidden_dim * 2**i, scale_factor=2)
|
| 71 |
-
for i in reversed(range(num_blocks))
|
| 72 |
-
]
|
| 73 |
-
)
|
| 74 |
-
self.head = nn.Sequential(
|
| 75 |
-
nn.Conv2d(hidden_dim, hidden_dim, 3, padding=1),
|
| 76 |
-
nn.GELU(),
|
| 77 |
-
nn.Conv2d(hidden_dim, output_dim, 1),
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
@property
|
| 81 |
-
def scale_factor(self):
|
| 82 |
-
return 2 ** len(self.encoder_blocks)
|
| 83 |
-
|
| 84 |
-
def pad_to_fit(self, x):
|
| 85 |
-
"""
|
| 86 |
-
Args:
|
| 87 |
-
x: (b c h w), input
|
| 88 |
-
Returns:
|
| 89 |
-
x: (b c h' w'), padded input
|
| 90 |
-
"""
|
| 91 |
-
hpad = (self.scale_factor - x.shape[2] % self.scale_factor) % self.scale_factor
|
| 92 |
-
wpad = (self.scale_factor - x.shape[3] % self.scale_factor) % self.scale_factor
|
| 93 |
-
return F.pad(x, (0, wpad, 0, hpad))
|
| 94 |
-
|
| 95 |
-
def forward(self, x):
|
| 96 |
-
"""
|
| 97 |
-
Args:
|
| 98 |
-
x: (b c h w), input
|
| 99 |
-
Returns:
|
| 100 |
-
o: (b c h w), output
|
| 101 |
-
"""
|
| 102 |
-
shape = x.shape
|
| 103 |
-
|
| 104 |
-
x = self.pad_to_fit(x)
|
| 105 |
-
x = self.input_proj(x)
|
| 106 |
-
|
| 107 |
-
s_list = []
|
| 108 |
-
for block in self.encoder_blocks:
|
| 109 |
-
x, s = block(x)
|
| 110 |
-
s_list.append(s)
|
| 111 |
-
|
| 112 |
-
for block in self.middle_blocks:
|
| 113 |
-
x, _ = block(x)
|
| 114 |
-
|
| 115 |
-
for block, s in zip(self.decoder_blocks, reversed(s_list)):
|
| 116 |
-
x, _ = block(x, s)
|
| 117 |
-
|
| 118 |
-
x = self.head(x)
|
| 119 |
-
x = x[..., : shape[2], : shape[3]]
|
| 120 |
-
|
| 121 |
-
return x
|
| 122 |
-
|
| 123 |
-
def test(self, shape=(3, 512, 256)):
|
| 124 |
-
import ptflops
|
| 125 |
-
|
| 126 |
-
macs, params = ptflops.get_model_complexity_info(
|
| 127 |
-
self,
|
| 128 |
-
shape,
|
| 129 |
-
as_strings=True,
|
| 130 |
-
print_per_layer_stat=True,
|
| 131 |
-
verbose=True,
|
| 132 |
-
)
|
| 133 |
-
|
| 134 |
-
print(f"macs: {macs}")
|
| 135 |
-
print(f"params: {params}")
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
def main():
|
| 139 |
-
model = UNet(3, 3)
|
| 140 |
-
model.test()
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
if __name__ == "__main__":
|
| 144 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/__init__.py
DELETED
|
File without changes
|
resemble_enhance/enhancer/__main__.py
DELETED
|
@@ -1,123 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
import random
|
| 3 |
-
import time
|
| 4 |
-
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
import torch
|
| 7 |
-
import torchaudio
|
| 8 |
-
from tqdm import tqdm
|
| 9 |
-
|
| 10 |
-
from .inference import denoise, enhance
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
@torch.inference_mode()
|
| 14 |
-
def main():
|
| 15 |
-
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
| 16 |
-
parser.add_argument("in_dir", type=Path, help="Path to input audio folder")
|
| 17 |
-
parser.add_argument("out_dir", type=Path, help="Output folder")
|
| 18 |
-
parser.add_argument(
|
| 19 |
-
"--run_dir",
|
| 20 |
-
type=Path,
|
| 21 |
-
default=None,
|
| 22 |
-
help="Path to the enhancer run folder, if None, use the default model",
|
| 23 |
-
)
|
| 24 |
-
parser.add_argument(
|
| 25 |
-
"--suffix",
|
| 26 |
-
type=str,
|
| 27 |
-
default=".wav",
|
| 28 |
-
help="Audio file suffix",
|
| 29 |
-
)
|
| 30 |
-
parser.add_argument(
|
| 31 |
-
"--device",
|
| 32 |
-
type=str,
|
| 33 |
-
default="cuda",
|
| 34 |
-
help="Device to use for computation, recommended to use CUDA",
|
| 35 |
-
)
|
| 36 |
-
parser.add_argument(
|
| 37 |
-
"--denoise_only",
|
| 38 |
-
action="store_true",
|
| 39 |
-
help="Only apply denoising without enhancement",
|
| 40 |
-
)
|
| 41 |
-
parser.add_argument(
|
| 42 |
-
"--lambd",
|
| 43 |
-
type=float,
|
| 44 |
-
default=1.0,
|
| 45 |
-
help="Denoise strength for enhancement (0.0 to 1.0)",
|
| 46 |
-
)
|
| 47 |
-
parser.add_argument(
|
| 48 |
-
"--tau",
|
| 49 |
-
type=float,
|
| 50 |
-
default=0.5,
|
| 51 |
-
help="CFM prior temperature (0.0 to 1.0)",
|
| 52 |
-
)
|
| 53 |
-
parser.add_argument(
|
| 54 |
-
"--solver",
|
| 55 |
-
type=str,
|
| 56 |
-
default="midpoint",
|
| 57 |
-
choices=["midpoint", "rk4", "euler"],
|
| 58 |
-
help="Numerical solver to use",
|
| 59 |
-
)
|
| 60 |
-
parser.add_argument(
|
| 61 |
-
"--nfe",
|
| 62 |
-
type=int,
|
| 63 |
-
default=64,
|
| 64 |
-
help="Number of function evaluations",
|
| 65 |
-
)
|
| 66 |
-
parser.add_argument(
|
| 67 |
-
"--parallel_mode",
|
| 68 |
-
action="store_true",
|
| 69 |
-
help="Shuffle the audio paths and skip the existing ones, enabling multiple jobs to run in parallel",
|
| 70 |
-
)
|
| 71 |
-
|
| 72 |
-
args = parser.parse_args()
|
| 73 |
-
|
| 74 |
-
start_time = time.perf_counter()
|
| 75 |
-
|
| 76 |
-
run_dir = args.run_dir
|
| 77 |
-
|
| 78 |
-
paths = sorted(args.in_dir.glob(f"**/*{args.suffix}"))
|
| 79 |
-
|
| 80 |
-
if args.parallel_mode:
|
| 81 |
-
random.shuffle(paths)
|
| 82 |
-
|
| 83 |
-
if len(paths) == 0:
|
| 84 |
-
print(f"No {args.suffix} files found in the following path: {args.in_dir}")
|
| 85 |
-
return
|
| 86 |
-
|
| 87 |
-
pbar = tqdm(paths)
|
| 88 |
-
|
| 89 |
-
for path in pbar:
|
| 90 |
-
out_path = args.out_dir / path.relative_to(args.in_dir)
|
| 91 |
-
if args.parallel_mode and out_path.exists():
|
| 92 |
-
continue
|
| 93 |
-
pbar.set_description(f"Processing {out_path}")
|
| 94 |
-
dwav, sr = torchaudio.load(path)
|
| 95 |
-
dwav = dwav.mean(0)
|
| 96 |
-
if args.denoise_only:
|
| 97 |
-
hwav, sr = denoise(
|
| 98 |
-
dwav=dwav,
|
| 99 |
-
sr=sr,
|
| 100 |
-
device=args.device,
|
| 101 |
-
run_dir=args.run_dir,
|
| 102 |
-
)
|
| 103 |
-
else:
|
| 104 |
-
hwav, sr = enhance(
|
| 105 |
-
dwav=dwav,
|
| 106 |
-
sr=sr,
|
| 107 |
-
device=args.device,
|
| 108 |
-
nfe=args.nfe,
|
| 109 |
-
solver=args.solver,
|
| 110 |
-
lambd=args.lambd,
|
| 111 |
-
tau=args.tau,
|
| 112 |
-
run_dir=run_dir,
|
| 113 |
-
)
|
| 114 |
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 115 |
-
torchaudio.save(out_path, hwav[None], sr)
|
| 116 |
-
|
| 117 |
-
# Cool emoji effect saying the job is done
|
| 118 |
-
elapsed_time = time.perf_counter() - start_time
|
| 119 |
-
print(f"🌟 Enhancement done! {len(paths)} files processed in {elapsed_time:.2f}s")
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
if __name__ == "__main__":
|
| 123 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/download.py
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import os
|
| 3 |
-
import subprocess
|
| 4 |
-
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
REPO_URL = "https://huggingface.co/ResembleAI/resemble-enhance"
|
| 7 |
-
REPO_DIR = Path(__file__).parent.parent / "model_repo"
|
| 8 |
-
|
| 9 |
-
logger = logging.getLogger(__name__)
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def run_command(command, msg=None, env={}):
|
| 13 |
-
try:
|
| 14 |
-
subprocess.run(command, check=True, env={**os.environ, **env})
|
| 15 |
-
except subprocess.CalledProcessError as e:
|
| 16 |
-
if msg is not None:
|
| 17 |
-
raise RuntimeError(msg) from e
|
| 18 |
-
raise e
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
def download():
|
| 22 |
-
logger.info("Downloading the model...")
|
| 23 |
-
|
| 24 |
-
if REPO_DIR.exists() and (REPO_DIR / ".git").exists():
|
| 25 |
-
logger.info("Repository already exists, attempting to pull latest changes...")
|
| 26 |
-
run_command(
|
| 27 |
-
["git", "-C", str(REPO_DIR), "pull"],
|
| 28 |
-
"Failed to pull latest changes, please try again.",
|
| 29 |
-
{"GIT_LFS_SKIP_SMUDGE": "1"},
|
| 30 |
-
)
|
| 31 |
-
else:
|
| 32 |
-
logger.info("Cloning the repository...")
|
| 33 |
-
run_command(
|
| 34 |
-
["git", "clone", REPO_URL, str(REPO_DIR)],
|
| 35 |
-
"Failed to clone the repository, please try again.",
|
| 36 |
-
{"GIT_LFS_SKIP_SMUDGE": "1"},
|
| 37 |
-
)
|
| 38 |
-
|
| 39 |
-
logger.info("Pulling large files...")
|
| 40 |
-
run_command(["git", "-C", str(REPO_DIR), "lfs", "pull"], "Failed to pull latest changes, please try again.")
|
| 41 |
-
|
| 42 |
-
run_dir = REPO_DIR / "enhancer_stage2"
|
| 43 |
-
|
| 44 |
-
return run_dir
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/enhancer.py
DELETED
|
@@ -1,177 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
|
| 3 |
-
import pandas as pd
|
| 4 |
-
import torch
|
| 5 |
-
from torch import Tensor, nn
|
| 6 |
-
from torch.distributions import Beta
|
| 7 |
-
|
| 8 |
-
from ..common import Normalizer
|
| 9 |
-
from ..denoiser.inference import load_denoiser
|
| 10 |
-
from ..melspec import MelSpectrogram
|
| 11 |
-
from .hparams import HParams
|
| 12 |
-
from .lcfm import CFM, IRMAE, LCFM
|
| 13 |
-
from .univnet import UnivNet
|
| 14 |
-
|
| 15 |
-
logger = logging.getLogger(__name__)
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
def _maybe(fn):
|
| 19 |
-
def _fn(*args):
|
| 20 |
-
if args[0] is None:
|
| 21 |
-
return None
|
| 22 |
-
return fn(*args)
|
| 23 |
-
|
| 24 |
-
return _fn
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def _normalize_wav(x: Tensor):
|
| 28 |
-
return x / (x.abs().max(dim=-1, keepdim=True).values + 1e-7)
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
class Enhancer(nn.Module):
|
| 32 |
-
def __init__(self, hp: HParams):
|
| 33 |
-
super().__init__()
|
| 34 |
-
self.hp = hp
|
| 35 |
-
|
| 36 |
-
n_mels = self.hp.num_mels
|
| 37 |
-
vocoder_input_dim = n_mels + self.hp.vocoder_extra_dim
|
| 38 |
-
latent_dim = self.hp.lcfm_latent_dim
|
| 39 |
-
|
| 40 |
-
self.lcfm = LCFM(
|
| 41 |
-
IRMAE(
|
| 42 |
-
input_dim=n_mels,
|
| 43 |
-
output_dim=vocoder_input_dim,
|
| 44 |
-
latent_dim=latent_dim,
|
| 45 |
-
),
|
| 46 |
-
CFM(
|
| 47 |
-
cond_dim=n_mels,
|
| 48 |
-
output_dim=self.hp.lcfm_latent_dim,
|
| 49 |
-
solver_nfe=self.hp.cfm_solver_nfe,
|
| 50 |
-
solver_method=self.hp.cfm_solver_method,
|
| 51 |
-
time_mapping_divisor=self.hp.cfm_time_mapping_divisor,
|
| 52 |
-
),
|
| 53 |
-
z_scale=self.hp.lcfm_z_scale,
|
| 54 |
-
)
|
| 55 |
-
|
| 56 |
-
self.lcfm.set_mode_(self.hp.lcfm_training_mode)
|
| 57 |
-
|
| 58 |
-
self.mel_fn = MelSpectrogram(hp)
|
| 59 |
-
self.vocoder = UnivNet(self.hp, vocoder_input_dim)
|
| 60 |
-
self.denoiser = load_denoiser(self.hp.denoiser_run_dir, "cpu")
|
| 61 |
-
self.normalizer = Normalizer()
|
| 62 |
-
|
| 63 |
-
self._eval_lambd = 0.0
|
| 64 |
-
|
| 65 |
-
self.dummy: Tensor
|
| 66 |
-
self.register_buffer("dummy", torch.zeros(1))
|
| 67 |
-
|
| 68 |
-
if self.hp.enhancer_stage1_run_dir is not None:
|
| 69 |
-
pretrained_path = self.hp.enhancer_stage1_run_dir / "ds/G/default/mp_rank_00_model_states.pt"
|
| 70 |
-
self._load_pretrained(pretrained_path)
|
| 71 |
-
|
| 72 |
-
logger.info(f"{self.__class__.__name__} summary")
|
| 73 |
-
logger.info(f"{self.summarize()}")
|
| 74 |
-
|
| 75 |
-
def _load_pretrained(self, path):
|
| 76 |
-
# Clone is necessary as otherwise it holds a reference to the original model
|
| 77 |
-
cfm_state_dict = {k: v.clone() for k, v in self.lcfm.cfm.state_dict().items()}
|
| 78 |
-
denoiser_state_dict = {k: v.clone() for k, v in self.denoiser.state_dict().items()}
|
| 79 |
-
state_dict = torch.load(path, map_location="cpu")["module"]
|
| 80 |
-
self.load_state_dict(state_dict, strict=False)
|
| 81 |
-
self.lcfm.cfm.load_state_dict(cfm_state_dict) # Reset cfm
|
| 82 |
-
self.denoiser.load_state_dict(denoiser_state_dict) # Reset denoiser
|
| 83 |
-
logger.info(f"Loaded pretrained model from {path}")
|
| 84 |
-
|
| 85 |
-
def summarize(self):
|
| 86 |
-
npa_train = lambda m: sum(p.numel() for p in m.parameters() if p.requires_grad)
|
| 87 |
-
npa = lambda m: sum(p.numel() for p in m.parameters())
|
| 88 |
-
rows = []
|
| 89 |
-
for name, module in self.named_children():
|
| 90 |
-
rows.append(dict(name=name, trainable=npa_train(module), total=npa(module)))
|
| 91 |
-
rows.append(dict(name="total", trainable=npa_train(self), total=npa(self)))
|
| 92 |
-
df = pd.DataFrame(rows)
|
| 93 |
-
return df.to_markdown(index=False)
|
| 94 |
-
|
| 95 |
-
def to_mel(self, x: Tensor, drop_last=True):
|
| 96 |
-
"""
|
| 97 |
-
Args:
|
| 98 |
-
x: (b t), wavs
|
| 99 |
-
Returns:
|
| 100 |
-
o: (b c t), mels
|
| 101 |
-
"""
|
| 102 |
-
if drop_last:
|
| 103 |
-
return self.mel_fn(x)[..., :-1] # (b d t)
|
| 104 |
-
return self.mel_fn(x)
|
| 105 |
-
|
| 106 |
-
@torch.no_grad()
|
| 107 |
-
def _visualize(self, original_mel, denoised_mel):
|
| 108 |
-
return
|
| 109 |
-
|
| 110 |
-
def _may_denoise(self, x: Tensor, y: Tensor | None = None):
|
| 111 |
-
if self.hp.lcfm_training_mode == "cfm":
|
| 112 |
-
return self.denoiser(x, y)
|
| 113 |
-
return x
|
| 114 |
-
|
| 115 |
-
def configurate_(self, nfe, solver, lambd, tau):
|
| 116 |
-
"""
|
| 117 |
-
Args:
|
| 118 |
-
nfe: number of function evaluations
|
| 119 |
-
solver: solver method
|
| 120 |
-
lambd: denoiser strength [0, 1]
|
| 121 |
-
tau: prior temperature [0, 1]
|
| 122 |
-
"""
|
| 123 |
-
self.lcfm.cfm.solver.configurate_(nfe, solver)
|
| 124 |
-
self.lcfm.eval_tau_(tau)
|
| 125 |
-
self._eval_lambd = lambd
|
| 126 |
-
|
| 127 |
-
def forward(self, x: Tensor, y: Tensor | None = None, z: Tensor | None = None):
|
| 128 |
-
"""
|
| 129 |
-
Args:
|
| 130 |
-
x: (b t), mix wavs (fg + bg)
|
| 131 |
-
y: (b t), fg clean wavs
|
| 132 |
-
z: (b t), fg distorted wavs
|
| 133 |
-
Returns:
|
| 134 |
-
o: (b t), reconstructed wavs
|
| 135 |
-
"""
|
| 136 |
-
assert x.dim() == 2, f"Expected (b t), got {x.size()}"
|
| 137 |
-
assert y is None or y.dim() == 2, f"Expected (b t), got {y.size()}"
|
| 138 |
-
|
| 139 |
-
if self.hp.lcfm_training_mode == "cfm":
|
| 140 |
-
self.normalizer.eval()
|
| 141 |
-
|
| 142 |
-
x = _normalize_wav(x)
|
| 143 |
-
y = _maybe(_normalize_wav)(y)
|
| 144 |
-
z = _maybe(_normalize_wav)(z)
|
| 145 |
-
|
| 146 |
-
x_mel_original = self.normalizer(self.to_mel(x), update=False) # (b d t)
|
| 147 |
-
|
| 148 |
-
if self.hp.lcfm_training_mode == "cfm":
|
| 149 |
-
if self.training:
|
| 150 |
-
lambd = Beta(0.2, 0.2).sample(x.shape[:1]).to(x.device)
|
| 151 |
-
lambd = lambd[:, None, None]
|
| 152 |
-
x_mel_denoised = self.normalizer(self.to_mel(self._may_denoise(x, z)), update=False)
|
| 153 |
-
x_mel_denoised = x_mel_denoised.detach()
|
| 154 |
-
x_mel_denoised = lambd * x_mel_denoised + (1 - lambd) * x_mel_original
|
| 155 |
-
self._visualize(x_mel_original, x_mel_denoised)
|
| 156 |
-
else:
|
| 157 |
-
lambd = self._eval_lambd
|
| 158 |
-
if lambd == 0:
|
| 159 |
-
x_mel_denoised = x_mel_original
|
| 160 |
-
else:
|
| 161 |
-
x_mel_denoised = self.normalizer(self.to_mel(self._may_denoise(x, z)), update=False)
|
| 162 |
-
x_mel_denoised = x_mel_denoised.detach()
|
| 163 |
-
x_mel_denoised = lambd * x_mel_denoised + (1 - lambd) * x_mel_original
|
| 164 |
-
else:
|
| 165 |
-
x_mel_denoised = x_mel_original
|
| 166 |
-
|
| 167 |
-
y_mel = _maybe(self.to_mel)(y) # (b d t)
|
| 168 |
-
y_mel = _maybe(self.normalizer)(y_mel)
|
| 169 |
-
|
| 170 |
-
lcfm_decoded = self.lcfm(x_mel_denoised, y_mel, ψ0=x_mel_original) # (b d t)
|
| 171 |
-
|
| 172 |
-
if lcfm_decoded is None:
|
| 173 |
-
o = None
|
| 174 |
-
else:
|
| 175 |
-
o = self.vocoder(lcfm_decoded, y)
|
| 176 |
-
|
| 177 |
-
return o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/hparams.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
from dataclasses import dataclass
|
| 2 |
-
from pathlib import Path
|
| 3 |
-
|
| 4 |
-
from ..hparams import HParams as HParamsBase
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
@dataclass(frozen=True)
|
| 8 |
-
class HParams(HParamsBase):
|
| 9 |
-
cfm_solver_method: str = "midpoint"
|
| 10 |
-
cfm_solver_nfe: int = 64
|
| 11 |
-
cfm_time_mapping_divisor: int = 4
|
| 12 |
-
univnet_nc: int = 96
|
| 13 |
-
|
| 14 |
-
lcfm_latent_dim: int = 64
|
| 15 |
-
lcfm_training_mode: str = "ae"
|
| 16 |
-
lcfm_z_scale: float = 5
|
| 17 |
-
|
| 18 |
-
vocoder_extra_dim: int = 32
|
| 19 |
-
|
| 20 |
-
gan_training_start_step: int | None = 5_000
|
| 21 |
-
enhancer_stage1_run_dir: Path | None = None
|
| 22 |
-
|
| 23 |
-
denoiser_run_dir: Path | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/inference.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from functools import cache
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
|
| 6 |
-
from ..inference import inference
|
| 7 |
-
from .download import download
|
| 8 |
-
from .enhancer import Enhancer
|
| 9 |
-
from .hparams import HParams
|
| 10 |
-
|
| 11 |
-
logger = logging.getLogger(__name__)
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
@cache
|
| 15 |
-
def load_enhancer(run_dir, device):
|
| 16 |
-
if run_dir is None:
|
| 17 |
-
run_dir = download()
|
| 18 |
-
hp = HParams.load(run_dir)
|
| 19 |
-
enhancer = Enhancer(hp)
|
| 20 |
-
path = run_dir / "ds" / "G" / "default" / "mp_rank_00_model_states.pt"
|
| 21 |
-
state_dict = torch.load(path, map_location="cpu")["module"]
|
| 22 |
-
enhancer.load_state_dict(state_dict)
|
| 23 |
-
enhancer.eval()
|
| 24 |
-
enhancer.to(device)
|
| 25 |
-
return enhancer
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
@torch.inference_mode()
|
| 29 |
-
def denoise(dwav, sr, device, run_dir=None):
|
| 30 |
-
enhancer = load_enhancer(run_dir, device)
|
| 31 |
-
return inference(model=enhancer.denoiser, dwav=dwav, sr=sr, device=device)
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
@torch.inference_mode()
|
| 35 |
-
def enhance(dwav, sr, device, nfe=32, solver="midpoint", lambd=0.5, tau=0.5, run_dir=None):
|
| 36 |
-
assert 0 < nfe <= 128, f"nfe must be in (0, 128], got {nfe}"
|
| 37 |
-
assert solver in ("midpoint", "rk4", "euler"), f"solver must be in ('midpoint', 'rk4', 'euler'), got {solver}"
|
| 38 |
-
assert 0 <= lambd <= 1, f"lambd must be in [0, 1], got {lambd}"
|
| 39 |
-
assert 0 <= tau <= 1, f"tau must be in [0, 1], got {tau}"
|
| 40 |
-
enhancer = load_enhancer(run_dir, device)
|
| 41 |
-
enhancer.configurate_(nfe=nfe, solver=solver, lambd=lambd, tau=tau)
|
| 42 |
-
return inference(model=enhancer, dwav=dwav, sr=sr, device=device)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/lcfm/__init__.py
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
from .irmae import IRMAE
|
| 2 |
-
from .lcfm import CFM, LCFM
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/lcfm/cfm.py
DELETED
|
@@ -1,372 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from dataclasses import dataclass
|
| 3 |
-
from functools import partial
|
| 4 |
-
from typing import Protocol
|
| 5 |
-
|
| 6 |
-
import matplotlib.pyplot as plt
|
| 7 |
-
import numpy as np
|
| 8 |
-
import scipy
|
| 9 |
-
import torch
|
| 10 |
-
import torch.nn.functional as F
|
| 11 |
-
from torch import Tensor, nn
|
| 12 |
-
from tqdm import trange
|
| 13 |
-
|
| 14 |
-
from .wn import WN
|
| 15 |
-
|
| 16 |
-
logger = logging.getLogger(__name__)
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
class VelocityField(Protocol):
|
| 20 |
-
def __call__(self, *, t: Tensor, ψt: Tensor, dt: Tensor) -> Tensor:
|
| 21 |
-
...
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
class Solver:
|
| 25 |
-
def __init__(
|
| 26 |
-
self,
|
| 27 |
-
method="midpoint",
|
| 28 |
-
nfe=32,
|
| 29 |
-
viz_name="solver",
|
| 30 |
-
viz_every=100,
|
| 31 |
-
mel_fn=None,
|
| 32 |
-
time_mapping_divisor=4,
|
| 33 |
-
verbose=False,
|
| 34 |
-
):
|
| 35 |
-
self.configurate_(nfe=nfe, method=method)
|
| 36 |
-
|
| 37 |
-
self.verbose = verbose
|
| 38 |
-
self.viz_every = viz_every
|
| 39 |
-
self.viz_name = viz_name
|
| 40 |
-
|
| 41 |
-
self._camera = None
|
| 42 |
-
self._mel_fn = mel_fn
|
| 43 |
-
self._time_mapping = partial(self.exponential_decay_mapping, n=time_mapping_divisor)
|
| 44 |
-
|
| 45 |
-
def configurate_(self, nfe=None, method=None):
|
| 46 |
-
if nfe is None:
|
| 47 |
-
nfe = self.nfe
|
| 48 |
-
|
| 49 |
-
if method is None:
|
| 50 |
-
method = self.method
|
| 51 |
-
|
| 52 |
-
if nfe == 1 and method in ("midpoint", "rk4"):
|
| 53 |
-
logger.warning(f"1 NFE is not supported for {method}, using euler method instead.")
|
| 54 |
-
method = "euler"
|
| 55 |
-
|
| 56 |
-
self.nfe = nfe
|
| 57 |
-
self.method = method
|
| 58 |
-
|
| 59 |
-
@property
|
| 60 |
-
def time_mapping(self):
|
| 61 |
-
return self._time_mapping
|
| 62 |
-
|
| 63 |
-
@staticmethod
|
| 64 |
-
def exponential_decay_mapping(t, n=4):
|
| 65 |
-
"""
|
| 66 |
-
Args:
|
| 67 |
-
n: target step
|
| 68 |
-
"""
|
| 69 |
-
|
| 70 |
-
def h(t, a):
|
| 71 |
-
return (a**t - 1) / (a - 1)
|
| 72 |
-
|
| 73 |
-
# Solve h(1/n) = 0.5
|
| 74 |
-
a = float(scipy.optimize.fsolve(lambda a: h(1 / n, a) - 0.5, x0=0))
|
| 75 |
-
|
| 76 |
-
t = h(t, a=a)
|
| 77 |
-
|
| 78 |
-
return t
|
| 79 |
-
|
| 80 |
-
@torch.no_grad()
|
| 81 |
-
def _maybe_camera_snap(self, *, ψt, t):
|
| 82 |
-
camera = self._camera
|
| 83 |
-
if camera is not None:
|
| 84 |
-
if ψt.shape[1] == 1:
|
| 85 |
-
# Waveform, b 1 t, plot every 100 samples
|
| 86 |
-
plt.subplot(211)
|
| 87 |
-
plt.plot(ψt.detach().cpu().numpy()[0, 0, ::100], color="blue")
|
| 88 |
-
if self._mel_fn is not None:
|
| 89 |
-
plt.subplot(212)
|
| 90 |
-
mel = self._mel_fn(ψt.detach().cpu().numpy()[0, 0])
|
| 91 |
-
plt.imshow(mel, origin="lower", interpolation="none")
|
| 92 |
-
elif ψt.shape[1] == 2:
|
| 93 |
-
# Complex
|
| 94 |
-
plt.subplot(121)
|
| 95 |
-
plt.imshow(
|
| 96 |
-
ψt.detach().cpu().numpy()[0, 0],
|
| 97 |
-
origin="lower",
|
| 98 |
-
interpolation="none",
|
| 99 |
-
)
|
| 100 |
-
plt.subplot(122)
|
| 101 |
-
plt.imshow(
|
| 102 |
-
ψt.detach().cpu().numpy()[0, 1],
|
| 103 |
-
origin="lower",
|
| 104 |
-
interpolation="none",
|
| 105 |
-
)
|
| 106 |
-
else:
|
| 107 |
-
# Spectrogram, b c t
|
| 108 |
-
plt.imshow(ψt.detach().cpu().numpy()[0], origin="lower", interpolation="none")
|
| 109 |
-
ax = plt.gca()
|
| 110 |
-
ax.text(0.5, 1.01, f"t={t:.2f}", transform=ax.transAxes, ha="center")
|
| 111 |
-
camera.snap()
|
| 112 |
-
|
| 113 |
-
@staticmethod
|
| 114 |
-
def _euler_step(t, ψt, dt, f: VelocityField):
|
| 115 |
-
return ψt + dt * f(t=t, ψt=ψt, dt=dt)
|
| 116 |
-
|
| 117 |
-
@staticmethod
|
| 118 |
-
def _midpoint_step(t, ψt, dt, f: VelocityField):
|
| 119 |
-
return ψt + dt * f(t=t + dt / 2, ψt=ψt + dt * f(t=t, ψt=ψt, dt=dt) / 2, dt=dt)
|
| 120 |
-
|
| 121 |
-
@staticmethod
|
| 122 |
-
def _rk4_step(t, ψt, dt, f: VelocityField):
|
| 123 |
-
k1 = f(t=t, ψt=ψt, dt=dt)
|
| 124 |
-
k2 = f(t=t + dt / 2, ψt=ψt + dt * k1 / 2, dt=dt)
|
| 125 |
-
k3 = f(t=t + dt / 2, ψt=ψt + dt * k2 / 2, dt=dt)
|
| 126 |
-
k4 = f(t=t + dt, ψt=ψt + dt * k3, dt=dt)
|
| 127 |
-
return ψt + dt * (k1 + 2 * k2 + 2 * k3 + k4) / 6
|
| 128 |
-
|
| 129 |
-
@property
|
| 130 |
-
def _step(self):
|
| 131 |
-
if self.method == "euler":
|
| 132 |
-
return self._euler_step
|
| 133 |
-
elif self.method == "midpoint":
|
| 134 |
-
return self._midpoint_step
|
| 135 |
-
elif self.method == "rk4":
|
| 136 |
-
return self._rk4_step
|
| 137 |
-
else:
|
| 138 |
-
raise ValueError(f"Unknown method: {self.method}")
|
| 139 |
-
|
| 140 |
-
def get_running_train_loop(self):
|
| 141 |
-
try:
|
| 142 |
-
# Lazy import
|
| 143 |
-
from ...utils.train_loop import TrainLoop
|
| 144 |
-
|
| 145 |
-
return TrainLoop.get_running_loop()
|
| 146 |
-
except ImportError:
|
| 147 |
-
return None
|
| 148 |
-
|
| 149 |
-
@property
|
| 150 |
-
def visualizing(self):
|
| 151 |
-
loop = self.get_running_train_loop()
|
| 152 |
-
if loop is None:
|
| 153 |
-
return
|
| 154 |
-
out_path = loop.make_current_step_viz_path(self.viz_name, ".gif")
|
| 155 |
-
return loop.global_step % self.viz_every == 0 and not out_path.exists()
|
| 156 |
-
|
| 157 |
-
def _reset_camera(self):
|
| 158 |
-
try:
|
| 159 |
-
from celluloid import Camera
|
| 160 |
-
|
| 161 |
-
self._camera = Camera(plt.figure())
|
| 162 |
-
except:
|
| 163 |
-
pass
|
| 164 |
-
|
| 165 |
-
def _maybe_dump_camera(self):
|
| 166 |
-
camera = self._camera
|
| 167 |
-
loop = self.get_running_train_loop()
|
| 168 |
-
if camera is not None and loop is not None:
|
| 169 |
-
animation = camera.animate()
|
| 170 |
-
out_path = loop.make_current_step_viz_path(self.viz_name, ".gif")
|
| 171 |
-
out_path.parent.mkdir(exist_ok=True, parents=True)
|
| 172 |
-
animation.save(out_path, writer="pillow", fps=4)
|
| 173 |
-
plt.close()
|
| 174 |
-
self._camera = None
|
| 175 |
-
|
| 176 |
-
@property
|
| 177 |
-
def n_steps(self):
|
| 178 |
-
n = self.nfe
|
| 179 |
-
if self.method == "euler":
|
| 180 |
-
pass
|
| 181 |
-
elif self.method == "midpoint":
|
| 182 |
-
n //= 2
|
| 183 |
-
elif self.method == "rk4":
|
| 184 |
-
n //= 4
|
| 185 |
-
else:
|
| 186 |
-
raise ValueError(f"Unknown method: {self.method}")
|
| 187 |
-
return n
|
| 188 |
-
|
| 189 |
-
def solve(self, f: VelocityField, ψ0: Tensor, t0=0.0, t1=1.0):
|
| 190 |
-
ts = self._time_mapping(np.linspace(t0, t1, self.n_steps + 1))
|
| 191 |
-
|
| 192 |
-
if self.visualizing:
|
| 193 |
-
self._reset_camera()
|
| 194 |
-
|
| 195 |
-
if self.verbose:
|
| 196 |
-
steps = trange(self.n_steps, desc="CFM inference")
|
| 197 |
-
else:
|
| 198 |
-
steps = range(self.n_steps)
|
| 199 |
-
|
| 200 |
-
ψt = ψ0
|
| 201 |
-
|
| 202 |
-
for i in steps:
|
| 203 |
-
dt = ts[i + 1] - ts[i]
|
| 204 |
-
t = ts[i]
|
| 205 |
-
self._maybe_camera_snap(ψt=ψt, t=t)
|
| 206 |
-
ψt = self._step(t=t, ψt=ψt, dt=dt, f=f)
|
| 207 |
-
|
| 208 |
-
self._maybe_camera_snap(ψt=ψt, t=ts[-1])
|
| 209 |
-
|
| 210 |
-
ψ1 = ψt
|
| 211 |
-
del ψt
|
| 212 |
-
|
| 213 |
-
self._maybe_dump_camera()
|
| 214 |
-
|
| 215 |
-
return ψ1
|
| 216 |
-
|
| 217 |
-
def __call__(self, f: VelocityField, ψ0: Tensor, t0=0.0, t1=1.0):
|
| 218 |
-
return self.solve(f=f, ψ0=ψ0, t0=t0, t1=t1)
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
class SinusodialTimeEmbedding(nn.Module):
|
| 222 |
-
def __init__(self, d_embed):
|
| 223 |
-
super().__init__()
|
| 224 |
-
self.d_embed = d_embed
|
| 225 |
-
assert d_embed % 2 == 0
|
| 226 |
-
|
| 227 |
-
def forward(self, t):
|
| 228 |
-
t = t.unsqueeze(-1) # ... 1
|
| 229 |
-
p = torch.linspace(0, 4, self.d_embed // 2).to(t)
|
| 230 |
-
while p.dim() < t.dim():
|
| 231 |
-
p = p.unsqueeze(0) # ... d/2
|
| 232 |
-
sin = torch.sin(t * 10**p)
|
| 233 |
-
cos = torch.cos(t * 10**p)
|
| 234 |
-
return torch.cat([sin, cos], dim=-1)
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
@dataclass(eq=False)
|
| 238 |
-
class CFM(nn.Module):
|
| 239 |
-
"""
|
| 240 |
-
This mixin is for general diffusion models.
|
| 241 |
-
|
| 242 |
-
ψ0 stands for the gaussian noise, and ψ1 is the data point.
|
| 243 |
-
|
| 244 |
-
Here we follow the CFM style:
|
| 245 |
-
The generation process (reverse process) is from t=0 to t=1.
|
| 246 |
-
The forward process is from t=1 to t=0.
|
| 247 |
-
"""
|
| 248 |
-
|
| 249 |
-
cond_dim: int
|
| 250 |
-
output_dim: int
|
| 251 |
-
time_emb_dim: int = 128
|
| 252 |
-
viz_name: str = "cfm"
|
| 253 |
-
solver_nfe: int = 32
|
| 254 |
-
solver_method: str = "midpoint"
|
| 255 |
-
time_mapping_divisor: int = 4
|
| 256 |
-
|
| 257 |
-
def __post_init__(self):
|
| 258 |
-
super().__init__()
|
| 259 |
-
self.solver = Solver(
|
| 260 |
-
viz_name=self.viz_name,
|
| 261 |
-
viz_every=1,
|
| 262 |
-
nfe=self.solver_nfe,
|
| 263 |
-
method=self.solver_method,
|
| 264 |
-
time_mapping_divisor=self.time_mapping_divisor,
|
| 265 |
-
)
|
| 266 |
-
self.emb = SinusodialTimeEmbedding(self.time_emb_dim)
|
| 267 |
-
self.net = WN(
|
| 268 |
-
input_dim=self.output_dim,
|
| 269 |
-
output_dim=self.output_dim,
|
| 270 |
-
local_dim=self.cond_dim,
|
| 271 |
-
global_dim=self.time_emb_dim,
|
| 272 |
-
)
|
| 273 |
-
|
| 274 |
-
def _perturb(self, ψ1: Tensor, t: Tensor | None = None):
|
| 275 |
-
"""
|
| 276 |
-
Perturb ψ1 to ψt.
|
| 277 |
-
"""
|
| 278 |
-
raise NotImplementedError
|
| 279 |
-
|
| 280 |
-
def _sample_ψ0(self, x: Tensor):
|
| 281 |
-
"""
|
| 282 |
-
Args:
|
| 283 |
-
x: (b c t), which implies the shape of ψ0
|
| 284 |
-
"""
|
| 285 |
-
shape = list(x.shape)
|
| 286 |
-
shape[1] = self.output_dim
|
| 287 |
-
if self.training:
|
| 288 |
-
g = None
|
| 289 |
-
else:
|
| 290 |
-
g = torch.Generator(device=x.device)
|
| 291 |
-
g.manual_seed(0) # deterministic sampling during eval
|
| 292 |
-
ψ0 = torch.randn(shape, device=x.device, dtype=x.dtype, generator=g)
|
| 293 |
-
return ψ0
|
| 294 |
-
|
| 295 |
-
@property
|
| 296 |
-
def sigma(self):
|
| 297 |
-
return 1e-4
|
| 298 |
-
|
| 299 |
-
def _to_ψt(self, *, ψ1: Tensor, ψ0: Tensor, t: Tensor):
|
| 300 |
-
"""
|
| 301 |
-
Eq (22)
|
| 302 |
-
"""
|
| 303 |
-
while t.dim() < ψ1.dim():
|
| 304 |
-
t = t.unsqueeze(-1)
|
| 305 |
-
μ = t * ψ1 + (1 - t) * ψ0
|
| 306 |
-
return μ + torch.randn_like(μ) * self.sigma
|
| 307 |
-
|
| 308 |
-
def _to_u(self, *, ψ1, ψ0: Tensor):
|
| 309 |
-
"""
|
| 310 |
-
Eq (21)
|
| 311 |
-
"""
|
| 312 |
-
return ψ1 - ψ0
|
| 313 |
-
|
| 314 |
-
def _to_v(self, *, ψt, x, t: float | Tensor):
|
| 315 |
-
"""
|
| 316 |
-
Args:
|
| 317 |
-
ψt: (b c t)
|
| 318 |
-
x: (b c t)
|
| 319 |
-
t: (b)
|
| 320 |
-
Returns:
|
| 321 |
-
v: (b c t)
|
| 322 |
-
"""
|
| 323 |
-
if isinstance(t, (float, int)):
|
| 324 |
-
t = torch.full(ψt.shape[:1], t).to(ψt)
|
| 325 |
-
t = t.clamp(0, 1) # [0, 1)
|
| 326 |
-
g = self.emb(t) # (b d)
|
| 327 |
-
v = self.net(ψt, l=x, g=g)
|
| 328 |
-
return v
|
| 329 |
-
|
| 330 |
-
def compute_losses(self, x, y, ψ0) -> dict:
|
| 331 |
-
"""
|
| 332 |
-
Args:
|
| 333 |
-
x: (b c t)
|
| 334 |
-
y: (b c t)
|
| 335 |
-
Returns:
|
| 336 |
-
losses: dict
|
| 337 |
-
"""
|
| 338 |
-
t = torch.rand(len(x), device=x.device, dtype=x.dtype)
|
| 339 |
-
t = self.solver.time_mapping(t)
|
| 340 |
-
|
| 341 |
-
if ψ0 is None:
|
| 342 |
-
ψ0 = self._sample_ψ0(x)
|
| 343 |
-
|
| 344 |
-
ψt = self._to_ψt(ψ1=y, t=t, ψ0=ψ0)
|
| 345 |
-
|
| 346 |
-
v = self._to_v(ψt=ψt, t=t, x=x)
|
| 347 |
-
u = self._to_u(ψ1=y, ψ0=ψ0)
|
| 348 |
-
|
| 349 |
-
losses = dict(l1=F.l1_loss(v, u))
|
| 350 |
-
|
| 351 |
-
return losses
|
| 352 |
-
|
| 353 |
-
@torch.inference_mode()
|
| 354 |
-
def sample(self, x, ψ0=None, t0=0.0):
|
| 355 |
-
"""
|
| 356 |
-
Args:
|
| 357 |
-
x: (b c t)
|
| 358 |
-
Returns:
|
| 359 |
-
y: (b ... t)
|
| 360 |
-
"""
|
| 361 |
-
if ψ0 is None:
|
| 362 |
-
ψ0 = self._sample_ψ0(x)
|
| 363 |
-
f = lambda t, ψt, dt: self._to_v(ψt=ψt, t=t, x=x)
|
| 364 |
-
ψ1 = self.solver(f=f, ψ0=ψ0, t0=t0)
|
| 365 |
-
return ψ1
|
| 366 |
-
|
| 367 |
-
def forward(self, x: Tensor, y: Tensor | None = None, ψ0: Tensor | None = None, t0=0.0):
|
| 368 |
-
if y is None:
|
| 369 |
-
y = self.sample(x, ψ0=ψ0, t0=t0)
|
| 370 |
-
else:
|
| 371 |
-
self.losses = self.compute_losses(x, y, ψ0=ψ0)
|
| 372 |
-
return y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/lcfm/irmae.py
DELETED
|
@@ -1,123 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from dataclasses import dataclass
|
| 3 |
-
|
| 4 |
-
import torch.nn as nn
|
| 5 |
-
import torch.nn.functional as F
|
| 6 |
-
from torch import Tensor, nn
|
| 7 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 8 |
-
|
| 9 |
-
from ...common import Normalizer
|
| 10 |
-
|
| 11 |
-
logger = logging.getLogger(__name__)
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
@dataclass
|
| 15 |
-
class IRMAEOutput:
|
| 16 |
-
latent: Tensor # latent vector
|
| 17 |
-
decoded: Tensor | None # decoder output, include extra dim
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
class ResBlock(nn.Sequential):
|
| 21 |
-
def __init__(self, channels, dilations=[1, 2, 4, 8]):
|
| 22 |
-
wn = weight_norm
|
| 23 |
-
super().__init__(
|
| 24 |
-
nn.GroupNorm(32, channels),
|
| 25 |
-
nn.GELU(),
|
| 26 |
-
wn(nn.Conv1d(channels, channels, 3, padding="same", dilation=dilations[0])),
|
| 27 |
-
nn.GroupNorm(32, channels),
|
| 28 |
-
nn.GELU(),
|
| 29 |
-
wn(nn.Conv1d(channels, channels, 3, padding="same", dilation=dilations[1])),
|
| 30 |
-
nn.GroupNorm(32, channels),
|
| 31 |
-
nn.GELU(),
|
| 32 |
-
wn(nn.Conv1d(channels, channels, 3, padding="same", dilation=dilations[2])),
|
| 33 |
-
nn.GroupNorm(32, channels),
|
| 34 |
-
nn.GELU(),
|
| 35 |
-
wn(nn.Conv1d(channels, channels, 3, padding="same", dilation=dilations[3])),
|
| 36 |
-
)
|
| 37 |
-
|
| 38 |
-
def forward(self, x: Tensor):
|
| 39 |
-
return x + super().forward(x)
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
class IRMAE(nn.Module):
|
| 43 |
-
def __init__(
|
| 44 |
-
self,
|
| 45 |
-
input_dim,
|
| 46 |
-
output_dim,
|
| 47 |
-
latent_dim,
|
| 48 |
-
hidden_dim=1024,
|
| 49 |
-
num_irms=4,
|
| 50 |
-
):
|
| 51 |
-
"""
|
| 52 |
-
Args:
|
| 53 |
-
input_dim: input dimension
|
| 54 |
-
output_dim: output dimension
|
| 55 |
-
latent_dim: latent dimension
|
| 56 |
-
hidden_dim: hidden layer dimension
|
| 57 |
-
num_irm_matrics: number of implicit rank minimization matrices
|
| 58 |
-
norm: normalization layer
|
| 59 |
-
"""
|
| 60 |
-
self.input_dim = input_dim
|
| 61 |
-
super().__init__()
|
| 62 |
-
|
| 63 |
-
self.encoder = nn.Sequential(
|
| 64 |
-
nn.Conv1d(input_dim, hidden_dim, 3, padding="same"),
|
| 65 |
-
*[ResBlock(hidden_dim) for _ in range(4)],
|
| 66 |
-
# Try to obtain compact representation (https://proceedings.neurips.cc/paper/2020/file/a9078e8653368c9c291ae2f8b74012e7-Paper.pdf)
|
| 67 |
-
*[nn.Conv1d(hidden_dim if i == 0 else latent_dim, latent_dim, 1, bias=False) for i in range(num_irms)],
|
| 68 |
-
nn.Tanh(),
|
| 69 |
-
)
|
| 70 |
-
|
| 71 |
-
self.decoder = nn.Sequential(
|
| 72 |
-
nn.Conv1d(latent_dim, hidden_dim, 3, padding="same"),
|
| 73 |
-
*[ResBlock(hidden_dim) for _ in range(4)],
|
| 74 |
-
nn.Conv1d(hidden_dim, output_dim, 1),
|
| 75 |
-
)
|
| 76 |
-
|
| 77 |
-
self.head = nn.Sequential(
|
| 78 |
-
nn.Conv1d(output_dim, hidden_dim, 3, padding="same"),
|
| 79 |
-
nn.GELU(),
|
| 80 |
-
nn.Conv1d(hidden_dim, input_dim, 1),
|
| 81 |
-
)
|
| 82 |
-
|
| 83 |
-
self.estimator = Normalizer()
|
| 84 |
-
|
| 85 |
-
def encode(self, x):
|
| 86 |
-
"""
|
| 87 |
-
Args:
|
| 88 |
-
x: (b c t) tensor
|
| 89 |
-
"""
|
| 90 |
-
z = self.encoder(x) # (b c t)
|
| 91 |
-
_ = self.estimator(z) # Estimate the glboal mean and std of z
|
| 92 |
-
self.stats = {}
|
| 93 |
-
self.stats["z_mean"] = z.mean().item()
|
| 94 |
-
self.stats["z_std"] = z.std().item()
|
| 95 |
-
self.stats["z_abs_68"] = z.abs().quantile(0.6827).item()
|
| 96 |
-
self.stats["z_abs_95"] = z.abs().quantile(0.9545).item()
|
| 97 |
-
self.stats["z_abs_99"] = z.abs().quantile(0.9973).item()
|
| 98 |
-
return z
|
| 99 |
-
|
| 100 |
-
def decode(self, z):
|
| 101 |
-
"""
|
| 102 |
-
Args:
|
| 103 |
-
z: (b c t) tensor
|
| 104 |
-
"""
|
| 105 |
-
return self.decoder(z)
|
| 106 |
-
|
| 107 |
-
def forward(self, x, skip_decoding=False):
|
| 108 |
-
"""
|
| 109 |
-
Args:
|
| 110 |
-
x: (b c t) tensor
|
| 111 |
-
skip_decoding: if True, skip the decoding step
|
| 112 |
-
"""
|
| 113 |
-
z = self.encode(x) # q(z|x)
|
| 114 |
-
|
| 115 |
-
if skip_decoding:
|
| 116 |
-
# This speeds up the training in cfm only mode
|
| 117 |
-
decoded = None
|
| 118 |
-
else:
|
| 119 |
-
decoded = self.decode(z) # p(x|z)
|
| 120 |
-
predicted = self.head(decoded)
|
| 121 |
-
self.losses = dict(mse=F.mse_loss(predicted, x))
|
| 122 |
-
|
| 123 |
-
return IRMAEOutput(latent=z, decoded=decoded)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/lcfm/lcfm.py
DELETED
|
@@ -1,152 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from enum import Enum
|
| 3 |
-
|
| 4 |
-
import matplotlib.pyplot as plt
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn as nn
|
| 7 |
-
from torch import Tensor, nn
|
| 8 |
-
|
| 9 |
-
from .cfm import CFM
|
| 10 |
-
from .irmae import IRMAE, IRMAEOutput
|
| 11 |
-
|
| 12 |
-
logger = logging.getLogger(__name__)
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
def freeze_(module):
|
| 16 |
-
for p in module.parameters():
|
| 17 |
-
p.requires_grad_(False)
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
class LCFM(nn.Module):
|
| 21 |
-
class Mode(Enum):
|
| 22 |
-
AE = "ae"
|
| 23 |
-
CFM = "cfm"
|
| 24 |
-
|
| 25 |
-
def __init__(self, ae: IRMAE, cfm: CFM, z_scale: float = 1.0):
|
| 26 |
-
super().__init__()
|
| 27 |
-
self.ae = ae
|
| 28 |
-
self.cfm = cfm
|
| 29 |
-
self.z_scale = z_scale
|
| 30 |
-
self._mode = None
|
| 31 |
-
self._eval_tau = 0.5
|
| 32 |
-
|
| 33 |
-
@property
|
| 34 |
-
def mode(self):
|
| 35 |
-
return self._mode
|
| 36 |
-
|
| 37 |
-
def set_mode_(self, mode):
|
| 38 |
-
mode = self.Mode(mode)
|
| 39 |
-
self._mode = mode
|
| 40 |
-
|
| 41 |
-
if mode == mode.AE:
|
| 42 |
-
freeze_(self.cfm)
|
| 43 |
-
logger.info("Freeze cfm")
|
| 44 |
-
elif mode == mode.CFM:
|
| 45 |
-
freeze_(self.ae)
|
| 46 |
-
logger.info("Freeze ae (encoder and decoder)")
|
| 47 |
-
else:
|
| 48 |
-
raise ValueError(f"Unknown training mode: {mode}")
|
| 49 |
-
|
| 50 |
-
def get_running_train_loop(self):
|
| 51 |
-
try:
|
| 52 |
-
# Lazy import
|
| 53 |
-
from ...utils.train_loop import TrainLoop
|
| 54 |
-
|
| 55 |
-
return TrainLoop.get_running_loop()
|
| 56 |
-
except ImportError:
|
| 57 |
-
return None
|
| 58 |
-
|
| 59 |
-
@property
|
| 60 |
-
def global_step(self):
|
| 61 |
-
loop = self.get_running_train_loop()
|
| 62 |
-
if loop is None:
|
| 63 |
-
return None
|
| 64 |
-
return loop.global_step
|
| 65 |
-
|
| 66 |
-
@torch.no_grad()
|
| 67 |
-
def _visualize(self, x, y, y_):
|
| 68 |
-
loop = self.get_running_train_loop()
|
| 69 |
-
if loop is None:
|
| 70 |
-
return
|
| 71 |
-
|
| 72 |
-
plt.subplot(221)
|
| 73 |
-
plt.imshow(y[0].detach().cpu().numpy(), aspect="auto", origin="lower", interpolation="none")
|
| 74 |
-
plt.title("GT")
|
| 75 |
-
|
| 76 |
-
plt.subplot(222)
|
| 77 |
-
y_ = y_[:, : y.shape[1]]
|
| 78 |
-
plt.imshow(y_[0].detach().cpu().numpy(), aspect="auto", origin="lower", interpolation="none")
|
| 79 |
-
plt.title("Posterior")
|
| 80 |
-
|
| 81 |
-
plt.subplot(223)
|
| 82 |
-
z_ = self.cfm(x)
|
| 83 |
-
y__ = self.ae.decode(z_)
|
| 84 |
-
y__ = y__[:, : y.shape[1]]
|
| 85 |
-
plt.imshow(y__[0].detach().cpu().numpy(), aspect="auto", origin="lower", interpolation="none")
|
| 86 |
-
plt.title("C-Prior")
|
| 87 |
-
del y__
|
| 88 |
-
|
| 89 |
-
plt.subplot(224)
|
| 90 |
-
z_ = torch.randn_like(z_)
|
| 91 |
-
y__ = self.ae.decode(z_)
|
| 92 |
-
y__ = y__[:, : y.shape[1]]
|
| 93 |
-
plt.imshow(y__[0].detach().cpu().numpy(), aspect="auto", origin="lower", interpolation="none")
|
| 94 |
-
plt.title("Prior")
|
| 95 |
-
del z_, y__
|
| 96 |
-
|
| 97 |
-
path = loop.make_current_step_viz_path("recon", ".png")
|
| 98 |
-
path.parent.mkdir(exist_ok=True, parents=True)
|
| 99 |
-
plt.tight_layout()
|
| 100 |
-
plt.savefig(path, dpi=500)
|
| 101 |
-
plt.close()
|
| 102 |
-
|
| 103 |
-
def _scale(self, z: Tensor):
|
| 104 |
-
return z * self.z_scale
|
| 105 |
-
|
| 106 |
-
def _unscale(self, z: Tensor):
|
| 107 |
-
return z / self.z_scale
|
| 108 |
-
|
| 109 |
-
def eval_tau_(self, tau):
|
| 110 |
-
self._eval_tau = tau
|
| 111 |
-
|
| 112 |
-
def forward(self, x, y: Tensor | None = None, ψ0: Tensor | None = None):
|
| 113 |
-
"""
|
| 114 |
-
Args:
|
| 115 |
-
x: (b d t), condition mel
|
| 116 |
-
y: (b d t), target mel
|
| 117 |
-
ψ0: (b d t), starting mel
|
| 118 |
-
"""
|
| 119 |
-
if self.mode == self.Mode.CFM:
|
| 120 |
-
self.ae.eval() # Always set to eval when training cfm
|
| 121 |
-
|
| 122 |
-
if ψ0 is not None:
|
| 123 |
-
ψ0 = self._scale(self.ae.encode(ψ0))
|
| 124 |
-
if self.training:
|
| 125 |
-
tau = torch.rand_like(ψ0[:, :1, :1])
|
| 126 |
-
else:
|
| 127 |
-
tau = self._eval_tau
|
| 128 |
-
ψ0 = tau * torch.randn_like(ψ0) + (1 - tau) * ψ0
|
| 129 |
-
|
| 130 |
-
if y is None:
|
| 131 |
-
if self.mode == self.Mode.AE:
|
| 132 |
-
with torch.no_grad():
|
| 133 |
-
training = self.ae.training
|
| 134 |
-
self.ae.eval()
|
| 135 |
-
z = self.ae.encode(x)
|
| 136 |
-
self.ae.train(training)
|
| 137 |
-
else:
|
| 138 |
-
z = self._unscale(self.cfm(x, ψ0=ψ0))
|
| 139 |
-
|
| 140 |
-
h = self.ae.decode(z)
|
| 141 |
-
else:
|
| 142 |
-
ae_output: IRMAEOutput = self.ae(y, skip_decoding=self.mode == self.Mode.CFM)
|
| 143 |
-
|
| 144 |
-
if self.mode == self.Mode.CFM:
|
| 145 |
-
_ = self.cfm(x, self._scale(ae_output.latent.detach()), ψ0=ψ0)
|
| 146 |
-
|
| 147 |
-
h = ae_output.decoded
|
| 148 |
-
|
| 149 |
-
if h is not None and self.global_step is not None and self.global_step % 100 == 0:
|
| 150 |
-
self._visualize(x[:1], y[:1], h[:1])
|
| 151 |
-
|
| 152 |
-
return h
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/lcfm/wn.py
DELETED
|
@@ -1,147 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import math
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
import torch.nn as nn
|
| 6 |
-
|
| 7 |
-
logger = logging.getLogger(__name__)
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
@torch.jit.script
|
| 11 |
-
def _fused_tanh_sigmoid(h):
|
| 12 |
-
a, b = h.chunk(2, dim=1)
|
| 13 |
-
h = a.tanh() * b.sigmoid()
|
| 14 |
-
return h
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
class WNLayer(nn.Module):
|
| 18 |
-
"""
|
| 19 |
-
A DiffWave-like WN
|
| 20 |
-
"""
|
| 21 |
-
|
| 22 |
-
def __init__(self, hidden_dim, local_dim, global_dim, kernel_size, dilation):
|
| 23 |
-
super().__init__()
|
| 24 |
-
|
| 25 |
-
local_output_dim = hidden_dim * 2
|
| 26 |
-
|
| 27 |
-
if global_dim is not None:
|
| 28 |
-
self.gconv = nn.Conv1d(global_dim, hidden_dim, 1)
|
| 29 |
-
|
| 30 |
-
if local_dim is not None:
|
| 31 |
-
self.lconv = nn.Conv1d(local_dim, local_output_dim, 1)
|
| 32 |
-
|
| 33 |
-
self.dconv = nn.Conv1d(hidden_dim, local_output_dim, kernel_size, dilation=dilation, padding="same")
|
| 34 |
-
|
| 35 |
-
self.out = nn.Conv1d(hidden_dim, 2 * hidden_dim, kernel_size=1)
|
| 36 |
-
|
| 37 |
-
def forward(self, z, l, g):
|
| 38 |
-
identity = z
|
| 39 |
-
|
| 40 |
-
if g is not None:
|
| 41 |
-
if g.dim() == 2:
|
| 42 |
-
g = g.unsqueeze(-1)
|
| 43 |
-
z = z + self.gconv(g)
|
| 44 |
-
|
| 45 |
-
z = self.dconv(z)
|
| 46 |
-
|
| 47 |
-
if l is not None:
|
| 48 |
-
z = z + self.lconv(l)
|
| 49 |
-
|
| 50 |
-
z = _fused_tanh_sigmoid(z)
|
| 51 |
-
|
| 52 |
-
h = self.out(z)
|
| 53 |
-
|
| 54 |
-
z, s = h.chunk(2, dim=1)
|
| 55 |
-
|
| 56 |
-
o = (z + identity) / math.sqrt(2)
|
| 57 |
-
|
| 58 |
-
return o, s
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
class WN(nn.Module):
|
| 62 |
-
def __init__(
|
| 63 |
-
self,
|
| 64 |
-
input_dim,
|
| 65 |
-
output_dim,
|
| 66 |
-
local_dim=None,
|
| 67 |
-
global_dim=None,
|
| 68 |
-
n_layers=30,
|
| 69 |
-
kernel_size=3,
|
| 70 |
-
dilation_cycle=5,
|
| 71 |
-
hidden_dim=512,
|
| 72 |
-
):
|
| 73 |
-
super().__init__()
|
| 74 |
-
assert kernel_size % 2 == 1
|
| 75 |
-
assert hidden_dim % 2 == 0
|
| 76 |
-
|
| 77 |
-
self.input_dim = input_dim
|
| 78 |
-
self.hidden_dim = hidden_dim
|
| 79 |
-
self.local_dim = local_dim
|
| 80 |
-
self.global_dim = global_dim
|
| 81 |
-
|
| 82 |
-
self.start = nn.Conv1d(input_dim, hidden_dim, 1)
|
| 83 |
-
if local_dim is not None:
|
| 84 |
-
self.local_norm = nn.InstanceNorm1d(local_dim)
|
| 85 |
-
|
| 86 |
-
self.layers = nn.ModuleList(
|
| 87 |
-
[
|
| 88 |
-
WNLayer(
|
| 89 |
-
hidden_dim=hidden_dim,
|
| 90 |
-
local_dim=local_dim,
|
| 91 |
-
global_dim=global_dim,
|
| 92 |
-
kernel_size=kernel_size,
|
| 93 |
-
dilation=2 ** (i % dilation_cycle),
|
| 94 |
-
)
|
| 95 |
-
for i in range(n_layers)
|
| 96 |
-
]
|
| 97 |
-
)
|
| 98 |
-
|
| 99 |
-
self.end = nn.Conv1d(hidden_dim, output_dim, 1)
|
| 100 |
-
|
| 101 |
-
def forward(self, z, l=None, g=None):
|
| 102 |
-
"""
|
| 103 |
-
Args:
|
| 104 |
-
z: input (b c t)
|
| 105 |
-
l: local condition (b c t)
|
| 106 |
-
g: global condition (b d)
|
| 107 |
-
"""
|
| 108 |
-
z = self.start(z)
|
| 109 |
-
|
| 110 |
-
if l is not None:
|
| 111 |
-
l = self.local_norm(l)
|
| 112 |
-
|
| 113 |
-
# Skips
|
| 114 |
-
s_list = []
|
| 115 |
-
|
| 116 |
-
for layer in self.layers:
|
| 117 |
-
z, s = layer(z, l, g)
|
| 118 |
-
s_list.append(s)
|
| 119 |
-
|
| 120 |
-
s_list = torch.stack(s_list, dim=0).sum(dim=0)
|
| 121 |
-
s_list = s_list / math.sqrt(len(self.layers))
|
| 122 |
-
|
| 123 |
-
o = self.end(s_list)
|
| 124 |
-
|
| 125 |
-
return o
|
| 126 |
-
|
| 127 |
-
def summarize(self, length=100):
|
| 128 |
-
from ptflops import get_model_complexity_info
|
| 129 |
-
|
| 130 |
-
x = torch.randn(1, self.input_dim, length)
|
| 131 |
-
|
| 132 |
-
macs, params = get_model_complexity_info(
|
| 133 |
-
self,
|
| 134 |
-
(self.input_dim, length),
|
| 135 |
-
as_strings=True,
|
| 136 |
-
print_per_layer_stat=True,
|
| 137 |
-
verbose=True,
|
| 138 |
-
)
|
| 139 |
-
|
| 140 |
-
print(f"Input shape: {x.shape}")
|
| 141 |
-
print(f"Computational complexity: {macs}")
|
| 142 |
-
print(f"Number of parameters: {params}")
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
if __name__ == "__main__":
|
| 146 |
-
model = WN(input_dim=64, output_dim=64)
|
| 147 |
-
model.summarize()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/train.py
DELETED
|
@@ -1,143 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
import random
|
| 3 |
-
from functools import partial
|
| 4 |
-
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
import soundfile
|
| 7 |
-
import torch
|
| 8 |
-
from deepspeed import DeepSpeedConfig
|
| 9 |
-
from torch import Tensor
|
| 10 |
-
from tqdm import tqdm
|
| 11 |
-
|
| 12 |
-
from ..data import create_dataloaders, mix_fg_bg
|
| 13 |
-
from ..utils import Engine, TrainLoop, save_mels, setup_logging, tree_map
|
| 14 |
-
from ..utils.distributed import is_local_leader
|
| 15 |
-
from .enhancer import Enhancer
|
| 16 |
-
from .hparams import HParams
|
| 17 |
-
from .univnet.discriminator import Discriminator
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def load_G(run_dir: Path, hp: HParams | None = None, training=True):
|
| 21 |
-
if hp is None:
|
| 22 |
-
hp = HParams.load(run_dir)
|
| 23 |
-
assert isinstance(hp, HParams)
|
| 24 |
-
model = Enhancer(hp)
|
| 25 |
-
engine = Engine(model=model, config_class=DeepSpeedConfig(hp.deepspeed_config), ckpt_dir=run_dir / "ds" / "G")
|
| 26 |
-
if training:
|
| 27 |
-
engine.load_checkpoint()
|
| 28 |
-
else:
|
| 29 |
-
engine.load_checkpoint(load_optimizer_states=False, load_lr_scheduler_states=False)
|
| 30 |
-
return engine
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
def load_D(run_dir: Path, hp: HParams):
|
| 34 |
-
if hp is None:
|
| 35 |
-
hp = HParams.load(run_dir)
|
| 36 |
-
assert isinstance(hp, HParams)
|
| 37 |
-
model = Discriminator(hp)
|
| 38 |
-
engine = Engine(model=model, config_class=DeepSpeedConfig(hp.deepspeed_config), ckpt_dir=run_dir / "ds" / "D")
|
| 39 |
-
engine.load_checkpoint()
|
| 40 |
-
return engine
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
def save_wav(path: Path, wav: Tensor, rate: int):
|
| 44 |
-
wav = wav.detach().cpu().numpy()
|
| 45 |
-
soundfile.write(path, wav, samplerate=rate)
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def main():
|
| 49 |
-
parser = argparse.ArgumentParser()
|
| 50 |
-
parser.add_argument("run_dir", type=Path)
|
| 51 |
-
parser.add_argument("--yaml", type=Path, default=None)
|
| 52 |
-
parser.add_argument("--device", type=str, default="cuda")
|
| 53 |
-
args = parser.parse_args()
|
| 54 |
-
|
| 55 |
-
setup_logging(args.run_dir)
|
| 56 |
-
hp = HParams.load(args.run_dir, yaml=args.yaml)
|
| 57 |
-
|
| 58 |
-
if is_local_leader():
|
| 59 |
-
hp.save_if_not_exists(args.run_dir)
|
| 60 |
-
hp.print()
|
| 61 |
-
|
| 62 |
-
train_dl, val_dl = create_dataloaders(hp, mode="enhancer")
|
| 63 |
-
|
| 64 |
-
def feed_G(engine: Engine, batch: dict[str, Tensor]):
|
| 65 |
-
if hp.lcfm_training_mode == "ae":
|
| 66 |
-
pred = engine(batch["fg_wavs"], batch["fg_wavs"])
|
| 67 |
-
elif hp.lcfm_training_mode == "cfm":
|
| 68 |
-
alpha_fn = lambda: random.uniform(*hp.mix_alpha_range)
|
| 69 |
-
mx_dwavs = mix_fg_bg(batch["fg_dwavs"], batch["bg_dwavs"], alpha=alpha_fn)
|
| 70 |
-
pred = engine(mx_dwavs, batch["fg_wavs"], batch["fg_dwavs"])
|
| 71 |
-
else:
|
| 72 |
-
raise ValueError(f"Unknown training mode: {hp.lcfm_training_mode}")
|
| 73 |
-
losses = engine.gather_attribute("losses")
|
| 74 |
-
return pred, losses
|
| 75 |
-
|
| 76 |
-
def feed_D(engine: Engine, batch: dict | None, fake: Tensor):
|
| 77 |
-
if batch is None:
|
| 78 |
-
losses = engine(fake=fake)
|
| 79 |
-
else:
|
| 80 |
-
losses = engine(fake=fake, real=batch["fg_wavs"])
|
| 81 |
-
return losses
|
| 82 |
-
|
| 83 |
-
@torch.no_grad()
|
| 84 |
-
def eval_fn(engine: Engine, eval_dir, n_saved=10):
|
| 85 |
-
assert isinstance(hp, HParams)
|
| 86 |
-
|
| 87 |
-
model = engine.module
|
| 88 |
-
model.eval()
|
| 89 |
-
|
| 90 |
-
step = engine.global_step
|
| 91 |
-
|
| 92 |
-
for i, batch in enumerate(tqdm(val_dl), 1):
|
| 93 |
-
batch = tree_map(lambda x: x.to(args.device) if isinstance(x, Tensor) else x, batch)
|
| 94 |
-
|
| 95 |
-
fg_wavs = batch["fg_wavs"] # 1 t
|
| 96 |
-
|
| 97 |
-
if hp.lcfm_training_mode == "ae":
|
| 98 |
-
in_dwavs = fg_wavs
|
| 99 |
-
elif hp.lcfm_training_mode == "cfm":
|
| 100 |
-
in_dwavs = mix_fg_bg(fg_wavs, batch["bg_dwavs"])
|
| 101 |
-
else:
|
| 102 |
-
raise ValueError(f"Unknown training mode: {hp.lcfm_training_mode}")
|
| 103 |
-
|
| 104 |
-
pred_fg_wavs = model(in_dwavs) # 1 t
|
| 105 |
-
|
| 106 |
-
in_mels = model.to_mel(in_dwavs) # 1 c t
|
| 107 |
-
fg_mels = model.to_mel(fg_wavs) # 1 c t
|
| 108 |
-
pred_fg_mels = model.to_mel(pred_fg_wavs) # 1 c t
|
| 109 |
-
|
| 110 |
-
rate = model.hp.wav_rate
|
| 111 |
-
get_path = lambda suffix: eval_dir / f"step_{step:08}_{i:03}{suffix}"
|
| 112 |
-
|
| 113 |
-
save_wav(get_path("_input.wav"), in_dwavs[0], rate=rate)
|
| 114 |
-
save_wav(get_path("_predict.wav"), pred_fg_wavs[0], rate=rate)
|
| 115 |
-
save_wav(get_path("_target.wav"), fg_wavs[0], rate=rate)
|
| 116 |
-
|
| 117 |
-
save_mels(
|
| 118 |
-
get_path(".png"),
|
| 119 |
-
cond_mel=in_mels[0].cpu().numpy(),
|
| 120 |
-
pred_mel=pred_fg_mels[0].cpu().numpy(),
|
| 121 |
-
targ_mel=fg_mels[0].cpu().numpy(),
|
| 122 |
-
)
|
| 123 |
-
|
| 124 |
-
if i >= n_saved:
|
| 125 |
-
break
|
| 126 |
-
|
| 127 |
-
train_loop = TrainLoop(
|
| 128 |
-
run_dir=args.run_dir,
|
| 129 |
-
train_dl=train_dl,
|
| 130 |
-
load_G=partial(load_G, hp=hp),
|
| 131 |
-
load_D=partial(load_D, hp=hp),
|
| 132 |
-
device=args.device,
|
| 133 |
-
feed_G=feed_G,
|
| 134 |
-
feed_D=feed_D,
|
| 135 |
-
eval_fn=eval_fn,
|
| 136 |
-
gan_training_start_step=hp.gan_training_start_step,
|
| 137 |
-
)
|
| 138 |
-
|
| 139 |
-
train_loop.run(max_steps=hp.max_steps)
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
if __name__ == "__main__":
|
| 143 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
from .univnet import UnivNet
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/alias_free_torch/__init__.py
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
# Adapted from https://github.com/junjun3518/alias-free-torch under the Apache License 2.0
|
| 2 |
-
# LICENSE is in incl_licenses directory.
|
| 3 |
-
|
| 4 |
-
from .filter import *
|
| 5 |
-
from .resample import *
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/alias_free_torch/filter.py
DELETED
|
@@ -1,95 +0,0 @@
|
|
| 1 |
-
# Adapted from https://github.com/junjun3518/alias-free-torch under the Apache License 2.0
|
| 2 |
-
# LICENSE is in incl_licenses directory.
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
import torch.nn as nn
|
| 6 |
-
import torch.nn.functional as F
|
| 7 |
-
import math
|
| 8 |
-
|
| 9 |
-
if 'sinc' in dir(torch):
|
| 10 |
-
sinc = torch.sinc
|
| 11 |
-
else:
|
| 12 |
-
# This code is adopted from adefossez's julius.core.sinc under the MIT License
|
| 13 |
-
# https://adefossez.github.io/julius/julius/core.html
|
| 14 |
-
# LICENSE is in incl_licenses directory.
|
| 15 |
-
def sinc(x: torch.Tensor):
|
| 16 |
-
"""
|
| 17 |
-
Implementation of sinc, i.e. sin(pi * x) / (pi * x)
|
| 18 |
-
__Warning__: Different to julius.sinc, the input is multiplied by `pi`!
|
| 19 |
-
"""
|
| 20 |
-
return torch.where(x == 0,
|
| 21 |
-
torch.tensor(1., device=x.device, dtype=x.dtype),
|
| 22 |
-
torch.sin(math.pi * x) / math.pi / x)
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
# This code is adopted from adefossez's julius.lowpass.LowPassFilters under the MIT License
|
| 26 |
-
# https://adefossez.github.io/julius/julius/lowpass.html
|
| 27 |
-
# LICENSE is in incl_licenses directory.
|
| 28 |
-
def kaiser_sinc_filter1d(cutoff, half_width, kernel_size): # return filter [1,1,kernel_size]
|
| 29 |
-
even = (kernel_size % 2 == 0)
|
| 30 |
-
half_size = kernel_size // 2
|
| 31 |
-
|
| 32 |
-
#For kaiser window
|
| 33 |
-
delta_f = 4 * half_width
|
| 34 |
-
A = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
|
| 35 |
-
if A > 50.:
|
| 36 |
-
beta = 0.1102 * (A - 8.7)
|
| 37 |
-
elif A >= 21.:
|
| 38 |
-
beta = 0.5842 * (A - 21)**0.4 + 0.07886 * (A - 21.)
|
| 39 |
-
else:
|
| 40 |
-
beta = 0.
|
| 41 |
-
window = torch.kaiser_window(kernel_size, beta=beta, periodic=False)
|
| 42 |
-
|
| 43 |
-
# ratio = 0.5/cutoff -> 2 * cutoff = 1 / ratio
|
| 44 |
-
if even:
|
| 45 |
-
time = (torch.arange(-half_size, half_size) + 0.5)
|
| 46 |
-
else:
|
| 47 |
-
time = torch.arange(kernel_size) - half_size
|
| 48 |
-
if cutoff == 0:
|
| 49 |
-
filter_ = torch.zeros_like(time)
|
| 50 |
-
else:
|
| 51 |
-
filter_ = 2 * cutoff * window * sinc(2 * cutoff * time)
|
| 52 |
-
# Normalize filter to have sum = 1, otherwise we will have a small leakage
|
| 53 |
-
# of the constant component in the input signal.
|
| 54 |
-
filter_ /= filter_.sum()
|
| 55 |
-
filter = filter_.view(1, 1, kernel_size)
|
| 56 |
-
|
| 57 |
-
return filter
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
class LowPassFilter1d(nn.Module):
|
| 61 |
-
def __init__(self,
|
| 62 |
-
cutoff=0.5,
|
| 63 |
-
half_width=0.6,
|
| 64 |
-
stride: int = 1,
|
| 65 |
-
padding: bool = True,
|
| 66 |
-
padding_mode: str = 'replicate',
|
| 67 |
-
kernel_size: int = 12):
|
| 68 |
-
# kernel_size should be even number for stylegan3 setup,
|
| 69 |
-
# in this implementation, odd number is also possible.
|
| 70 |
-
super().__init__()
|
| 71 |
-
if cutoff < -0.:
|
| 72 |
-
raise ValueError("Minimum cutoff must be larger than zero.")
|
| 73 |
-
if cutoff > 0.5:
|
| 74 |
-
raise ValueError("A cutoff above 0.5 does not make sense.")
|
| 75 |
-
self.kernel_size = kernel_size
|
| 76 |
-
self.even = (kernel_size % 2 == 0)
|
| 77 |
-
self.pad_left = kernel_size // 2 - int(self.even)
|
| 78 |
-
self.pad_right = kernel_size // 2
|
| 79 |
-
self.stride = stride
|
| 80 |
-
self.padding = padding
|
| 81 |
-
self.padding_mode = padding_mode
|
| 82 |
-
filter = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
|
| 83 |
-
self.register_buffer("filter", filter)
|
| 84 |
-
|
| 85 |
-
#input [B, C, T]
|
| 86 |
-
def forward(self, x):
|
| 87 |
-
_, C, _ = x.shape
|
| 88 |
-
|
| 89 |
-
if self.padding:
|
| 90 |
-
x = F.pad(x, (self.pad_left, self.pad_right),
|
| 91 |
-
mode=self.padding_mode)
|
| 92 |
-
out = F.conv1d(x, self.filter.expand(C, -1, -1),
|
| 93 |
-
stride=self.stride, groups=C)
|
| 94 |
-
|
| 95 |
-
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/alias_free_torch/resample.py
DELETED
|
@@ -1,49 +0,0 @@
|
|
| 1 |
-
# Adapted from https://github.com/junjun3518/alias-free-torch under the Apache License 2.0
|
| 2 |
-
# LICENSE is in incl_licenses directory.
|
| 3 |
-
|
| 4 |
-
import torch.nn as nn
|
| 5 |
-
from torch.nn import functional as F
|
| 6 |
-
from .filter import LowPassFilter1d
|
| 7 |
-
from .filter import kaiser_sinc_filter1d
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
class UpSample1d(nn.Module):
|
| 11 |
-
def __init__(self, ratio=2, kernel_size=None):
|
| 12 |
-
super().__init__()
|
| 13 |
-
self.ratio = ratio
|
| 14 |
-
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
|
| 15 |
-
self.stride = ratio
|
| 16 |
-
self.pad = self.kernel_size // ratio - 1
|
| 17 |
-
self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
|
| 18 |
-
self.pad_right = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
|
| 19 |
-
filter = kaiser_sinc_filter1d(cutoff=0.5 / ratio,
|
| 20 |
-
half_width=0.6 / ratio,
|
| 21 |
-
kernel_size=self.kernel_size)
|
| 22 |
-
self.register_buffer("filter", filter)
|
| 23 |
-
|
| 24 |
-
# x: [B, C, T]
|
| 25 |
-
def forward(self, x):
|
| 26 |
-
_, C, _ = x.shape
|
| 27 |
-
|
| 28 |
-
x = F.pad(x, (self.pad, self.pad), mode='replicate')
|
| 29 |
-
x = self.ratio * F.conv_transpose1d(
|
| 30 |
-
x, self.filter.expand(C, -1, -1), stride=self.stride, groups=C)
|
| 31 |
-
x = x[..., self.pad_left:-self.pad_right]
|
| 32 |
-
|
| 33 |
-
return x
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
class DownSample1d(nn.Module):
|
| 37 |
-
def __init__(self, ratio=2, kernel_size=None):
|
| 38 |
-
super().__init__()
|
| 39 |
-
self.ratio = ratio
|
| 40 |
-
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
|
| 41 |
-
self.lowpass = LowPassFilter1d(cutoff=0.5 / ratio,
|
| 42 |
-
half_width=0.6 / ratio,
|
| 43 |
-
stride=ratio,
|
| 44 |
-
kernel_size=self.kernel_size)
|
| 45 |
-
|
| 46 |
-
def forward(self, x):
|
| 47 |
-
xx = self.lowpass(x)
|
| 48 |
-
|
| 49 |
-
return xx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/amp.py
DELETED
|
@@ -1,101 +0,0 @@
|
|
| 1 |
-
# Refer from https://github.com/NVIDIA/BigVGAN
|
| 2 |
-
|
| 3 |
-
import math
|
| 4 |
-
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn as nn
|
| 7 |
-
from torch import nn
|
| 8 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 9 |
-
|
| 10 |
-
from .alias_free_torch import DownSample1d, UpSample1d
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
class SnakeBeta(nn.Module):
|
| 14 |
-
"""
|
| 15 |
-
A modified Snake function which uses separate parameters for the magnitude of the periodic components
|
| 16 |
-
Shape:
|
| 17 |
-
- Input: (B, C, T)
|
| 18 |
-
- Output: (B, C, T), same shape as the input
|
| 19 |
-
Parameters:
|
| 20 |
-
- alpha - trainable parameter that controls frequency
|
| 21 |
-
- beta - trainable parameter that controls magnitude
|
| 22 |
-
References:
|
| 23 |
-
- This activation function is a modified version based on this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
|
| 24 |
-
https://arxiv.org/abs/2006.08195
|
| 25 |
-
Examples:
|
| 26 |
-
>>> a1 = snakebeta(256)
|
| 27 |
-
>>> x = torch.randn(256)
|
| 28 |
-
>>> x = a1(x)
|
| 29 |
-
"""
|
| 30 |
-
|
| 31 |
-
def __init__(self, in_features, alpha=1.0, clamp=(1e-2, 50)):
|
| 32 |
-
"""
|
| 33 |
-
Initialization.
|
| 34 |
-
INPUT:
|
| 35 |
-
- in_features: shape of the input
|
| 36 |
-
- alpha - trainable parameter that controls frequency
|
| 37 |
-
- beta - trainable parameter that controls magnitude
|
| 38 |
-
alpha is initialized to 1 by default, higher values = higher-frequency.
|
| 39 |
-
beta is initialized to 1 by default, higher values = higher-magnitude.
|
| 40 |
-
alpha will be trained along with the rest of your model.
|
| 41 |
-
"""
|
| 42 |
-
super().__init__()
|
| 43 |
-
self.in_features = in_features
|
| 44 |
-
self.log_alpha = nn.Parameter(torch.zeros(in_features) + math.log(alpha))
|
| 45 |
-
self.log_beta = nn.Parameter(torch.zeros(in_features) + math.log(alpha))
|
| 46 |
-
self.clamp = clamp
|
| 47 |
-
|
| 48 |
-
def forward(self, x):
|
| 49 |
-
"""
|
| 50 |
-
Forward pass of the function.
|
| 51 |
-
Applies the function to the input elementwise.
|
| 52 |
-
SnakeBeta ∶= x + 1/b * sin^2 (xa)
|
| 53 |
-
"""
|
| 54 |
-
alpha = self.log_alpha.exp().clamp(*self.clamp)
|
| 55 |
-
alpha = alpha[None, :, None]
|
| 56 |
-
|
| 57 |
-
beta = self.log_beta.exp().clamp(*self.clamp)
|
| 58 |
-
beta = beta[None, :, None]
|
| 59 |
-
|
| 60 |
-
x = x + (1.0 / beta) * (x * alpha).sin().pow(2)
|
| 61 |
-
|
| 62 |
-
return x
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
class UpActDown(nn.Module):
|
| 66 |
-
def __init__(
|
| 67 |
-
self,
|
| 68 |
-
act,
|
| 69 |
-
up_ratio: int = 2,
|
| 70 |
-
down_ratio: int = 2,
|
| 71 |
-
up_kernel_size: int = 12,
|
| 72 |
-
down_kernel_size: int = 12,
|
| 73 |
-
):
|
| 74 |
-
super().__init__()
|
| 75 |
-
self.up_ratio = up_ratio
|
| 76 |
-
self.down_ratio = down_ratio
|
| 77 |
-
self.act = act
|
| 78 |
-
self.upsample = UpSample1d(up_ratio, up_kernel_size)
|
| 79 |
-
self.downsample = DownSample1d(down_ratio, down_kernel_size)
|
| 80 |
-
|
| 81 |
-
def forward(self, x):
|
| 82 |
-
# x: [B,C,T]
|
| 83 |
-
x = self.upsample(x)
|
| 84 |
-
x = self.act(x)
|
| 85 |
-
x = self.downsample(x)
|
| 86 |
-
return x
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
class AMPBlock(nn.Sequential):
|
| 90 |
-
def __init__(self, channels, *, kernel_size=3, dilations=(1, 3, 5)):
|
| 91 |
-
super().__init__(*(self._make_layer(channels, kernel_size, d) for d in dilations))
|
| 92 |
-
|
| 93 |
-
def _make_layer(self, channels, kernel_size, dilation):
|
| 94 |
-
return nn.Sequential(
|
| 95 |
-
weight_norm(nn.Conv1d(channels, channels, kernel_size, dilation=dilation, padding="same")),
|
| 96 |
-
UpActDown(act=SnakeBeta(channels)),
|
| 97 |
-
weight_norm(nn.Conv1d(channels, channels, kernel_size, padding="same")),
|
| 98 |
-
)
|
| 99 |
-
|
| 100 |
-
def forward(self, x):
|
| 101 |
-
return x + super().forward(x)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/discriminator.py
DELETED
|
@@ -1,210 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
import torch.nn.functional as F
|
| 5 |
-
from torch import Tensor, nn
|
| 6 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 7 |
-
|
| 8 |
-
from ..hparams import HParams
|
| 9 |
-
from .mrstft import get_stft_cfgs
|
| 10 |
-
|
| 11 |
-
logger = logging.getLogger(__name__)
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
class PeriodNetwork(nn.Module):
|
| 15 |
-
def __init__(self, period):
|
| 16 |
-
super().__init__()
|
| 17 |
-
self.period = period
|
| 18 |
-
wn = weight_norm
|
| 19 |
-
self.convs = nn.ModuleList(
|
| 20 |
-
[
|
| 21 |
-
wn(nn.Conv2d(1, 64, (5, 1), (3, 1), padding=(2, 0))),
|
| 22 |
-
wn(nn.Conv2d(64, 128, (5, 1), (3, 1), padding=(2, 0))),
|
| 23 |
-
wn(nn.Conv2d(128, 256, (5, 1), (3, 1), padding=(2, 0))),
|
| 24 |
-
wn(nn.Conv2d(256, 512, (5, 1), (3, 1), padding=(2, 0))),
|
| 25 |
-
wn(nn.Conv2d(512, 1024, (5, 1), 1, padding=(2, 0))),
|
| 26 |
-
]
|
| 27 |
-
)
|
| 28 |
-
self.conv_post = wn(nn.Conv2d(1024, 1, (3, 1), 1, padding=(1, 0)))
|
| 29 |
-
|
| 30 |
-
def forward(self, x):
|
| 31 |
-
"""
|
| 32 |
-
Args:
|
| 33 |
-
x: [B, 1, T]
|
| 34 |
-
"""
|
| 35 |
-
assert x.dim() == 3, f"(B, 1, T) is expected, but got {x.shape}."
|
| 36 |
-
|
| 37 |
-
# 1d to 2d
|
| 38 |
-
b, c, t = x.shape
|
| 39 |
-
if t % self.period != 0: # pad first
|
| 40 |
-
n_pad = self.period - (t % self.period)
|
| 41 |
-
x = F.pad(x, (0, n_pad), "reflect")
|
| 42 |
-
t = t + n_pad
|
| 43 |
-
x = x.view(b, c, t // self.period, self.period)
|
| 44 |
-
|
| 45 |
-
for l in self.convs:
|
| 46 |
-
x = l(x)
|
| 47 |
-
x = F.leaky_relu(x, 0.2)
|
| 48 |
-
x = self.conv_post(x)
|
| 49 |
-
x = torch.flatten(x, 1, -1)
|
| 50 |
-
|
| 51 |
-
return x
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
class SpecNetwork(nn.Module):
|
| 55 |
-
def __init__(self, stft_cfg: dict):
|
| 56 |
-
super().__init__()
|
| 57 |
-
wn = weight_norm
|
| 58 |
-
self.stft_cfg = stft_cfg
|
| 59 |
-
self.convs = nn.ModuleList(
|
| 60 |
-
[
|
| 61 |
-
wn(nn.Conv2d(1, 32, (3, 9), padding=(1, 4))),
|
| 62 |
-
wn(nn.Conv2d(32, 32, (3, 9), stride=(1, 2), padding=(1, 4))),
|
| 63 |
-
wn(nn.Conv2d(32, 32, (3, 9), stride=(1, 2), padding=(1, 4))),
|
| 64 |
-
wn(nn.Conv2d(32, 32, (3, 9), stride=(1, 2), padding=(1, 4))),
|
| 65 |
-
wn(nn.Conv2d(32, 32, (3, 3), padding=(1, 1))),
|
| 66 |
-
]
|
| 67 |
-
)
|
| 68 |
-
self.conv_post = wn(nn.Conv2d(32, 1, (3, 3), padding=(1, 1)))
|
| 69 |
-
|
| 70 |
-
def forward(self, x):
|
| 71 |
-
"""
|
| 72 |
-
Args:
|
| 73 |
-
x: [B, 1, T]
|
| 74 |
-
"""
|
| 75 |
-
x = self.spectrogram(x)
|
| 76 |
-
x = x.unsqueeze(1)
|
| 77 |
-
for l in self.convs:
|
| 78 |
-
x = l(x)
|
| 79 |
-
x = F.leaky_relu(x, 0.2)
|
| 80 |
-
x = self.conv_post(x)
|
| 81 |
-
x = x.flatten(1, -1)
|
| 82 |
-
return x
|
| 83 |
-
|
| 84 |
-
def spectrogram(self, x):
|
| 85 |
-
"""
|
| 86 |
-
Args:
|
| 87 |
-
x: [B, 1, T]
|
| 88 |
-
"""
|
| 89 |
-
x = x.squeeze(1)
|
| 90 |
-
dtype = x.dtype
|
| 91 |
-
stft_cfg = dict(self.stft_cfg)
|
| 92 |
-
x = torch.stft(x.float(), center=False, return_complex=False, **stft_cfg)
|
| 93 |
-
mag = x.norm(p=2, dim=-1) # [B, F, TT]
|
| 94 |
-
mag = mag.to(dtype) # [B, F, TT]
|
| 95 |
-
return mag
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
class MD(nn.ModuleList):
|
| 99 |
-
def __init__(self, l: list):
|
| 100 |
-
super().__init__([self._create_network(x) for x in l])
|
| 101 |
-
self._loss_type = None
|
| 102 |
-
|
| 103 |
-
def loss_type_(self, loss_type):
|
| 104 |
-
self._loss_type = loss_type
|
| 105 |
-
|
| 106 |
-
def _create_network(self, _):
|
| 107 |
-
raise NotImplementedError
|
| 108 |
-
|
| 109 |
-
def _forward_each(self, d, x, y):
|
| 110 |
-
assert self._loss_type is not None, "loss_type is not set."
|
| 111 |
-
loss_type = self._loss_type
|
| 112 |
-
|
| 113 |
-
if loss_type == "hinge":
|
| 114 |
-
if y == 0:
|
| 115 |
-
# d(x) should be small -> -1
|
| 116 |
-
loss = F.relu(1 + d(x)).mean()
|
| 117 |
-
elif y == 1:
|
| 118 |
-
# d(x) should be large -> 1
|
| 119 |
-
loss = F.relu(1 - d(x)).mean()
|
| 120 |
-
else:
|
| 121 |
-
raise ValueError(f"Invalid y: {y}")
|
| 122 |
-
elif loss_type == "wgan":
|
| 123 |
-
if y == 0:
|
| 124 |
-
loss = d(x).mean()
|
| 125 |
-
elif y == 1:
|
| 126 |
-
loss = -d(x).mean()
|
| 127 |
-
else:
|
| 128 |
-
raise ValueError(f"Invalid y: {y}")
|
| 129 |
-
else:
|
| 130 |
-
raise ValueError(f"Invalid loss_type: {loss_type}")
|
| 131 |
-
|
| 132 |
-
return loss
|
| 133 |
-
|
| 134 |
-
def forward(self, x, y) -> Tensor:
|
| 135 |
-
losses = [self._forward_each(d, x, y) for d in self]
|
| 136 |
-
return torch.stack(losses).mean()
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
class MPD(MD):
|
| 140 |
-
def __init__(self):
|
| 141 |
-
super().__init__([2, 3, 7, 13, 17])
|
| 142 |
-
|
| 143 |
-
def _create_network(self, period):
|
| 144 |
-
return PeriodNetwork(period)
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
class MRD(MD):
|
| 148 |
-
def __init__(self, stft_cfgs):
|
| 149 |
-
super().__init__(stft_cfgs)
|
| 150 |
-
|
| 151 |
-
def _create_network(self, stft_cfg):
|
| 152 |
-
return SpecNetwork(stft_cfg)
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
class Discriminator(nn.Module):
|
| 156 |
-
@property
|
| 157 |
-
def wav_rate(self):
|
| 158 |
-
return self.hp.wav_rate
|
| 159 |
-
|
| 160 |
-
def __init__(self, hp: HParams):
|
| 161 |
-
super().__init__()
|
| 162 |
-
self.hp = hp
|
| 163 |
-
self.stft_cfgs = get_stft_cfgs(hp)
|
| 164 |
-
self.mpd = MPD()
|
| 165 |
-
self.mrd = MRD(self.stft_cfgs)
|
| 166 |
-
self.dummy_float: Tensor
|
| 167 |
-
self.register_buffer("dummy_float", torch.zeros(0), persistent=False)
|
| 168 |
-
|
| 169 |
-
def loss_type_(self, loss_type):
|
| 170 |
-
self.mpd.loss_type_(loss_type)
|
| 171 |
-
self.mrd.loss_type_(loss_type)
|
| 172 |
-
|
| 173 |
-
def forward(self, fake, real=None):
|
| 174 |
-
"""
|
| 175 |
-
Args:
|
| 176 |
-
fake: [B T]
|
| 177 |
-
real: [B T]
|
| 178 |
-
"""
|
| 179 |
-
fake = fake.to(self.dummy_float)
|
| 180 |
-
|
| 181 |
-
if real is None:
|
| 182 |
-
self.loss_type_("wgan")
|
| 183 |
-
else:
|
| 184 |
-
length_difference = (fake.shape[-1] - real.shape[-1]) / real.shape[-1]
|
| 185 |
-
assert length_difference < 0.05, f"length_difference should be smaller than 5%"
|
| 186 |
-
|
| 187 |
-
self.loss_type_("hinge")
|
| 188 |
-
real = real.to(self.dummy_float)
|
| 189 |
-
|
| 190 |
-
fake = fake[..., : real.shape[-1]]
|
| 191 |
-
real = real[..., : fake.shape[-1]]
|
| 192 |
-
|
| 193 |
-
losses = {}
|
| 194 |
-
|
| 195 |
-
assert fake.dim() == 2, f"(B, T) is expected, but got {fake.shape}."
|
| 196 |
-
assert real is None or real.dim() == 2, f"(B, T) is expected, but got {real.shape}."
|
| 197 |
-
|
| 198 |
-
fake = fake.unsqueeze(1)
|
| 199 |
-
|
| 200 |
-
if real is None:
|
| 201 |
-
losses["mpd"] = self.mpd(fake, 1)
|
| 202 |
-
losses["mrd"] = self.mrd(fake, 1)
|
| 203 |
-
else:
|
| 204 |
-
real = real.unsqueeze(1)
|
| 205 |
-
losses["mpd_fake"] = self.mpd(fake, 0)
|
| 206 |
-
losses["mpd_real"] = self.mpd(real, 1)
|
| 207 |
-
losses["mrd_fake"] = self.mrd(fake, 0)
|
| 208 |
-
losses["mrd_real"] = self.mrd(real, 1)
|
| 209 |
-
|
| 210 |
-
return losses
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/lvcnet.py
DELETED
|
@@ -1,281 +0,0 @@
|
|
| 1 |
-
""" refer from https://github.com/zceng/LVCNet """
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
import torch.nn as nn
|
| 5 |
-
import torch.nn.functional as F
|
| 6 |
-
from torch import nn
|
| 7 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 8 |
-
|
| 9 |
-
from .amp import AMPBlock
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
class KernelPredictor(torch.nn.Module):
|
| 13 |
-
"""Kernel predictor for the location-variable convolutions"""
|
| 14 |
-
|
| 15 |
-
def __init__(
|
| 16 |
-
self,
|
| 17 |
-
cond_channels,
|
| 18 |
-
conv_in_channels,
|
| 19 |
-
conv_out_channels,
|
| 20 |
-
conv_layers,
|
| 21 |
-
conv_kernel_size=3,
|
| 22 |
-
kpnet_hidden_channels=64,
|
| 23 |
-
kpnet_conv_size=3,
|
| 24 |
-
kpnet_dropout=0.0,
|
| 25 |
-
kpnet_nonlinear_activation="LeakyReLU",
|
| 26 |
-
kpnet_nonlinear_activation_params={"negative_slope": 0.1},
|
| 27 |
-
):
|
| 28 |
-
"""
|
| 29 |
-
Args:
|
| 30 |
-
cond_channels (int): number of channel for the conditioning sequence,
|
| 31 |
-
conv_in_channels (int): number of channel for the input sequence,
|
| 32 |
-
conv_out_channels (int): number of channel for the output sequence,
|
| 33 |
-
conv_layers (int): number of layers
|
| 34 |
-
"""
|
| 35 |
-
super().__init__()
|
| 36 |
-
|
| 37 |
-
self.conv_in_channels = conv_in_channels
|
| 38 |
-
self.conv_out_channels = conv_out_channels
|
| 39 |
-
self.conv_kernel_size = conv_kernel_size
|
| 40 |
-
self.conv_layers = conv_layers
|
| 41 |
-
|
| 42 |
-
kpnet_kernel_channels = conv_in_channels * conv_out_channels * conv_kernel_size * conv_layers # l_w
|
| 43 |
-
kpnet_bias_channels = conv_out_channels * conv_layers # l_b
|
| 44 |
-
|
| 45 |
-
self.input_conv = nn.Sequential(
|
| 46 |
-
weight_norm(nn.Conv1d(cond_channels, kpnet_hidden_channels, 5, padding=2, bias=True)),
|
| 47 |
-
getattr(nn, kpnet_nonlinear_activation)(**kpnet_nonlinear_activation_params),
|
| 48 |
-
)
|
| 49 |
-
|
| 50 |
-
self.residual_convs = nn.ModuleList()
|
| 51 |
-
padding = (kpnet_conv_size - 1) // 2
|
| 52 |
-
for _ in range(3):
|
| 53 |
-
self.residual_convs.append(
|
| 54 |
-
nn.Sequential(
|
| 55 |
-
nn.Dropout(kpnet_dropout),
|
| 56 |
-
weight_norm(
|
| 57 |
-
nn.Conv1d(
|
| 58 |
-
kpnet_hidden_channels,
|
| 59 |
-
kpnet_hidden_channels,
|
| 60 |
-
kpnet_conv_size,
|
| 61 |
-
padding=padding,
|
| 62 |
-
bias=True,
|
| 63 |
-
)
|
| 64 |
-
),
|
| 65 |
-
getattr(nn, kpnet_nonlinear_activation)(**kpnet_nonlinear_activation_params),
|
| 66 |
-
weight_norm(
|
| 67 |
-
nn.Conv1d(
|
| 68 |
-
kpnet_hidden_channels,
|
| 69 |
-
kpnet_hidden_channels,
|
| 70 |
-
kpnet_conv_size,
|
| 71 |
-
padding=padding,
|
| 72 |
-
bias=True,
|
| 73 |
-
)
|
| 74 |
-
),
|
| 75 |
-
getattr(nn, kpnet_nonlinear_activation)(**kpnet_nonlinear_activation_params),
|
| 76 |
-
)
|
| 77 |
-
)
|
| 78 |
-
self.kernel_conv = weight_norm(
|
| 79 |
-
nn.Conv1d(
|
| 80 |
-
kpnet_hidden_channels,
|
| 81 |
-
kpnet_kernel_channels,
|
| 82 |
-
kpnet_conv_size,
|
| 83 |
-
padding=padding,
|
| 84 |
-
bias=True,
|
| 85 |
-
)
|
| 86 |
-
)
|
| 87 |
-
self.bias_conv = weight_norm(
|
| 88 |
-
nn.Conv1d(
|
| 89 |
-
kpnet_hidden_channels,
|
| 90 |
-
kpnet_bias_channels,
|
| 91 |
-
kpnet_conv_size,
|
| 92 |
-
padding=padding,
|
| 93 |
-
bias=True,
|
| 94 |
-
)
|
| 95 |
-
)
|
| 96 |
-
|
| 97 |
-
def forward(self, c):
|
| 98 |
-
"""
|
| 99 |
-
Args:
|
| 100 |
-
c (Tensor): the conditioning sequence (batch, cond_channels, cond_length)
|
| 101 |
-
"""
|
| 102 |
-
batch, _, cond_length = c.shape
|
| 103 |
-
c = self.input_conv(c)
|
| 104 |
-
for residual_conv in self.residual_convs:
|
| 105 |
-
residual_conv.to(c.device)
|
| 106 |
-
c = c + residual_conv(c)
|
| 107 |
-
k = self.kernel_conv(c)
|
| 108 |
-
b = self.bias_conv(c)
|
| 109 |
-
kernels = k.contiguous().view(
|
| 110 |
-
batch,
|
| 111 |
-
self.conv_layers,
|
| 112 |
-
self.conv_in_channels,
|
| 113 |
-
self.conv_out_channels,
|
| 114 |
-
self.conv_kernel_size,
|
| 115 |
-
cond_length,
|
| 116 |
-
)
|
| 117 |
-
bias = b.contiguous().view(
|
| 118 |
-
batch,
|
| 119 |
-
self.conv_layers,
|
| 120 |
-
self.conv_out_channels,
|
| 121 |
-
cond_length,
|
| 122 |
-
)
|
| 123 |
-
|
| 124 |
-
return kernels, bias
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
class LVCBlock(torch.nn.Module):
|
| 128 |
-
"""the location-variable convolutions"""
|
| 129 |
-
|
| 130 |
-
def __init__(
|
| 131 |
-
self,
|
| 132 |
-
in_channels,
|
| 133 |
-
cond_channels,
|
| 134 |
-
stride,
|
| 135 |
-
dilations=[1, 3, 9, 27],
|
| 136 |
-
lReLU_slope=0.2,
|
| 137 |
-
conv_kernel_size=3,
|
| 138 |
-
cond_hop_length=256,
|
| 139 |
-
kpnet_hidden_channels=64,
|
| 140 |
-
kpnet_conv_size=3,
|
| 141 |
-
kpnet_dropout=0.0,
|
| 142 |
-
add_extra_noise=False,
|
| 143 |
-
downsampling=False,
|
| 144 |
-
):
|
| 145 |
-
super().__init__()
|
| 146 |
-
|
| 147 |
-
self.add_extra_noise = add_extra_noise
|
| 148 |
-
|
| 149 |
-
self.cond_hop_length = cond_hop_length
|
| 150 |
-
self.conv_layers = len(dilations)
|
| 151 |
-
self.conv_kernel_size = conv_kernel_size
|
| 152 |
-
|
| 153 |
-
self.kernel_predictor = KernelPredictor(
|
| 154 |
-
cond_channels=cond_channels,
|
| 155 |
-
conv_in_channels=in_channels,
|
| 156 |
-
conv_out_channels=2 * in_channels,
|
| 157 |
-
conv_layers=len(dilations),
|
| 158 |
-
conv_kernel_size=conv_kernel_size,
|
| 159 |
-
kpnet_hidden_channels=kpnet_hidden_channels,
|
| 160 |
-
kpnet_conv_size=kpnet_conv_size,
|
| 161 |
-
kpnet_dropout=kpnet_dropout,
|
| 162 |
-
kpnet_nonlinear_activation_params={"negative_slope": lReLU_slope},
|
| 163 |
-
)
|
| 164 |
-
|
| 165 |
-
if downsampling:
|
| 166 |
-
self.convt_pre = nn.Sequential(
|
| 167 |
-
nn.LeakyReLU(lReLU_slope),
|
| 168 |
-
weight_norm(nn.Conv1d(in_channels, in_channels, 2 * stride + 1, padding="same")),
|
| 169 |
-
nn.AvgPool1d(stride, stride),
|
| 170 |
-
)
|
| 171 |
-
else:
|
| 172 |
-
if stride == 1:
|
| 173 |
-
self.convt_pre = nn.Sequential(
|
| 174 |
-
nn.LeakyReLU(lReLU_slope),
|
| 175 |
-
weight_norm(nn.Conv1d(in_channels, in_channels, 1)),
|
| 176 |
-
)
|
| 177 |
-
else:
|
| 178 |
-
self.convt_pre = nn.Sequential(
|
| 179 |
-
nn.LeakyReLU(lReLU_slope),
|
| 180 |
-
weight_norm(
|
| 181 |
-
nn.ConvTranspose1d(
|
| 182 |
-
in_channels,
|
| 183 |
-
in_channels,
|
| 184 |
-
2 * stride,
|
| 185 |
-
stride=stride,
|
| 186 |
-
padding=stride // 2 + stride % 2,
|
| 187 |
-
output_padding=stride % 2,
|
| 188 |
-
)
|
| 189 |
-
),
|
| 190 |
-
)
|
| 191 |
-
|
| 192 |
-
self.amp_block = AMPBlock(in_channels)
|
| 193 |
-
|
| 194 |
-
self.conv_blocks = nn.ModuleList()
|
| 195 |
-
for d in dilations:
|
| 196 |
-
self.conv_blocks.append(
|
| 197 |
-
nn.Sequential(
|
| 198 |
-
nn.LeakyReLU(lReLU_slope),
|
| 199 |
-
weight_norm(nn.Conv1d(in_channels, in_channels, conv_kernel_size, dilation=d, padding="same")),
|
| 200 |
-
nn.LeakyReLU(lReLU_slope),
|
| 201 |
-
)
|
| 202 |
-
)
|
| 203 |
-
|
| 204 |
-
def forward(self, x, c):
|
| 205 |
-
"""forward propagation of the location-variable convolutions.
|
| 206 |
-
Args:
|
| 207 |
-
x (Tensor): the input sequence (batch, in_channels, in_length)
|
| 208 |
-
c (Tensor): the conditioning sequence (batch, cond_channels, cond_length)
|
| 209 |
-
|
| 210 |
-
Returns:
|
| 211 |
-
Tensor: the output sequence (batch, in_channels, in_length)
|
| 212 |
-
"""
|
| 213 |
-
_, in_channels, _ = x.shape # (B, c_g, L')
|
| 214 |
-
|
| 215 |
-
x = self.convt_pre(x) # (B, c_g, stride * L')
|
| 216 |
-
|
| 217 |
-
# Add one amp block just after the upsampling
|
| 218 |
-
x = self.amp_block(x) # (B, c_g, stride * L')
|
| 219 |
-
|
| 220 |
-
kernels, bias = self.kernel_predictor(c)
|
| 221 |
-
|
| 222 |
-
if self.add_extra_noise:
|
| 223 |
-
# Add extra noise to part of the feature
|
| 224 |
-
a, b = x.chunk(2, dim=1)
|
| 225 |
-
b = b + torch.randn_like(b) * 0.1
|
| 226 |
-
x = torch.cat([a, b], dim=1)
|
| 227 |
-
|
| 228 |
-
for i, conv in enumerate(self.conv_blocks):
|
| 229 |
-
output = conv(x) # (B, c_g, stride * L')
|
| 230 |
-
|
| 231 |
-
k = kernels[:, i, :, :, :, :] # (B, 2 * c_g, c_g, kernel_size, cond_length)
|
| 232 |
-
b = bias[:, i, :, :] # (B, 2 * c_g, cond_length)
|
| 233 |
-
|
| 234 |
-
output = self.location_variable_convolution(
|
| 235 |
-
output, k, b, hop_size=self.cond_hop_length
|
| 236 |
-
) # (B, 2 * c_g, stride * L'): LVC
|
| 237 |
-
x = x + torch.sigmoid(output[:, :in_channels, :]) * torch.tanh(
|
| 238 |
-
output[:, in_channels:, :]
|
| 239 |
-
) # (B, c_g, stride * L'): GAU
|
| 240 |
-
|
| 241 |
-
return x
|
| 242 |
-
|
| 243 |
-
def location_variable_convolution(self, x, kernel, bias, dilation=1, hop_size=256):
|
| 244 |
-
"""perform location-variable convolution operation on the input sequence (x) using the local convolution kernl.
|
| 245 |
-
Time: 414 μs ± 309 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each), test on NVIDIA V100.
|
| 246 |
-
Args:
|
| 247 |
-
x (Tensor): the input sequence (batch, in_channels, in_length).
|
| 248 |
-
kernel (Tensor): the local convolution kernel (batch, in_channel, out_channels, kernel_size, kernel_length)
|
| 249 |
-
bias (Tensor): the bias for the local convolution (batch, out_channels, kernel_length)
|
| 250 |
-
dilation (int): the dilation of convolution.
|
| 251 |
-
hop_size (int): the hop_size of the conditioning sequence.
|
| 252 |
-
Returns:
|
| 253 |
-
(Tensor): the output sequence after performing local convolution. (batch, out_channels, in_length).
|
| 254 |
-
"""
|
| 255 |
-
batch, _, in_length = x.shape
|
| 256 |
-
batch, _, out_channels, kernel_size, kernel_length = kernel.shape
|
| 257 |
-
|
| 258 |
-
assert in_length == (
|
| 259 |
-
kernel_length * hop_size
|
| 260 |
-
), f"length of (x, kernel) is not matched, {in_length} != {kernel_length} * {hop_size}"
|
| 261 |
-
|
| 262 |
-
padding = dilation * int((kernel_size - 1) / 2)
|
| 263 |
-
x = F.pad(x, (padding, padding), "constant", 0) # (batch, in_channels, in_length + 2*padding)
|
| 264 |
-
x = x.unfold(2, hop_size + 2 * padding, hop_size) # (batch, in_channels, kernel_length, hop_size + 2*padding)
|
| 265 |
-
|
| 266 |
-
if hop_size < dilation:
|
| 267 |
-
x = F.pad(x, (0, dilation), "constant", 0)
|
| 268 |
-
x = x.unfold(
|
| 269 |
-
3, dilation, dilation
|
| 270 |
-
) # (batch, in_channels, kernel_length, (hop_size + 2*padding)/dilation, dilation)
|
| 271 |
-
x = x[:, :, :, :, :hop_size]
|
| 272 |
-
x = x.transpose(3, 4) # (batch, in_channels, kernel_length, dilation, (hop_size + 2*padding)/dilation)
|
| 273 |
-
x = x.unfold(4, kernel_size, 1) # (batch, in_channels, kernel_length, dilation, _, kernel_size)
|
| 274 |
-
|
| 275 |
-
o = torch.einsum("bildsk,biokl->bolsd", x, kernel)
|
| 276 |
-
o = o.to(memory_format=torch.channels_last_3d)
|
| 277 |
-
bias = bias.unsqueeze(-1).unsqueeze(-1).to(memory_format=torch.channels_last_3d)
|
| 278 |
-
o = o + bias
|
| 279 |
-
o = o.contiguous().view(batch, out_channels, -1)
|
| 280 |
-
|
| 281 |
-
return o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/mrstft.py
DELETED
|
@@ -1,128 +0,0 @@
|
|
| 1 |
-
# -*- coding: utf-8 -*-
|
| 2 |
-
|
| 3 |
-
# Copyright 2019 Tomoki Hayashi
|
| 4 |
-
# MIT License (https://opensource.org/licenses/MIT)
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
import torch
|
| 8 |
-
import torch.nn.functional as F
|
| 9 |
-
from torch import nn
|
| 10 |
-
|
| 11 |
-
from ..hparams import HParams
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def _make_stft_cfg(hop_length, win_length=None):
|
| 15 |
-
if win_length is None:
|
| 16 |
-
win_length = 4 * hop_length
|
| 17 |
-
n_fft = 2 ** (win_length - 1).bit_length()
|
| 18 |
-
return dict(n_fft=n_fft, hop_length=hop_length, win_length=win_length)
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
def get_stft_cfgs(hp: HParams):
|
| 22 |
-
assert hp.wav_rate == 44100, f"wav_rate must be 44100, got {hp.wav_rate}"
|
| 23 |
-
return [_make_stft_cfg(h) for h in (100, 256, 512)]
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
def stft(x, n_fft, hop_length, win_length, window):
|
| 27 |
-
dtype = x.dtype
|
| 28 |
-
x = torch.stft(x.float(), n_fft, hop_length, win_length, window, return_complex=True)
|
| 29 |
-
x = x.abs().to(dtype)
|
| 30 |
-
x = x.transpose(2, 1) # (b f t) -> (b t f)
|
| 31 |
-
return x
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
class SpectralConvergengeLoss(nn.Module):
|
| 35 |
-
def forward(self, x_mag, y_mag):
|
| 36 |
-
"""Calculate forward propagation.
|
| 37 |
-
Args:
|
| 38 |
-
x_mag (Tensor): Magnitude spectrogram of predicted signal (B, #frames, #freq_bins).
|
| 39 |
-
y_mag (Tensor): Magnitude spectrogram of groundtruth signal (B, #frames, #freq_bins).
|
| 40 |
-
Returns:
|
| 41 |
-
Tensor: Spectral convergence loss value.
|
| 42 |
-
"""
|
| 43 |
-
return torch.norm(y_mag - x_mag, p="fro") / torch.norm(y_mag, p="fro")
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
class LogSTFTMagnitudeLoss(nn.Module):
|
| 47 |
-
def forward(self, x_mag, y_mag):
|
| 48 |
-
"""Calculate forward propagation.
|
| 49 |
-
Args:
|
| 50 |
-
x_mag (Tensor): Magnitude spectrogram of predicted signal (B, #frames, #freq_bins).
|
| 51 |
-
y_mag (Tensor): Magnitude spectrogram of groundtruth signal (B, #frames, #freq_bins).
|
| 52 |
-
Returns:
|
| 53 |
-
Tensor: Log STFT magnitude loss value.
|
| 54 |
-
"""
|
| 55 |
-
return F.l1_loss(torch.log1p(x_mag), torch.log1p(y_mag))
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
class STFTLoss(nn.Module):
|
| 59 |
-
def __init__(self, hp, stft_cfg: dict, window="hann_window"):
|
| 60 |
-
super().__init__()
|
| 61 |
-
self.hp = hp
|
| 62 |
-
self.stft_cfg = stft_cfg
|
| 63 |
-
self.spectral_convergenge_loss = SpectralConvergengeLoss()
|
| 64 |
-
self.log_stft_magnitude_loss = LogSTFTMagnitudeLoss()
|
| 65 |
-
self.register_buffer("window", getattr(torch, window)(stft_cfg["win_length"]), persistent=False)
|
| 66 |
-
|
| 67 |
-
def forward(self, x, y):
|
| 68 |
-
"""Calculate forward propagation.
|
| 69 |
-
Args:
|
| 70 |
-
x (Tensor): Predicted signal (B, T).
|
| 71 |
-
y (Tensor): Groundtruth signal (B, T).
|
| 72 |
-
Returns:
|
| 73 |
-
Tensor: Spectral convergence loss value.
|
| 74 |
-
Tensor: Log STFT magnitude loss value.
|
| 75 |
-
"""
|
| 76 |
-
stft_cfg = dict(self.stft_cfg)
|
| 77 |
-
x_mag = stft(x, **stft_cfg, window=self.window) # (b t) -> (b t f)
|
| 78 |
-
y_mag = stft(y, **stft_cfg, window=self.window)
|
| 79 |
-
sc_loss = self.spectral_convergenge_loss(x_mag, y_mag)
|
| 80 |
-
mag_loss = self.log_stft_magnitude_loss(x_mag, y_mag)
|
| 81 |
-
return dict(sc=sc_loss, mag=mag_loss)
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
class MRSTFTLoss(nn.Module):
|
| 85 |
-
def __init__(self, hp: HParams, window="hann_window"):
|
| 86 |
-
"""Initialize Multi resolution STFT loss module.
|
| 87 |
-
Args:
|
| 88 |
-
resolutions (list): List of (FFT size, hop size, window length).
|
| 89 |
-
window (str): Window function type.
|
| 90 |
-
"""
|
| 91 |
-
super().__init__()
|
| 92 |
-
stft_cfgs = get_stft_cfgs(hp)
|
| 93 |
-
self.stft_losses = nn.ModuleList()
|
| 94 |
-
self.hp = hp
|
| 95 |
-
for c in stft_cfgs:
|
| 96 |
-
self.stft_losses += [STFTLoss(hp, c, window=window)]
|
| 97 |
-
|
| 98 |
-
def forward(self, x, y):
|
| 99 |
-
"""Calculate forward propagation.
|
| 100 |
-
Args:
|
| 101 |
-
x (Tensor): Predicted signal (b t).
|
| 102 |
-
y (Tensor): Groundtruth signal (b t).
|
| 103 |
-
Returns:
|
| 104 |
-
Tensor: Multi resolution spectral convergence loss value.
|
| 105 |
-
Tensor: Multi resolution log STFT magnitude loss value.
|
| 106 |
-
"""
|
| 107 |
-
assert x.dim() == 2 and y.dim() == 2, f"(b t) is expected, but got {x.shape} and {y.shape}."
|
| 108 |
-
|
| 109 |
-
dtype = x.dtype
|
| 110 |
-
|
| 111 |
-
x = x.float()
|
| 112 |
-
y = y.float()
|
| 113 |
-
|
| 114 |
-
# Align length
|
| 115 |
-
x = x[..., : y.shape[-1]]
|
| 116 |
-
y = y[..., : x.shape[-1]]
|
| 117 |
-
|
| 118 |
-
losses = {}
|
| 119 |
-
|
| 120 |
-
for f in self.stft_losses:
|
| 121 |
-
d = f(x, y)
|
| 122 |
-
for k, v in d.items():
|
| 123 |
-
losses.setdefault(k, []).append(v)
|
| 124 |
-
|
| 125 |
-
for k, v in losses.items():
|
| 126 |
-
losses[k] = torch.stack(v, dim=0).mean().to(dtype)
|
| 127 |
-
|
| 128 |
-
return losses
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/enhancer/univnet/univnet.py
DELETED
|
@@ -1,94 +0,0 @@
|
|
| 1 |
-
import numpy as np
|
| 2 |
-
import torch
|
| 3 |
-
import torch.nn.functional as F
|
| 4 |
-
from torch import Tensor, nn
|
| 5 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 6 |
-
|
| 7 |
-
from ..hparams import HParams
|
| 8 |
-
from .lvcnet import LVCBlock
|
| 9 |
-
from .mrstft import MRSTFTLoss
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
class UnivNet(nn.Module):
|
| 13 |
-
@property
|
| 14 |
-
def d_noise(self):
|
| 15 |
-
return 128
|
| 16 |
-
|
| 17 |
-
@property
|
| 18 |
-
def strides(self):
|
| 19 |
-
return [7, 5, 4, 3]
|
| 20 |
-
|
| 21 |
-
@property
|
| 22 |
-
def dilations(self):
|
| 23 |
-
return [1, 3, 9, 27]
|
| 24 |
-
|
| 25 |
-
@property
|
| 26 |
-
def nc(self):
|
| 27 |
-
return self.hp.univnet_nc
|
| 28 |
-
|
| 29 |
-
@property
|
| 30 |
-
def scale_factor(self) -> int:
|
| 31 |
-
return self.hp.hop_size
|
| 32 |
-
|
| 33 |
-
def __init__(self, hp: HParams, d_input):
|
| 34 |
-
super().__init__()
|
| 35 |
-
self.d_input = d_input
|
| 36 |
-
|
| 37 |
-
self.hp = hp
|
| 38 |
-
|
| 39 |
-
self.blocks = nn.ModuleList(
|
| 40 |
-
[
|
| 41 |
-
LVCBlock(
|
| 42 |
-
self.nc,
|
| 43 |
-
d_input,
|
| 44 |
-
stride=stride,
|
| 45 |
-
dilations=self.dilations,
|
| 46 |
-
cond_hop_length=hop_length,
|
| 47 |
-
kpnet_conv_size=3,
|
| 48 |
-
)
|
| 49 |
-
for stride, hop_length in zip(self.strides, np.cumprod(self.strides))
|
| 50 |
-
]
|
| 51 |
-
)
|
| 52 |
-
|
| 53 |
-
self.conv_pre = weight_norm(nn.Conv1d(self.d_noise, self.nc, 7, padding=3, padding_mode="reflect"))
|
| 54 |
-
|
| 55 |
-
self.conv_post = nn.Sequential(
|
| 56 |
-
nn.LeakyReLU(0.2),
|
| 57 |
-
weight_norm(nn.Conv1d(self.nc, 1, 7, padding=3, padding_mode="reflect")),
|
| 58 |
-
nn.Tanh(),
|
| 59 |
-
)
|
| 60 |
-
|
| 61 |
-
self.mrstft = MRSTFTLoss(hp)
|
| 62 |
-
|
| 63 |
-
@property
|
| 64 |
-
def eps(self):
|
| 65 |
-
return 1e-5
|
| 66 |
-
|
| 67 |
-
def forward(self, x: Tensor, y: Tensor | None = None, npad=10):
|
| 68 |
-
"""
|
| 69 |
-
Args:
|
| 70 |
-
x: (b c t), acoustic features
|
| 71 |
-
y: (b t), waveform
|
| 72 |
-
Returns:
|
| 73 |
-
z: (b t), waveform
|
| 74 |
-
"""
|
| 75 |
-
assert x.ndim == 3, "x must be 3D tensor"
|
| 76 |
-
assert y is None or y.ndim == 2, "y must be 2D tensor"
|
| 77 |
-
assert x.shape[1] == self.d_input, f"x.shape[1] must be {self.d_input}, but got {x.shape}"
|
| 78 |
-
assert npad >= 0, "npad must be positive or zero"
|
| 79 |
-
|
| 80 |
-
x = F.pad(x, (0, npad), "constant", 0)
|
| 81 |
-
z = torch.randn(x.shape[0], self.d_noise, x.shape[2]).to(x)
|
| 82 |
-
z = self.conv_pre(z) # (b c t)
|
| 83 |
-
|
| 84 |
-
for block in self.blocks:
|
| 85 |
-
z = block(z, x) # (b c t)
|
| 86 |
-
|
| 87 |
-
z = self.conv_post(z) # (b 1 t)
|
| 88 |
-
z = z[..., : -self.scale_factor * npad]
|
| 89 |
-
z = z.squeeze(1) # (b t)
|
| 90 |
-
|
| 91 |
-
if y is not None:
|
| 92 |
-
self.losses = self.mrstft(z, y)
|
| 93 |
-
|
| 94 |
-
return z
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/hparams.py
DELETED
|
@@ -1,128 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from dataclasses import asdict, dataclass
|
| 3 |
-
from pathlib import Path
|
| 4 |
-
|
| 5 |
-
from omegaconf import OmegaConf
|
| 6 |
-
from rich.console import Console
|
| 7 |
-
from rich.panel import Panel
|
| 8 |
-
from rich.table import Table
|
| 9 |
-
|
| 10 |
-
logger = logging.getLogger(__name__)
|
| 11 |
-
|
| 12 |
-
console = Console()
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
def _make_stft_cfg(hop_length, win_length=None):
|
| 16 |
-
if win_length is None:
|
| 17 |
-
win_length = 4 * hop_length
|
| 18 |
-
n_fft = 2 ** (win_length - 1).bit_length()
|
| 19 |
-
return dict(n_fft=n_fft, hop_length=hop_length, win_length=win_length)
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def _build_rich_table(rows, columns, title=None):
|
| 23 |
-
table = Table(title=title, header_style=None)
|
| 24 |
-
for column in columns:
|
| 25 |
-
table.add_column(column.capitalize(), justify="left")
|
| 26 |
-
for row in rows:
|
| 27 |
-
table.add_row(*map(str, row))
|
| 28 |
-
return Panel(table, expand=False)
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
def _rich_print_dict(d, title="Config", key="Key", value="Value"):
|
| 32 |
-
console.print(_build_rich_table(d.items(), [key, value], title))
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
@dataclass(frozen=True)
|
| 36 |
-
class HParams:
|
| 37 |
-
# Dataset
|
| 38 |
-
fg_dir: Path = Path("data/fg")
|
| 39 |
-
bg_dir: Path = Path("data/bg")
|
| 40 |
-
rir_dir: Path = Path("data/rir")
|
| 41 |
-
load_fg_only: bool = False
|
| 42 |
-
praat_augment_prob: float = 0
|
| 43 |
-
|
| 44 |
-
# Audio settings
|
| 45 |
-
wav_rate: int = 44_100
|
| 46 |
-
n_fft: int = 2048
|
| 47 |
-
win_size: int = 2048
|
| 48 |
-
hop_size: int = 420 # 9.5ms
|
| 49 |
-
num_mels: int = 128
|
| 50 |
-
stft_magnitude_min: float = 1e-4
|
| 51 |
-
preemphasis: float = 0.97
|
| 52 |
-
mix_alpha_range: tuple[float, float] = (0.2, 0.8)
|
| 53 |
-
|
| 54 |
-
# Training
|
| 55 |
-
nj: int = 64
|
| 56 |
-
training_seconds: float = 1.0
|
| 57 |
-
batch_size_per_gpu: int = 16
|
| 58 |
-
min_lr: float = 1e-5
|
| 59 |
-
max_lr: float = 1e-4
|
| 60 |
-
warmup_steps: int = 1000
|
| 61 |
-
max_steps: int = 1_000_000
|
| 62 |
-
gradient_clipping: float = 1.0
|
| 63 |
-
|
| 64 |
-
@property
|
| 65 |
-
def deepspeed_config(self):
|
| 66 |
-
return {
|
| 67 |
-
"train_micro_batch_size_per_gpu": self.batch_size_per_gpu,
|
| 68 |
-
"optimizer": {
|
| 69 |
-
"type": "Adam",
|
| 70 |
-
"params": {"lr": float(self.min_lr)},
|
| 71 |
-
},
|
| 72 |
-
"scheduler": {
|
| 73 |
-
"type": "WarmupDecayLR",
|
| 74 |
-
"params": {
|
| 75 |
-
"warmup_min_lr": float(self.min_lr),
|
| 76 |
-
"warmup_max_lr": float(self.max_lr),
|
| 77 |
-
"warmup_num_steps": self.warmup_steps,
|
| 78 |
-
"total_num_steps": self.max_steps,
|
| 79 |
-
"warmup_type": "linear",
|
| 80 |
-
},
|
| 81 |
-
},
|
| 82 |
-
"gradient_clipping": self.gradient_clipping,
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
@property
|
| 86 |
-
def stft_cfgs(self):
|
| 87 |
-
assert self.wav_rate == 44_100, f"wav_rate must be 44_100, got {self.wav_rate}"
|
| 88 |
-
return [_make_stft_cfg(h) for h in (100, 256, 512)]
|
| 89 |
-
|
| 90 |
-
@classmethod
|
| 91 |
-
def from_yaml(cls, path: Path) -> "HParams":
|
| 92 |
-
logger.info(f"Reading hparams from {path}")
|
| 93 |
-
# First merge to fix types (e.g., str -> Path)
|
| 94 |
-
return cls(**dict(OmegaConf.merge(cls(), OmegaConf.load(path))))
|
| 95 |
-
|
| 96 |
-
def save_if_not_exists(self, run_dir: Path):
|
| 97 |
-
path = run_dir / "hparams.yaml"
|
| 98 |
-
if path.exists():
|
| 99 |
-
logger.info(f"{path} already exists, not saving")
|
| 100 |
-
return
|
| 101 |
-
path.parent.mkdir(parents=True, exist_ok=True)
|
| 102 |
-
OmegaConf.save(asdict(self), str(path))
|
| 103 |
-
|
| 104 |
-
@classmethod
|
| 105 |
-
def load(cls, run_dir, yaml: Path | None = None):
|
| 106 |
-
hps = []
|
| 107 |
-
|
| 108 |
-
if (run_dir / "hparams.yaml").exists():
|
| 109 |
-
hps.append(cls.from_yaml(run_dir / "hparams.yaml"))
|
| 110 |
-
|
| 111 |
-
if yaml is not None:
|
| 112 |
-
hps.append(cls.from_yaml(yaml))
|
| 113 |
-
|
| 114 |
-
if len(hps) == 0:
|
| 115 |
-
hps.append(cls())
|
| 116 |
-
|
| 117 |
-
for hp in hps[1:]:
|
| 118 |
-
if hp != hps[0]:
|
| 119 |
-
errors = {}
|
| 120 |
-
for k, v in asdict(hp).items():
|
| 121 |
-
if getattr(hps[0], k) != v:
|
| 122 |
-
errors[k] = f"{getattr(hps[0], k)} != {v}"
|
| 123 |
-
raise ValueError(f"Found inconsistent hparams: {errors}, consider deleting {run_dir}")
|
| 124 |
-
|
| 125 |
-
return hps[0]
|
| 126 |
-
|
| 127 |
-
def print(self):
|
| 128 |
-
_rich_print_dict(asdict(self), title="HParams")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/inference.py
DELETED
|
@@ -1,163 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import time
|
| 3 |
-
|
| 4 |
-
import torch
|
| 5 |
-
import torch.nn.functional as F
|
| 6 |
-
from torch.nn.utils.parametrize import remove_parametrizations
|
| 7 |
-
from torchaudio.functional import resample
|
| 8 |
-
from torchaudio.transforms import MelSpectrogram
|
| 9 |
-
from tqdm import trange
|
| 10 |
-
|
| 11 |
-
from .hparams import HParams
|
| 12 |
-
|
| 13 |
-
logger = logging.getLogger(__name__)
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
@torch.inference_mode()
|
| 17 |
-
def inference_chunk(model, dwav, sr, device, npad=441):
|
| 18 |
-
assert model.hp.wav_rate == sr, f"Expected {model.hp.wav_rate} Hz, got {sr} Hz"
|
| 19 |
-
del sr
|
| 20 |
-
|
| 21 |
-
length = dwav.shape[-1]
|
| 22 |
-
abs_max = dwav.abs().max().clamp(min=1e-7)
|
| 23 |
-
|
| 24 |
-
assert dwav.dim() == 1, f"Expected 1D waveform, got {dwav.dim()}D"
|
| 25 |
-
dwav = dwav.to(device)
|
| 26 |
-
dwav = dwav / abs_max # Normalize
|
| 27 |
-
dwav = F.pad(dwav, (0, npad))
|
| 28 |
-
hwav = model(dwav[None])[0].cpu() # (T,)
|
| 29 |
-
hwav = hwav[:length] # Trim padding
|
| 30 |
-
hwav = hwav * abs_max # Unnormalize
|
| 31 |
-
|
| 32 |
-
return hwav
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
def compute_corr(x, y):
|
| 36 |
-
return torch.fft.ifft(torch.fft.fft(x) * torch.fft.fft(y).conj()).abs()
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
def compute_offset(chunk1, chunk2, sr=44100):
|
| 40 |
-
"""
|
| 41 |
-
Args:
|
| 42 |
-
chunk1: (T,)
|
| 43 |
-
chunk2: (T,)
|
| 44 |
-
Returns:
|
| 45 |
-
offset: int, offset in samples such that chunk1 ~= chunk2.roll(-offset)
|
| 46 |
-
"""
|
| 47 |
-
hop_length = sr // 200 # 5 ms resolution
|
| 48 |
-
win_length = hop_length * 4
|
| 49 |
-
n_fft = 2 ** (win_length - 1).bit_length()
|
| 50 |
-
|
| 51 |
-
mel_fn = MelSpectrogram(
|
| 52 |
-
sample_rate=sr,
|
| 53 |
-
n_fft=n_fft,
|
| 54 |
-
win_length=win_length,
|
| 55 |
-
hop_length=hop_length,
|
| 56 |
-
n_mels=80,
|
| 57 |
-
f_min=0.0,
|
| 58 |
-
f_max=sr // 2,
|
| 59 |
-
)
|
| 60 |
-
|
| 61 |
-
spec1 = mel_fn(chunk1).log1p()
|
| 62 |
-
spec2 = mel_fn(chunk2).log1p()
|
| 63 |
-
|
| 64 |
-
corr = compute_corr(spec1, spec2) # (F, T)
|
| 65 |
-
corr = corr.mean(dim=0) # (T,)
|
| 66 |
-
|
| 67 |
-
argmax = corr.argmax().item()
|
| 68 |
-
|
| 69 |
-
if argmax > len(corr) // 2:
|
| 70 |
-
argmax -= len(corr)
|
| 71 |
-
|
| 72 |
-
offset = -argmax * hop_length
|
| 73 |
-
|
| 74 |
-
return offset
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
def merge_chunks(chunks, chunk_length, hop_length, sr=44100, length=None):
|
| 78 |
-
signal_length = (len(chunks) - 1) * hop_length + chunk_length
|
| 79 |
-
overlap_length = chunk_length - hop_length
|
| 80 |
-
signal = torch.zeros(signal_length, device=chunks[0].device)
|
| 81 |
-
|
| 82 |
-
fadein = torch.linspace(0, 1, overlap_length, device=chunks[0].device)
|
| 83 |
-
fadein = torch.cat([fadein, torch.ones(hop_length, device=chunks[0].device)])
|
| 84 |
-
fadeout = torch.linspace(1, 0, overlap_length, device=chunks[0].device)
|
| 85 |
-
fadeout = torch.cat([torch.ones(hop_length, device=chunks[0].device), fadeout])
|
| 86 |
-
|
| 87 |
-
for i, chunk in enumerate(chunks):
|
| 88 |
-
start = i * hop_length
|
| 89 |
-
end = start + chunk_length
|
| 90 |
-
|
| 91 |
-
if len(chunk) < chunk_length:
|
| 92 |
-
chunk = F.pad(chunk, (0, chunk_length - len(chunk)))
|
| 93 |
-
|
| 94 |
-
if i > 0:
|
| 95 |
-
pre_region = chunks[i - 1][-overlap_length:]
|
| 96 |
-
cur_region = chunk[:overlap_length]
|
| 97 |
-
offset = compute_offset(pre_region, cur_region, sr=sr)
|
| 98 |
-
start -= offset
|
| 99 |
-
end -= offset
|
| 100 |
-
|
| 101 |
-
if i == 0:
|
| 102 |
-
chunk = chunk * fadeout
|
| 103 |
-
elif i == len(chunks) - 1:
|
| 104 |
-
chunk = chunk * fadein
|
| 105 |
-
else:
|
| 106 |
-
chunk = chunk * fadein * fadeout
|
| 107 |
-
|
| 108 |
-
signal[start:end] += chunk[: len(signal[start:end])]
|
| 109 |
-
|
| 110 |
-
signal = signal[:length]
|
| 111 |
-
|
| 112 |
-
return signal
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
def remove_weight_norm_recursively(module):
|
| 116 |
-
for _, module in module.named_modules():
|
| 117 |
-
try:
|
| 118 |
-
remove_parametrizations(module, "weight")
|
| 119 |
-
except Exception:
|
| 120 |
-
pass
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
def inference(model, dwav, sr, device, chunk_seconds: float = 30.0, overlap_seconds: float = 1.0):
|
| 124 |
-
remove_weight_norm_recursively(model)
|
| 125 |
-
|
| 126 |
-
hp: HParams = model.hp
|
| 127 |
-
|
| 128 |
-
dwav = resample(
|
| 129 |
-
dwav,
|
| 130 |
-
orig_freq=sr,
|
| 131 |
-
new_freq=hp.wav_rate,
|
| 132 |
-
lowpass_filter_width=64,
|
| 133 |
-
rolloff=0.9475937167399596,
|
| 134 |
-
resampling_method="sinc_interp_kaiser",
|
| 135 |
-
beta=14.769656459379492,
|
| 136 |
-
)
|
| 137 |
-
|
| 138 |
-
del sr # Everything is in hp.wav_rate now
|
| 139 |
-
|
| 140 |
-
sr = hp.wav_rate
|
| 141 |
-
|
| 142 |
-
if torch.cuda.is_available():
|
| 143 |
-
torch.cuda.synchronize()
|
| 144 |
-
|
| 145 |
-
start_time = time.perf_counter()
|
| 146 |
-
|
| 147 |
-
chunk_length = int(sr * chunk_seconds)
|
| 148 |
-
overlap_length = int(sr * overlap_seconds)
|
| 149 |
-
hop_length = chunk_length - overlap_length
|
| 150 |
-
|
| 151 |
-
chunks = []
|
| 152 |
-
for start in trange(0, dwav.shape[-1], hop_length):
|
| 153 |
-
chunks.append(inference_chunk(model, dwav[start : start + chunk_length], sr, device))
|
| 154 |
-
|
| 155 |
-
hwav = merge_chunks(chunks, chunk_length, hop_length, sr=sr, length=dwav.shape[-1])
|
| 156 |
-
|
| 157 |
-
if torch.cuda.is_available():
|
| 158 |
-
torch.cuda.synchronize()
|
| 159 |
-
|
| 160 |
-
elapsed_time = time.perf_counter() - start_time
|
| 161 |
-
logger.info(f"Elapsed time: {elapsed_time:.3f} s, {hwav.shape[-1] / elapsed_time / 1000:.3f} kHz")
|
| 162 |
-
|
| 163 |
-
return hwav, sr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/melspec.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
| 1 |
-
import numpy as np
|
| 2 |
-
import torch
|
| 3 |
-
from torch import nn
|
| 4 |
-
from torchaudio.transforms import MelSpectrogram as TorchMelSpectrogram
|
| 5 |
-
|
| 6 |
-
from .hparams import HParams
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
class MelSpectrogram(nn.Module):
|
| 10 |
-
def __init__(self, hp: HParams):
|
| 11 |
-
"""
|
| 12 |
-
Torch implementation of Resemble's mel extraction.
|
| 13 |
-
Note that the values are NOT identical to librosa's implementation
|
| 14 |
-
due to floating point precisions.
|
| 15 |
-
"""
|
| 16 |
-
super().__init__()
|
| 17 |
-
self.hp = hp
|
| 18 |
-
self.melspec = TorchMelSpectrogram(
|
| 19 |
-
hp.wav_rate,
|
| 20 |
-
n_fft=hp.n_fft,
|
| 21 |
-
win_length=hp.win_size,
|
| 22 |
-
hop_length=hp.hop_size,
|
| 23 |
-
f_min=0,
|
| 24 |
-
f_max=hp.wav_rate // 2,
|
| 25 |
-
n_mels=hp.num_mels,
|
| 26 |
-
power=1,
|
| 27 |
-
normalized=False,
|
| 28 |
-
# NOTE: Folowing librosa's default.
|
| 29 |
-
pad_mode="constant",
|
| 30 |
-
norm="slaney",
|
| 31 |
-
mel_scale="slaney",
|
| 32 |
-
)
|
| 33 |
-
self.register_buffer("stft_magnitude_min", torch.FloatTensor([hp.stft_magnitude_min]))
|
| 34 |
-
self.min_level_db = 20 * np.log10(hp.stft_magnitude_min)
|
| 35 |
-
self.preemphasis = hp.preemphasis
|
| 36 |
-
self.hop_size = hp.hop_size
|
| 37 |
-
|
| 38 |
-
def forward(self, wav, pad=True):
|
| 39 |
-
"""
|
| 40 |
-
Args:
|
| 41 |
-
wav: [B, T]
|
| 42 |
-
"""
|
| 43 |
-
device = wav.device
|
| 44 |
-
if wav.is_mps:
|
| 45 |
-
wav = wav.cpu()
|
| 46 |
-
self.to(wav.device)
|
| 47 |
-
if self.preemphasis > 0:
|
| 48 |
-
wav = torch.nn.functional.pad(wav, [1, 0], value=0)
|
| 49 |
-
wav = wav[..., 1:] - self.preemphasis * wav[..., :-1]
|
| 50 |
-
mel = self.melspec(wav)
|
| 51 |
-
mel = self._amp_to_db(mel)
|
| 52 |
-
mel_normed = self._normalize(mel)
|
| 53 |
-
assert not pad or mel_normed.shape[-1] == 1 + wav.shape[-1] // self.hop_size # Sanity check
|
| 54 |
-
mel_normed = mel_normed.to(device)
|
| 55 |
-
return mel_normed # (M, T)
|
| 56 |
-
|
| 57 |
-
def _normalize(self, s, headroom_db=15):
|
| 58 |
-
return (s - self.min_level_db) / (-self.min_level_db + headroom_db)
|
| 59 |
-
|
| 60 |
-
def _amp_to_db(self, x):
|
| 61 |
-
return x.clamp_min(self.hp.stft_magnitude_min).log10() * 20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/utils/__init__.py
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
from .distributed import global_leader_only
|
| 2 |
-
from .engine import Engine, gather_attribute
|
| 3 |
-
from .logging import setup_logging
|
| 4 |
-
from .train_loop import TrainLoop, is_global_leader
|
| 5 |
-
from .utils import save_mels, tree_map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/utils/control.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import selectors
|
| 3 |
-
import sys
|
| 4 |
-
from functools import cache
|
| 5 |
-
|
| 6 |
-
from .distributed import global_leader_only
|
| 7 |
-
|
| 8 |
-
_logger = logging.getLogger(__name__)
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
@cache
|
| 12 |
-
def _get_stdin_selector():
|
| 13 |
-
selector = selectors.DefaultSelector()
|
| 14 |
-
selector.register(fileobj=sys.stdin, events=selectors.EVENT_READ)
|
| 15 |
-
return selector
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
@global_leader_only(boardcast_return=True)
|
| 19 |
-
def non_blocking_input():
|
| 20 |
-
s = ""
|
| 21 |
-
selector = _get_stdin_selector()
|
| 22 |
-
events = selector.select(timeout=0)
|
| 23 |
-
for key, _ in events:
|
| 24 |
-
s: str = key.fileobj.readline().strip()
|
| 25 |
-
_logger.info(f'Get stdin "{s}".')
|
| 26 |
-
return s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/utils/distributed.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import socket
|
| 3 |
-
from functools import cache, partial, wraps
|
| 4 |
-
from typing import Callable
|
| 5 |
-
|
| 6 |
-
import deepspeed
|
| 7 |
-
import torch
|
| 8 |
-
from deepspeed.accelerator import get_accelerator
|
| 9 |
-
from torch.distributed import broadcast_object_list
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def get_free_port():
|
| 13 |
-
sock = socket.socket()
|
| 14 |
-
sock.bind(("", 0))
|
| 15 |
-
return sock.getsockname()[1]
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
@cache
|
| 19 |
-
def fix_unset_envs():
|
| 20 |
-
envs = dict(RANK="0", WORLD_SIZE="1", MASTER_ADDR="localhost", MASTER_PORT=str(get_free_port()), LOCAL_RANK="0")
|
| 21 |
-
|
| 22 |
-
for key in envs:
|
| 23 |
-
value = os.getenv(key)
|
| 24 |
-
if value is not None:
|
| 25 |
-
return
|
| 26 |
-
|
| 27 |
-
for key, value in envs.items():
|
| 28 |
-
os.environ[key] = value
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
@cache
|
| 32 |
-
def init_distributed():
|
| 33 |
-
fix_unset_envs()
|
| 34 |
-
deepspeed.init_distributed(get_accelerator().communication_backend_name())
|
| 35 |
-
torch.cuda.set_device(local_rank())
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
def local_rank():
|
| 39 |
-
return int(os.getenv("LOCAL_RANK", 0))
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def global_rank():
|
| 43 |
-
return int(os.getenv("RANK", 0))
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def is_local_leader():
|
| 47 |
-
return local_rank() == 0
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def is_global_leader():
|
| 51 |
-
return global_rank() == 0
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
def leader_only(leader_only_type, fn: Callable | None = None, boardcast_return=False) -> Callable:
|
| 55 |
-
"""
|
| 56 |
-
Args:
|
| 57 |
-
fn: The function to decorate
|
| 58 |
-
boardcast_return: Whether to boardcast the return value to all processes
|
| 59 |
-
(may cause deadlock if the function calls another decorated function)
|
| 60 |
-
"""
|
| 61 |
-
|
| 62 |
-
def wrapper(fn):
|
| 63 |
-
if hasattr(fn, "__leader_only_type__"):
|
| 64 |
-
raise RuntimeError(f"Function {fn.__name__} has already been decorated with {fn.__leader_only_type__}")
|
| 65 |
-
|
| 66 |
-
fn.__leader_only_type__ = leader_only_type
|
| 67 |
-
|
| 68 |
-
if leader_only_type == "local":
|
| 69 |
-
guard_fn = is_local_leader
|
| 70 |
-
elif leader_only_type == "global":
|
| 71 |
-
guard_fn = is_global_leader
|
| 72 |
-
else:
|
| 73 |
-
raise ValueError(f"Unknown leader_only_type: {leader_only_type}")
|
| 74 |
-
|
| 75 |
-
@wraps(fn)
|
| 76 |
-
def wrapped(*args, **kwargs):
|
| 77 |
-
if boardcast_return:
|
| 78 |
-
init_distributed()
|
| 79 |
-
obj_list = [None]
|
| 80 |
-
if guard_fn():
|
| 81 |
-
ret = fn(*args, **kwargs)
|
| 82 |
-
obj_list[0] = ret
|
| 83 |
-
if boardcast_return:
|
| 84 |
-
broadcast_object_list(obj_list, src=0)
|
| 85 |
-
return obj_list[0]
|
| 86 |
-
|
| 87 |
-
return wrapped
|
| 88 |
-
|
| 89 |
-
if fn is None:
|
| 90 |
-
return wrapper
|
| 91 |
-
|
| 92 |
-
return wrapper(fn)
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
local_leader_only = partial(leader_only, "local")
|
| 96 |
-
global_leader_only = partial(leader_only, "global")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/utils/engine.py
DELETED
|
@@ -1,145 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
import re
|
| 3 |
-
from functools import cache, partial
|
| 4 |
-
from typing import Callable, TypeVar
|
| 5 |
-
|
| 6 |
-
import deepspeed
|
| 7 |
-
import pandas as pd
|
| 8 |
-
from deepspeed.accelerator import get_accelerator
|
| 9 |
-
from deepspeed.runtime.engine import DeepSpeedEngine
|
| 10 |
-
from deepspeed.runtime.utils import clip_grad_norm_
|
| 11 |
-
from torch import nn
|
| 12 |
-
|
| 13 |
-
from .distributed import fix_unset_envs
|
| 14 |
-
|
| 15 |
-
logger = logging.getLogger(__name__)
|
| 16 |
-
|
| 17 |
-
T = TypeVar("T")
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def flatten_dict(d):
|
| 21 |
-
records = pd.json_normalize(d, sep="/").to_dict(orient="records")
|
| 22 |
-
return records[0] if records else {}
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
def _get_named_modules(module, attrname, sep="/"):
|
| 26 |
-
for name, module in module.named_modules():
|
| 27 |
-
name = name.replace(".", sep)
|
| 28 |
-
if hasattr(module, attrname):
|
| 29 |
-
yield name, module
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
def gather_attribute(module, attrname, delete=True, prefix=None):
|
| 33 |
-
ret = {}
|
| 34 |
-
for name, module in _get_named_modules(module, attrname):
|
| 35 |
-
ret[name] = getattr(module, attrname)
|
| 36 |
-
if delete:
|
| 37 |
-
try:
|
| 38 |
-
delattr(module, attrname)
|
| 39 |
-
except Exception as e:
|
| 40 |
-
raise RuntimeError(f"{name} {module} {attrname}") from e
|
| 41 |
-
if prefix:
|
| 42 |
-
ret = {prefix: ret}
|
| 43 |
-
ret = flatten_dict(ret)
|
| 44 |
-
# remove consecutive /
|
| 45 |
-
ret = {re.sub(r"\/+", "/", k): v for k, v in ret.items()}
|
| 46 |
-
return ret
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
def dispatch_attribute(module, attrname, value, filter_fn: Callable[[nn.Module], bool] | None = None):
|
| 50 |
-
for _, module in _get_named_modules(module, attrname):
|
| 51 |
-
if filter_fn is None or filter_fn(module):
|
| 52 |
-
setattr(module, attrname, value)
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
@cache
|
| 56 |
-
def update_deepspeed_logger():
|
| 57 |
-
logger = logging.getLogger("DeepSpeed")
|
| 58 |
-
logger.setLevel(logging.WARNING)
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
@cache
|
| 62 |
-
def init_distributed():
|
| 63 |
-
update_deepspeed_logger()
|
| 64 |
-
fix_unset_envs()
|
| 65 |
-
deepspeed.init_distributed(get_accelerator().communication_backend_name())
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
def _try_each(*fns, e=None):
|
| 69 |
-
if len(fns) == 0:
|
| 70 |
-
raise RuntimeError("All functions failed")
|
| 71 |
-
|
| 72 |
-
head, *tails = fns
|
| 73 |
-
|
| 74 |
-
try:
|
| 75 |
-
return head()
|
| 76 |
-
except Exception as e:
|
| 77 |
-
logger.warning(f"Tried {head} but failed: {e}, trying next")
|
| 78 |
-
return _try_each(*tails)
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
class Engine(DeepSpeedEngine):
|
| 82 |
-
def __init__(self, *args, ckpt_dir, **kwargs):
|
| 83 |
-
init_distributed()
|
| 84 |
-
super().__init__(args=None, *args, **kwargs)
|
| 85 |
-
self._ckpt_dir = ckpt_dir
|
| 86 |
-
self._frozen_params = set()
|
| 87 |
-
self._fp32_grad_norm = None
|
| 88 |
-
|
| 89 |
-
@property
|
| 90 |
-
def path(self):
|
| 91 |
-
return self._ckpt_dir
|
| 92 |
-
|
| 93 |
-
def freeze_(self):
|
| 94 |
-
for p in self.module.parameters():
|
| 95 |
-
if p.requires_grad:
|
| 96 |
-
p.requires_grad_(False)
|
| 97 |
-
self._frozen_params.add(p)
|
| 98 |
-
|
| 99 |
-
def unfreeze_(self):
|
| 100 |
-
for p in self._frozen_params:
|
| 101 |
-
p.requires_grad_(True)
|
| 102 |
-
self._frozen_params.clear()
|
| 103 |
-
|
| 104 |
-
@property
|
| 105 |
-
def global_step(self):
|
| 106 |
-
return self.global_steps
|
| 107 |
-
|
| 108 |
-
def gather_attribute(self, *args, **kwargs):
|
| 109 |
-
return gather_attribute(self.module, *args, **kwargs)
|
| 110 |
-
|
| 111 |
-
def dispatch_attribute(self, *args, **kwargs):
|
| 112 |
-
return dispatch_attribute(self.module, *args, **kwargs)
|
| 113 |
-
|
| 114 |
-
def clip_fp32_gradients(self):
|
| 115 |
-
self._fp32_grad_norm = clip_grad_norm_(
|
| 116 |
-
parameters=self.module.parameters(),
|
| 117 |
-
max_norm=self.gradient_clipping(),
|
| 118 |
-
mpu=self.mpu,
|
| 119 |
-
)
|
| 120 |
-
|
| 121 |
-
def get_grad_norm(self):
|
| 122 |
-
grad_norm = self.get_global_grad_norm()
|
| 123 |
-
if grad_norm is None:
|
| 124 |
-
grad_norm = self._fp32_grad_norm
|
| 125 |
-
return grad_norm
|
| 126 |
-
|
| 127 |
-
def save_checkpoint(self, *args, **kwargs):
|
| 128 |
-
if not self._ckpt_dir.exists():
|
| 129 |
-
self._ckpt_dir.mkdir(parents=True, exist_ok=True)
|
| 130 |
-
super().save_checkpoint(save_dir=self._ckpt_dir, *args, **kwargs)
|
| 131 |
-
logger.info(f"Saved checkpoint to {self._ckpt_dir}")
|
| 132 |
-
|
| 133 |
-
def load_checkpoint(self, *args, **kwargs):
|
| 134 |
-
fn = partial(super().load_checkpoint, *args, load_dir=self._ckpt_dir, **kwargs)
|
| 135 |
-
return _try_each(
|
| 136 |
-
lambda: fn(),
|
| 137 |
-
lambda: fn(load_optimizer_states=False),
|
| 138 |
-
lambda: fn(load_lr_scheduler_states=False),
|
| 139 |
-
lambda: fn(load_optimizer_states=False, load_lr_scheduler_states=False),
|
| 140 |
-
lambda: fn(
|
| 141 |
-
load_optimizer_states=False,
|
| 142 |
-
load_lr_scheduler_states=False,
|
| 143 |
-
load_module_strict=False,
|
| 144 |
-
),
|
| 145 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resemble_enhance/utils/logging.py
DELETED
|
@@ -1,38 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
from pathlib import Path
|
| 3 |
-
|
| 4 |
-
from rich.logging import RichHandler
|
| 5 |
-
|
| 6 |
-
from .distributed import global_leader_only
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
@global_leader_only
|
| 10 |
-
def setup_logging(run_dir):
|
| 11 |
-
handlers = []
|
| 12 |
-
stdout_handler = RichHandler()
|
| 13 |
-
stdout_handler.setLevel(logging.INFO)
|
| 14 |
-
handlers.append(stdout_handler)
|
| 15 |
-
|
| 16 |
-
if run_dir is not None:
|
| 17 |
-
filename = Path(run_dir) / f"log.txt"
|
| 18 |
-
filename.parent.mkdir(parents=True, exist_ok=True)
|
| 19 |
-
file_handler = logging.FileHandler(filename, mode="a")
|
| 20 |
-
file_handler.setLevel(logging.DEBUG)
|
| 21 |
-
handlers.append(file_handler)
|
| 22 |
-
|
| 23 |
-
# Update all existing loggers
|
| 24 |
-
for name in ["DeepSpeed"]:
|
| 25 |
-
logger = logging.getLogger(name)
|
| 26 |
-
if isinstance(logger, logging.Logger):
|
| 27 |
-
for handler in list(logger.handlers):
|
| 28 |
-
logger.removeHandler(handler)
|
| 29 |
-
for handler in handlers:
|
| 30 |
-
logger.addHandler(handler)
|
| 31 |
-
|
| 32 |
-
# Set the default logger
|
| 33 |
-
logging.basicConfig(
|
| 34 |
-
level=logging.getLevelName("INFO"),
|
| 35 |
-
format="%(message)s",
|
| 36 |
-
datefmt="[%X]",
|
| 37 |
-
handlers=handlers,
|
| 38 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|