fakesound 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fakesound/data/dataset.py +58 -0
- fakesound/data/mel_bands.py +34 -0
- fakesound/data/pqmf.py +21 -0
- fakesound/data/transforms.py +168 -0
- fakesound/gansynth/dataset.py +46 -0
- fakesound/gansynth/models.py +89 -0
- fakesound/gansynth/utils.py +31 -0
- fakesound/hifigan/blocks.py +57 -0
- fakesound/hifigan/loss_funcs.py +29 -0
- fakesound/hifigan/models.py +168 -0
- fakesound/rave/core_funcs.py +46 -0
- fakesound/rave/discriminator.py +47 -0
- fakesound/rave/encoder.py +28 -0
- fakesound/rave/generator.py +102 -0
- fakesound/rave/model.py +31 -0
- fakesound/samplernn/blocks.py +65 -0
- fakesound/samplernn/model.py +75 -0
- fakesound/util/train_utils.py +31 -0
- fakesound/wavenet/blocks.py +18 -0
- fakesound/wavenet/layers.py +41 -0
- fakesound/wavenet/model.py +50 -0
- fakesound-0.0.0.dist-info/METADATA +6 -0
- fakesound-0.0.0.dist-info/RECORD +26 -0
- fakesound-0.0.0.dist-info/WHEEL +5 -0
- fakesound-0.0.0.dist-info/licenses/LICENSE +18 -0
- fakesound-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
import numpy as np
|
|
3
|
+
import glob, os
|
|
4
|
+
import torch
|
|
5
|
+
from scipy.io import wavfile
|
|
6
|
+
from numpy.lib.stride_tricks import sliding_window_view
|
|
7
|
+
from torch.utils.data import Dataset
|
|
8
|
+
|
|
9
|
+
class AudioDataSet(Dataset[torch.Tensor]):
|
|
10
|
+
def __init__(self, folder_path:str, chunk_samples:int,
|
|
11
|
+
hop_samples:int, transform:Callable = None,
|
|
12
|
+
reset = False, pad_start:int = 0):
|
|
13
|
+
self.sample_rate = None # set when 1st loading audio
|
|
14
|
+
self.transform = transform
|
|
15
|
+
files = glob.glob(os.path.join(folder_path, "*.wav"))
|
|
16
|
+
arrays = []
|
|
17
|
+
self.reset_flags = []
|
|
18
|
+
# if reset is used, all files should be equal length
|
|
19
|
+
self.num_chunks = []
|
|
20
|
+
for f in files:
|
|
21
|
+
x = self.load_audio(f)
|
|
22
|
+
x = np.pad(x, (pad_start, 0))
|
|
23
|
+
chunks = sliding_window_view(x, chunk_samples)[::hop_samples,:]
|
|
24
|
+
self.num_chunks.append(len(chunks))
|
|
25
|
+
file_reset = [False] * self.num_chunks[-1]
|
|
26
|
+
if reset:
|
|
27
|
+
file_reset[0] = True
|
|
28
|
+
arrays.append(chunks)
|
|
29
|
+
self.reset_flags = self.reset_flags + file_reset
|
|
30
|
+
self.data = np.concatenate(arrays, 0)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def __len__(self):
|
|
34
|
+
return len(self.data)
|
|
35
|
+
|
|
36
|
+
# reset assumes no shuffling
|
|
37
|
+
def __getitem__(self, index:int):
|
|
38
|
+
sample = self.data[index]
|
|
39
|
+
reset = self.reset_flags[index]
|
|
40
|
+
sample = torch.from_numpy(sample).unsqueeze(0).float()
|
|
41
|
+
transformed = sample
|
|
42
|
+
if self.transform is not None:
|
|
43
|
+
transformed = self.transform(sample)
|
|
44
|
+
return transformed, sample, reset
|
|
45
|
+
|
|
46
|
+
def load_audio(self, file_path:str):
|
|
47
|
+
samplerate, data = wavfile.read(file_path)
|
|
48
|
+
if self.sample_rate is None:
|
|
49
|
+
self.sample_rate = samplerate
|
|
50
|
+
if samplerate != self.sample_rate:
|
|
51
|
+
raise Exception("Different sample rates in dataset")
|
|
52
|
+
if data.dtype == np.int16:
|
|
53
|
+
data = data / 2**15
|
|
54
|
+
if data.dtype == np.int32:
|
|
55
|
+
data = data / 2**31
|
|
56
|
+
if len(data.shape) > 1:
|
|
57
|
+
data = data[:,0]
|
|
58
|
+
return data
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
|
|
4
|
+
def mel2hz(mel):
|
|
5
|
+
return 700. * (np.exp(mel / 1127.) - 1.0)
|
|
6
|
+
|
|
7
|
+
def hz2mel(hz):
|
|
8
|
+
return 1127. * np.log(1.0 + (hz / 700.0))
|
|
9
|
+
|
|
10
|
+
def linear2mel(bin_freqs:np.ndarray, n_mels:int, fmin:float, fmax:float):
|
|
11
|
+
return get_mel_matrix(bin_freqs, n_mels, fmin, fmax)
|
|
12
|
+
|
|
13
|
+
def mel2linear(bin_freqs:np.ndarray, n_mels:int, fmin:float, fmax:float):
|
|
14
|
+
M = get_mel_matrix(bin_freqs, n_mels, fmin, fmax)
|
|
15
|
+
Mt = M.T
|
|
16
|
+
S = np.sum(np.dot(M, Mt), 0)
|
|
17
|
+
d = np.divide(1.0, S, out=np.zeros_like(S), where = S!=0)
|
|
18
|
+
return np.dot(Mt, np.diag(d))
|
|
19
|
+
|
|
20
|
+
def get_mel_matrix(bin_freqs:np.ndarray, n_mels:int, fmin:float, fmax:float):
|
|
21
|
+
# based on https://librosa.org/doc/main/_modules/librosa/filters.html#mel
|
|
22
|
+
N = bin_freqs.shape[0]
|
|
23
|
+
M = np.zeros((n_mels,N))
|
|
24
|
+
mels = np.linspace(hz2mel(fmin), hz2mel(fmax), n_mels+2)
|
|
25
|
+
mel_freqs = mel2hz(mels)
|
|
26
|
+
fdiff = np.diff(mel_freqs)
|
|
27
|
+
ramps = np.subtract.outer(mel_freqs, bin_freqs)
|
|
28
|
+
for i in range(n_mels):
|
|
29
|
+
rising = -ramps[i, :] / fdiff[i]
|
|
30
|
+
falling = ramps[i + 2, :] / fdiff[i + 1]
|
|
31
|
+
M[i, :] = np.maximum(0, np.minimum(rising, falling))
|
|
32
|
+
norm = 2.0 / (mel_freqs[2 : n_mels + 2] - mel_freqs[:n_mels])
|
|
33
|
+
M = M * norm[:, None]
|
|
34
|
+
return M
|
fakesound/data/pqmf.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
from scipy import signal
|
|
5
|
+
|
|
6
|
+
def get_pqmf_filter( n_bands:int = 16, atten:float=100, analysis = True):
|
|
7
|
+
cutoff = 1 / (2 * n_bands)
|
|
8
|
+
n_taps, beta = signal.kaiserord(atten, cutoff)
|
|
9
|
+
h = signal.firwin(n_taps + 1, cutoff,
|
|
10
|
+
window=('kaiser', beta), scale = False )
|
|
11
|
+
k = torch.arange(n_bands).reshape(-1, 1)
|
|
12
|
+
alpha = (2 * k + 1) * (torch.pi /
|
|
13
|
+
(2 * n_bands)) * (torch.arange( n_taps + 1)-(( n_taps - 1) / 2))
|
|
14
|
+
phase = (-1)**k * np.pi / 4
|
|
15
|
+
if analysis:
|
|
16
|
+
f = 2 * torch.from_numpy(h) * torch.cos(alpha + phase)
|
|
17
|
+
f = f[:, None, :].float()
|
|
18
|
+
else:
|
|
19
|
+
f = 2 * torch.from_numpy(h) * torch.cos(alpha - phase)
|
|
20
|
+
f = f[None, :, :].float()
|
|
21
|
+
return f
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
from torch import nn
|
|
4
|
+
import torch.nn.functional as F
|
|
5
|
+
from .mel_bands import linear2mel
|
|
6
|
+
from .pqmf import get_pqmf_filter
|
|
7
|
+
|
|
8
|
+
class muLawEncoder(nn.Module):
|
|
9
|
+
def __init__(self, n_levels:int = 256):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.num_levels:int = n_levels
|
|
12
|
+
bins:torch.Tensor = torch.linspace(-1, 1, n_levels)
|
|
13
|
+
mu:torch.Tensor = torch.Tensor([n_levels - 1])
|
|
14
|
+
self.register_buffer('bins', bins)
|
|
15
|
+
self.register_buffer('mu', mu)
|
|
16
|
+
|
|
17
|
+
def forward(self, x:torch.Tensor) -> torch.Tensor:
|
|
18
|
+
x = x.clone()
|
|
19
|
+
compressed = torch.sign(x) * torch.log1p(self.mu * torch.abs(x)) / torch.log1p(self.mu)
|
|
20
|
+
return torch.bucketize(compressed, self.bins)
|
|
21
|
+
|
|
22
|
+
class muLawDecoder(nn.Module):
|
|
23
|
+
def __init__(self, n_levels:int = 256):
|
|
24
|
+
super().__init__()
|
|
25
|
+
mu:torch.Tensor = torch.Tensor([n_levels - 1])
|
|
26
|
+
self.register_buffer('mu', mu)
|
|
27
|
+
|
|
28
|
+
def forward(self, x:torch.Tensor) -> torch.Tensor:
|
|
29
|
+
x = x / (1 + self.mu) * 2 - 1
|
|
30
|
+
return torch.sign(x) * (torch.pow(self.mu + 1, torch.abs(x)) - 1) / self.mu
|
|
31
|
+
|
|
32
|
+
class Wave2LogMagIF(nn.Module):
|
|
33
|
+
def __init__(self, fft_size:int, hop_size:int):
|
|
34
|
+
super().__init__()
|
|
35
|
+
self.fft_size = fft_size
|
|
36
|
+
self.hop_size = hop_size
|
|
37
|
+
self.epsilon = 1e-7
|
|
38
|
+
window = torch.hann_window(fft_size)
|
|
39
|
+
self.register_buffer('window', window)
|
|
40
|
+
|
|
41
|
+
def forward(self, x:torch.Tensor, remove_nyquist:bool = True) -> tuple[torch.Tensor, torch.Tensor]:
|
|
42
|
+
x = x.squeeze(1)
|
|
43
|
+
spec = torch.stft(x,
|
|
44
|
+
n_fft = self.fft_size,
|
|
45
|
+
hop_length = self.hop_size,
|
|
46
|
+
win_length = self.fft_size,
|
|
47
|
+
window = self.window,
|
|
48
|
+
center = True,
|
|
49
|
+
pad_mode = 'reflect',
|
|
50
|
+
normalized = False,
|
|
51
|
+
onesided = True,
|
|
52
|
+
return_complex = True).squeeze(0)
|
|
53
|
+
logmag = torch.log(torch.abs(spec).clip(min = self.epsilon))
|
|
54
|
+
phase = torch.angle(spec)
|
|
55
|
+
dphase = torch.diff(phase)
|
|
56
|
+
dphase = torch.where(dphase > np.pi, dphase - 2 * np.pi, dphase)
|
|
57
|
+
dphase = torch.where(dphase < -np.pi, dphase + 2 * np.pi, dphase)
|
|
58
|
+
dphase = torch.hstack((phase[:,0, None], dphase))
|
|
59
|
+
if remove_nyquist:
|
|
60
|
+
return (logmag[:-1,:], dphase[:-1,:])
|
|
61
|
+
else:
|
|
62
|
+
return (logmag, dphase)
|
|
63
|
+
|
|
64
|
+
class LogMagIF2Wave(nn.Module):
|
|
65
|
+
def __init__(self, fft_size:int, hop_size:int):
|
|
66
|
+
super().__init__()
|
|
67
|
+
self.fft_size = fft_size
|
|
68
|
+
self.hop_size = hop_size
|
|
69
|
+
window = torch.hann_window(fft_size)
|
|
70
|
+
self.register_buffer('window', window)
|
|
71
|
+
|
|
72
|
+
def forward(self, logmag:torch.Tensor, instfreq: torch.Tensor, add_nyquist:bool = True) -> torch.Tensor:
|
|
73
|
+
mag = torch.exp(logmag)
|
|
74
|
+
phase = torch.cumsum(instfreq, 1)
|
|
75
|
+
spec = torch.polar(mag, phase)
|
|
76
|
+
if add_nyquist:
|
|
77
|
+
new_spec = torch.empty(
|
|
78
|
+
logmag.shape[0]+1, logmag.shape[1] ,
|
|
79
|
+
dtype = spec.dtype).to(logmag.device)
|
|
80
|
+
new_spec[:logmag.shape[0], :] = spec
|
|
81
|
+
spec = new_spec
|
|
82
|
+
audio = torch.istft(spec,
|
|
83
|
+
n_fft = self.fft_size,
|
|
84
|
+
hop_length = self.hop_size,
|
|
85
|
+
win_length = self.fft_size,
|
|
86
|
+
window = self.window,
|
|
87
|
+
center = True,
|
|
88
|
+
normalized = False,
|
|
89
|
+
onesided = True,
|
|
90
|
+
return_complex = False
|
|
91
|
+
)
|
|
92
|
+
return audio
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Wave2LogMelIF(nn.Module):
|
|
96
|
+
def __init__(self, sr:float, fft_size:int, hop_size:int,
|
|
97
|
+
n_mels:int, fmin:float, fmax:float,
|
|
98
|
+
pad_amount:int = None, return_phase:bool = True):
|
|
99
|
+
super().__init__()
|
|
100
|
+
self.fft_size = fft_size
|
|
101
|
+
self.hop_size = hop_size
|
|
102
|
+
self.n_mels = n_mels
|
|
103
|
+
self.return_phase = return_phase
|
|
104
|
+
self.epsilon = 1e-7
|
|
105
|
+
if pad_amount is None:
|
|
106
|
+
self.pad_amount = fft_size //2
|
|
107
|
+
else:
|
|
108
|
+
self.pad_amount = pad_amount
|
|
109
|
+
dF = sr/fft_size
|
|
110
|
+
n_bins = fft_size / 2 + 1
|
|
111
|
+
ff = np.arange(0, dF * n_bins, dF)
|
|
112
|
+
mel_matrix = torch.from_numpy(linear2mel(ff, n_mels, fmin, fmax)).float()
|
|
113
|
+
window = torch.hann_window(fft_size)
|
|
114
|
+
self.register_buffer('mel_matrix', mel_matrix)
|
|
115
|
+
self.register_buffer('window', window)
|
|
116
|
+
|
|
117
|
+
def forward(self, x:torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
|
118
|
+
x = torch.nn.functional.pad(
|
|
119
|
+
x.unsqueeze(1), (self.pad_amount, self.pad_amount),
|
|
120
|
+
mode='reflect'
|
|
121
|
+
)
|
|
122
|
+
x = x.squeeze(1)
|
|
123
|
+
spec = torch.stft(x,
|
|
124
|
+
n_fft = self.fft_size,
|
|
125
|
+
hop_length = self.hop_size,
|
|
126
|
+
win_length = self.fft_size,
|
|
127
|
+
window = self.window,
|
|
128
|
+
center= False,
|
|
129
|
+
pad_mode = 'reflect',
|
|
130
|
+
normalized = False,
|
|
131
|
+
onesided = True,
|
|
132
|
+
return_complex = True).squeeze(0)
|
|
133
|
+
mel_mag = torch.matmul(self.mel_matrix, torch.abs(spec))
|
|
134
|
+
mel_logmag = torch.log(mel_mag.clip(min = self.epsilon))
|
|
135
|
+
if not self.return_phase: return (mel_logmag, torch.empty(0))
|
|
136
|
+
mel_phase = torch.matmul(self.mel_matrix, torch.angle(spec))
|
|
137
|
+
dphase = torch.diff(mel_phase)
|
|
138
|
+
dphase = torch.where(dphase > np.pi, dphase - 2 * np.pi, dphase)
|
|
139
|
+
dphase = torch.where(dphase < -np.pi, dphase + 2 * np.pi, dphase)
|
|
140
|
+
dphase = torch.hstack((mel_phase[:,0, None], dphase))
|
|
141
|
+
return (mel_logmag, dphase)
|
|
142
|
+
|
|
143
|
+
class Wave2PQMF(nn.Module):
|
|
144
|
+
def __init__(self, n_bands:int = 16, atten:float = 100):
|
|
145
|
+
super().__init__()
|
|
146
|
+
h = get_pqmf_filter(n_bands, atten)
|
|
147
|
+
self.n_taps = h.shape[-1]-1
|
|
148
|
+
self.n_bands = n_bands
|
|
149
|
+
self.register_buffer("h", h)
|
|
150
|
+
def forward(self, x:torch.Tensor)-> torch.Tensor:
|
|
151
|
+
return F.conv1d(x, self.h, padding = self.n_taps // 2, stride=self.n_bands)
|
|
152
|
+
|
|
153
|
+
class PQMF2Wave(nn.Module):
|
|
154
|
+
def __init__(self, n_bands:int = 16, atten:float = 100):
|
|
155
|
+
super().__init__()
|
|
156
|
+
h = get_pqmf_filter(n_bands, atten, False)
|
|
157
|
+
self.n_taps = h.shape[-1]-1
|
|
158
|
+
self.n_bands = n_bands
|
|
159
|
+
self.register_buffer("h", h)
|
|
160
|
+
updown_filter = torch.zeros((n_bands, n_bands, n_bands)).float()
|
|
161
|
+
updown_filter[range(n_bands), range(n_bands), 0] = 1
|
|
162
|
+
self.register_buffer("updown_filter", updown_filter)
|
|
163
|
+
self.pad_fn = torch.nn.ConstantPad1d(self.n_taps // 2, 0.0)
|
|
164
|
+
|
|
165
|
+
def forward(self, x:torch.Tensor)-> torch.Tensor:
|
|
166
|
+
x = F.conv_transpose1d(x, self.updown_filter * self.n_bands,stride=self.n_bands)
|
|
167
|
+
x = F.conv1d(x, self.h, padding = self.n_taps // 2)
|
|
168
|
+
return x
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import glob, os
|
|
3
|
+
import torch
|
|
4
|
+
from fakesound.data.dataset import AudioDataSet
|
|
5
|
+
from fakesound.data.transforms import Wave2LogMagIF
|
|
6
|
+
|
|
7
|
+
# Lazy dataset for NSynth training set including pitch
|
|
8
|
+
|
|
9
|
+
class NSynthDataset(AudioDataSet):
|
|
10
|
+
def __init__(self, folder_path:str, sample_rate:int,
|
|
11
|
+
fft_size:int, hop_size:int, pad_start:int):
|
|
12
|
+
self.sample_rate = None
|
|
13
|
+
self.fft_size = fft_size
|
|
14
|
+
self.n_mels = fft_size // 2
|
|
15
|
+
self.pad_start = pad_start
|
|
16
|
+
self.transform = Wave2LogMagIF(fft_size, hop_size)
|
|
17
|
+
|
|
18
|
+
self.files = glob.glob(os.path.join(folder_path, "*.wav"))[:16]
|
|
19
|
+
|
|
20
|
+
self.max_mag = np.log(fft_size//4)
|
|
21
|
+
self.min_mag = np.log(self.transform.epsilon)
|
|
22
|
+
self.max_phase = np.pi
|
|
23
|
+
self.min_phase = -np.pi
|
|
24
|
+
def __len__(self):
|
|
25
|
+
return len(self.files)
|
|
26
|
+
|
|
27
|
+
def normalise_mag(self, x:torch.Tensor)-> torch.Tensor:
|
|
28
|
+
return 2 * (x - self.min_mag) / (self.max_mag - self.min_mag) -1
|
|
29
|
+
def normalise_phase(self, x:torch.Tensor)-> torch.Tensor:
|
|
30
|
+
return 2 * (x - self.min_phase) / (self.max_phase - self.min_phase) -1
|
|
31
|
+
def denormalise_mag(self, x:torch.Tensor)-> torch.Tensor:
|
|
32
|
+
return (x + 1)* (self.max_mag - self.min_mag) / 2 + self.min_mag
|
|
33
|
+
def denormalise_phase(self, x:torch.Tensor)-> torch.Tensor:
|
|
34
|
+
return (x + 1)* (self.max_phase - self.min_phase) / 2 + self.min_phase
|
|
35
|
+
|
|
36
|
+
# reset assumes no shuffling
|
|
37
|
+
def __getitem__(self, index:int):
|
|
38
|
+
filename = self.files[index]
|
|
39
|
+
pitch = int(filename.split("_")[-1].split("-")[1])
|
|
40
|
+
sample = self.load_audio(filename)
|
|
41
|
+
sample = np.pad(sample, (self.pad_start, 0))
|
|
42
|
+
sample = torch.from_numpy(sample).unsqueeze(0).float()
|
|
43
|
+
logmag, phase = self.transform(sample)
|
|
44
|
+
logmag = self.normalise_mag(logmag)
|
|
45
|
+
phase = self.normalise_phase(phase)
|
|
46
|
+
return torch.stack((logmag, phase)), pitch
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from torch.nn import functional as F
|
|
4
|
+
|
|
5
|
+
class PixelNorm(nn.Module):
|
|
6
|
+
def forward(self, x):
|
|
7
|
+
n_chan = x.shape[1]
|
|
8
|
+
return x / (1/ n_chan * (x ** 2).sum(dim = 1, keepdims = True)).sqrt()
|
|
9
|
+
|
|
10
|
+
class Generator(nn.Module):
|
|
11
|
+
def __init__(self, input_size:int = 317):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.input_size = input_size
|
|
14
|
+
self.input_block = nn.Sequential(
|
|
15
|
+
nn.Conv2d(input_size, 256, (16, 2)),
|
|
16
|
+
PixelNorm(), nn.LeakyReLU(),
|
|
17
|
+
nn.Conv2d(256, 256, 3, padding="same"),
|
|
18
|
+
PixelNorm(), nn.LeakyReLU())
|
|
19
|
+
self.upsample2x2 = lambda c: nn.ConvTranspose2d(c, c, (2,2),(2,2))
|
|
20
|
+
self.conv_block = lambda in_c, out_c: nn.Sequential(
|
|
21
|
+
nn.Conv2d(in_c, out_c, 3, padding="same"),
|
|
22
|
+
PixelNorm(), nn.LeakyReLU(),
|
|
23
|
+
nn.Conv2d(out_c, out_c, 3, padding="same"),
|
|
24
|
+
PixelNorm(), nn.LeakyReLU())
|
|
25
|
+
self.output = nn.Sequential(
|
|
26
|
+
nn.Conv2d(32, 2, 1),
|
|
27
|
+
nn.Tanh()
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
self.network = nn.Sequential(
|
|
31
|
+
self.input_block,
|
|
32
|
+
self.upsample2x2(256),
|
|
33
|
+
self.conv_block(256, 256),
|
|
34
|
+
self.upsample2x2(256),
|
|
35
|
+
self.conv_block(256, 256),
|
|
36
|
+
self.upsample2x2(256),
|
|
37
|
+
self.conv_block(256, 256),
|
|
38
|
+
self.upsample2x2(256),
|
|
39
|
+
self.conv_block(256, 128),
|
|
40
|
+
self.upsample2x2(128),
|
|
41
|
+
self.conv_block(128, 64),
|
|
42
|
+
self.upsample2x2(64),
|
|
43
|
+
self.conv_block(64, 32),
|
|
44
|
+
self.output
|
|
45
|
+
)
|
|
46
|
+
def forward(self, x:torch.Tensor)-> torch.Tensor:
|
|
47
|
+
x = F.pad(x,(1, 1, 15, 15))
|
|
48
|
+
return self.network(x)
|
|
49
|
+
|
|
50
|
+
class Discriminator(nn.Module):
|
|
51
|
+
def __init__(self, num_classes:int):
|
|
52
|
+
super().__init__()
|
|
53
|
+
self.input = nn.Conv2d(2, 32, 1)
|
|
54
|
+
self.downsample2x2 = lambda c: nn.Conv2d(c, c, (2,2),(2,2))
|
|
55
|
+
self.conv_block = lambda in_c, out_c: nn.Sequential(
|
|
56
|
+
nn.Conv2d(in_c, out_c, 3, padding = "same"),
|
|
57
|
+
nn.LeakyReLU(),
|
|
58
|
+
nn.Conv2d(out_c, out_c, 3, padding = "same"),
|
|
59
|
+
nn.LeakyReLU()
|
|
60
|
+
)
|
|
61
|
+
self.last_conv = nn.Sequential(
|
|
62
|
+
nn.Conv2d(256, 256, 3, padding="same"),
|
|
63
|
+
nn.LeakyReLU(),
|
|
64
|
+
nn.Conv2d(256, 256, (16,2), padding="valid"),
|
|
65
|
+
nn.LeakyReLU()
|
|
66
|
+
)
|
|
67
|
+
self.disc_out = nn.Linear(256, 1)
|
|
68
|
+
self.classifier_out = nn.Linear(256, num_classes)
|
|
69
|
+
|
|
70
|
+
self.network = nn.Sequential(
|
|
71
|
+
self.input,
|
|
72
|
+
self.conv_block(32, 32),
|
|
73
|
+
self.downsample2x2(32),
|
|
74
|
+
self.conv_block(32, 64),
|
|
75
|
+
self.downsample2x2(64),
|
|
76
|
+
self.conv_block(64, 128),
|
|
77
|
+
self.downsample2x2(128),
|
|
78
|
+
self.conv_block(128, 256),
|
|
79
|
+
self.downsample2x2(256),
|
|
80
|
+
self.conv_block(256, 256),
|
|
81
|
+
self.downsample2x2(256),
|
|
82
|
+
self.conv_block(256, 256),
|
|
83
|
+
self.downsample2x2(256),
|
|
84
|
+
self.conv_block(256, 256),
|
|
85
|
+
self.last_conv
|
|
86
|
+
)
|
|
87
|
+
def forward(self, x:torch.Tensor)-> torch.Tensor:
|
|
88
|
+
x = self.network(x).flatten(1)
|
|
89
|
+
return self.disc_out(x), self.classifier_out(x)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
|
|
5
|
+
gp_beta = 10
|
|
6
|
+
pitch_beta = 10
|
|
7
|
+
crossentropy = nn.CrossEntropyLoss()
|
|
8
|
+
|
|
9
|
+
# https://github.com/EmilienDupont/wgan-gp/
|
|
10
|
+
def gradient_penalty(real_data, fake_data, batch_size, disc, device):
|
|
11
|
+
alpha = torch.rand(batch_size, 1, 1, 1)
|
|
12
|
+
alpha = alpha.expand_as(real_data).to(device)
|
|
13
|
+
interpolated = alpha * real_data.detach() + (1 - alpha) * fake_data.detach()
|
|
14
|
+
interpolated = torch.autograd.Variable(interpolated, requires_grad=True)
|
|
15
|
+
prob, _ = disc(interpolated)
|
|
16
|
+
gradients = torch.autograd.grad(outputs = prob,
|
|
17
|
+
inputs = interpolated,
|
|
18
|
+
grad_outputs = torch.ones_like(prob),
|
|
19
|
+
create_graph = True, retain_graph = True)[0]
|
|
20
|
+
|
|
21
|
+
gradients = gradients.view(batch_size, -1)
|
|
22
|
+
gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean()
|
|
23
|
+
return gradient_penalty
|
|
24
|
+
|
|
25
|
+
def create_fake_data(generator, config):
|
|
26
|
+
fake_pitch = torch.randint( 0, 61, (config.batch_size,)).unsqueeze(1).to(config.device)
|
|
27
|
+
fake_pitch_vector = torch.zeros(config.batch_size, 61).to(config.device).scatter_(1, fake_pitch, 1).unsqueeze(2).unsqueeze(3).to(config.device)
|
|
28
|
+
noise = torch.randn(config.batch_size, config.latent_size, 1, 1).to(config.device)
|
|
29
|
+
gen_input = torch.cat((noise, fake_pitch_vector), 1)
|
|
30
|
+
fake_mel = generator(gen_input)
|
|
31
|
+
return fake_pitch, fake_mel
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# based on https://github.com/jik876/hifi-gan
|
|
2
|
+
# only v1 implemented
|
|
3
|
+
|
|
4
|
+
import torch
|
|
5
|
+
from torch import nn
|
|
6
|
+
from torch.nn.utils import remove_weight_norm
|
|
7
|
+
from torch.nn.utils.parametrizations import weight_norm
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResidualBlock(torch.nn.Module):
|
|
11
|
+
def __init__(self, channels:int, kernel_size:int = 3, dilations:list[int] = [1, 3, 5]):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.conv = lambda d: weight_norm(
|
|
14
|
+
nn.Conv1d(channels, channels, kernel_size, 1,
|
|
15
|
+
dilation = d, padding = (kernel_size * d - d) // 2)
|
|
16
|
+
)
|
|
17
|
+
self.convs = nn.Sequential()
|
|
18
|
+
for d in dilations:
|
|
19
|
+
self.convs.extend(nn.Sequential(*[
|
|
20
|
+
nn.LeakyReLU(0.1), self.conv(d), nn.LeakyReLU(0.1), self.conv(1)
|
|
21
|
+
]))
|
|
22
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
23
|
+
return x + self.convs(x)
|
|
24
|
+
|
|
25
|
+
def remove_weight_norm(self):
|
|
26
|
+
for l in self.convs:
|
|
27
|
+
if type(l) == nn.Conv1d:
|
|
28
|
+
remove_weight_norm(l)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class UpsamplingBlock(torch.nn.Module):
|
|
32
|
+
def __init__(self, in_channels:int, out_channels:int, kernel_size:int, stride:int,
|
|
33
|
+
res_channels:int, res_kernels:list[int], res_dilations:list[int]):
|
|
34
|
+
assert(len(res_kernels) == len(res_dilations))
|
|
35
|
+
super().__init__()
|
|
36
|
+
self.num_res_blocks = len(res_kernels)
|
|
37
|
+
self.relu = nn.LeakyReLU(0.1)
|
|
38
|
+
self.conv_transpose = nn.ConvTranspose1d(
|
|
39
|
+
in_channels,out_channels, kernel_size, stride,
|
|
40
|
+
(kernel_size - stride ) // 2)
|
|
41
|
+
self.res_blocks = nn.ModuleList(
|
|
42
|
+
[ResidualBlock(res_channels, res_kernels[i], res_dilations)
|
|
43
|
+
for i in range(self.num_res_blocks)]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
47
|
+
x = self.conv_transpose(self.relu(x))
|
|
48
|
+
xs = 0
|
|
49
|
+
for res_block in self.res_blocks:
|
|
50
|
+
xs += res_block(x)
|
|
51
|
+
x = xs / self.num_res_blocks
|
|
52
|
+
return x
|
|
53
|
+
|
|
54
|
+
def remove_weight_norm(self):
|
|
55
|
+
remove_weight_norm(self.conv_transpose)
|
|
56
|
+
for res_block in self.res_blocks:
|
|
57
|
+
res_block.remove_weight_norm()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
|
|
3
|
+
def feature_loss(fmap_real:list, fmap_fake:list):
|
|
4
|
+
loss = 0
|
|
5
|
+
for disc_real, disc_fake in zip(fmap_real, fmap_fake):
|
|
6
|
+
for layer_real, layer_fake in zip(disc_real, disc_fake):
|
|
7
|
+
loss += torch.mean(torch.abs(layer_real - layer_fake))
|
|
8
|
+
return loss * 2
|
|
9
|
+
|
|
10
|
+
def discriminator_loss(disc_real:list, disc_fake:list):
|
|
11
|
+
loss = 0
|
|
12
|
+
real_losses = []
|
|
13
|
+
fake_losses = []
|
|
14
|
+
for subdisc_real, subdisc_fake in zip(disc_real, disc_fake):
|
|
15
|
+
real_loss = torch.mean((1 - subdisc_real) ** 2)
|
|
16
|
+
fake_loss = torch.mean(subdisc_fake ** 2)
|
|
17
|
+
loss += (real_loss + fake_loss)
|
|
18
|
+
real_losses.append(real_loss.item())
|
|
19
|
+
fake_losses.append(fake_loss.item())
|
|
20
|
+
return loss, real_losses, fake_losses
|
|
21
|
+
|
|
22
|
+
def generator_loss(disc_outputs:list):
|
|
23
|
+
loss = 0
|
|
24
|
+
generator_losses = []
|
|
25
|
+
for subdisc_fake in disc_outputs:
|
|
26
|
+
l = torch.mean((1 - subdisc_fake) ** 2)
|
|
27
|
+
generator_losses.append(l)
|
|
28
|
+
loss += l
|
|
29
|
+
return loss, generator_losses
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# based on https://github.com/jik876/hifi-gan
|
|
2
|
+
# only v1 implemented
|
|
3
|
+
#
|
|
4
|
+
import torch
|
|
5
|
+
from .blocks import ResidualBlock
|
|
6
|
+
from .blocks import UpsamplingBlock
|
|
7
|
+
|
|
8
|
+
from torch import nn
|
|
9
|
+
import torch.nn.functional as F
|
|
10
|
+
from torch.nn.utils.parametrizations import weight_norm, spectral_norm
|
|
11
|
+
from torch.nn.utils import remove_weight_norm
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Generator(torch.nn.Module):
|
|
15
|
+
def __init__(self,
|
|
16
|
+
n_mels,
|
|
17
|
+
upsample_kernels,
|
|
18
|
+
upsample_strides,
|
|
19
|
+
upsample_start,
|
|
20
|
+
residual_kernels,
|
|
21
|
+
residual_dilations
|
|
22
|
+
):
|
|
23
|
+
super().__init__()
|
|
24
|
+
assert(len(upsample_kernels) == len(upsample_strides))
|
|
25
|
+
self.num_upsamples = len(upsample_kernels)
|
|
26
|
+
self.num_res_blocks = len(residual_kernels)
|
|
27
|
+
self.relu = nn.LeakyReLU(0.1)
|
|
28
|
+
self.tanh = nn.Tanh()
|
|
29
|
+
self.initial_conv = weight_norm(nn.Conv1d(n_mels, upsample_start, 7, 1, 3))
|
|
30
|
+
self.upsample = nn.Sequential(*[UpsamplingBlock(
|
|
31
|
+
upsample_start // (2 ** i),
|
|
32
|
+
upsample_start // (2 ** (i + 1)),
|
|
33
|
+
upsample_kernels[i],
|
|
34
|
+
upsample_strides[i],
|
|
35
|
+
upsample_start // (2 ** (i + 1)),
|
|
36
|
+
residual_kernels,
|
|
37
|
+
residual_dilations
|
|
38
|
+
) for i in range(self.num_upsamples)])
|
|
39
|
+
self.final_conv = weight_norm(nn.Conv1d(
|
|
40
|
+
upsample_start//(2 ** (self.num_upsamples)), 1, 7, 1, 3)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
44
|
+
x = self.initial_conv(x)
|
|
45
|
+
x = self.upsample(x)
|
|
46
|
+
x = self.relu(x)
|
|
47
|
+
x = self.final_conv(x)
|
|
48
|
+
x = self.tanh(x)
|
|
49
|
+
return x
|
|
50
|
+
|
|
51
|
+
def remove_weight_norm(self):
|
|
52
|
+
remove_weight_norm(self.initial_conv)
|
|
53
|
+
for u in self.upsample.modules():
|
|
54
|
+
u.remove_weight_norm()
|
|
55
|
+
remove_weight_norm(self.final_conv)
|
|
56
|
+
|
|
57
|
+
class PeriodDiscriminator(torch.nn.Module):
|
|
58
|
+
def __init__(self, period:int, kernel_size:int = 5, stride:int = 3):
|
|
59
|
+
super().__init__()
|
|
60
|
+
self.period = period
|
|
61
|
+
self.conv = lambda in_c, out_c: weight_norm(
|
|
62
|
+
nn.Conv2d(in_c, out_c,
|
|
63
|
+
(kernel_size, 1), (stride, 1),
|
|
64
|
+
((kernel_size -1)//2, 0))
|
|
65
|
+
)
|
|
66
|
+
self.convs = nn.ModuleList([
|
|
67
|
+
self.conv(1, 32),
|
|
68
|
+
self.conv(32, 128),
|
|
69
|
+
self.conv(128, 512),
|
|
70
|
+
self.conv(512, 1024),
|
|
71
|
+
weight_norm(nn.Conv2d(1024, 1024,
|
|
72
|
+
(kernel_size, 1), 1, (2, 0)))
|
|
73
|
+
])
|
|
74
|
+
self.final_conv = weight_norm(
|
|
75
|
+
nn.Conv2d(1024, 1, (3, 1), 1, (1, 0))
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
79
|
+
fmap = []
|
|
80
|
+
n_batches, n_chans, n_frames = x.shape
|
|
81
|
+
if n_frames % self.period != 0:
|
|
82
|
+
n_pad = self.period - (n_frames % self.period)
|
|
83
|
+
x = F.pad(x, (0, n_pad), "reflect")
|
|
84
|
+
n_frames += n_pad
|
|
85
|
+
x = x.view(n_batches, n_chans, n_frames // self.period, self.period)
|
|
86
|
+
|
|
87
|
+
for conv in self.convs:
|
|
88
|
+
x = F.leaky_relu(conv(x), 0.1)
|
|
89
|
+
fmap.append(x)
|
|
90
|
+
x = self.final_conv(x)
|
|
91
|
+
fmap.append(x)
|
|
92
|
+
return x.flatten(1, -1), fmap
|
|
93
|
+
|
|
94
|
+
class MultiPeriodDiscriminator(torch.nn.Module):
|
|
95
|
+
def __init__(self):
|
|
96
|
+
super().__init__()
|
|
97
|
+
self.sub_discriminators = nn.ModuleList([
|
|
98
|
+
PeriodDiscriminator(n) for n in [2, 3, 5, 7, 11]
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
def forward(self, y:torch.Tensor, y_hat:torch.Tensor):
|
|
102
|
+
y_real = []
|
|
103
|
+
y_fake = []
|
|
104
|
+
fmap_real = []
|
|
105
|
+
fmap_fake = []
|
|
106
|
+
for d in self.sub_discriminators:
|
|
107
|
+
y_r, fmap_r = d(y)
|
|
108
|
+
y_real.append(y_r)
|
|
109
|
+
fmap_real.append(fmap_r)
|
|
110
|
+
y_f, fmap_f = d(y_hat)
|
|
111
|
+
y_fake.append(y_f)
|
|
112
|
+
fmap_fake.append(fmap_f)
|
|
113
|
+
return y_real, y_fake, fmap_real, fmap_fake
|
|
114
|
+
|
|
115
|
+
class ScaleDiscriminator(torch.nn.Module):
|
|
116
|
+
def __init__(self, use_spectral_norm:bool = False):
|
|
117
|
+
super().__init__()
|
|
118
|
+
norm = spectral_norm if not use_spectral_norm else weight_norm
|
|
119
|
+
self.convs = nn.ModuleList([
|
|
120
|
+
norm(nn.Conv1d(1, 128, 15, 1, 7)),
|
|
121
|
+
norm(nn.Conv1d(128, 128, 41, 2, 20, 1, 4)),
|
|
122
|
+
norm(nn.Conv1d(128, 256, 41, 2, 20, 1, 16)),
|
|
123
|
+
norm(nn.Conv1d(256, 512, 41, 4, 20, 1, 16)),
|
|
124
|
+
norm(nn.Conv1d(512, 1024, 41, 4, 20, 1, 16)),
|
|
125
|
+
norm(nn.Conv1d(1024, 1024, 41, 1, 20, 1, 16)),
|
|
126
|
+
norm(nn.Conv1d(1024, 1024, 5, 1, 2))
|
|
127
|
+
])
|
|
128
|
+
self.final_conv = norm(nn.Conv1d(1024, 1, 3, 1, 1))
|
|
129
|
+
|
|
130
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
131
|
+
fmap = []
|
|
132
|
+
for conv in self.convs:
|
|
133
|
+
x = F.leaky_relu(conv(x), 0.1)
|
|
134
|
+
fmap.append(x)
|
|
135
|
+
x = self.final_conv(x)
|
|
136
|
+
fmap.append(x)
|
|
137
|
+
return x.flatten(1, -1), fmap
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class MultiScaleDiscriminator(torch.nn.Module):
|
|
141
|
+
def __init__(self):
|
|
142
|
+
super().__init__()
|
|
143
|
+
self.sub_discriminators = nn.ModuleList([
|
|
144
|
+
ScaleDiscriminator(use_spectral_norm=True),
|
|
145
|
+
ScaleDiscriminator(),
|
|
146
|
+
ScaleDiscriminator(),
|
|
147
|
+
])
|
|
148
|
+
self.avg_pools = nn.ModuleList([
|
|
149
|
+
nn.AvgPool1d(4, 2, 2),
|
|
150
|
+
nn.AvgPool1d(4, 2, 2)
|
|
151
|
+
])
|
|
152
|
+
|
|
153
|
+
def forward(self, y:torch.Tensor, y_hat:torch.Tensor)->tuple[torch.Tensor,torch.Tensor,torch.Tensor,torch.Tensor]:
|
|
154
|
+
y_real = []
|
|
155
|
+
y_fake = []
|
|
156
|
+
fmap_real = []
|
|
157
|
+
fmap_fake = []
|
|
158
|
+
for i, d in enumerate(self.sub_discriminators):
|
|
159
|
+
if i != 0:
|
|
160
|
+
y = self.avg_pools[i-1](y)
|
|
161
|
+
y_hat = self.avg_pools[i-1](y_hat)
|
|
162
|
+
y_r, fmap_r = d(y)
|
|
163
|
+
y_real.append(y_r)
|
|
164
|
+
fmap_real.append(fmap_r)
|
|
165
|
+
y_f, fmap_f = d(y_hat)
|
|
166
|
+
y_fake.append(y_f)
|
|
167
|
+
fmap_fake.append(fmap_f)
|
|
168
|
+
return y_real, y_fake, fmap_real, fmap_fake
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
import torch.fft as fft
|
|
5
|
+
|
|
6
|
+
# From
|
|
7
|
+
# https://github.com/acids-ircam/RAVE/blob/master/rave/core.py
|
|
8
|
+
|
|
9
|
+
def mod_sigmoid(x):
|
|
10
|
+
return 2 * torch.sigmoid(x)**2.3 + 1e-7
|
|
11
|
+
|
|
12
|
+
def get_augmented_latent_size(latent_size: int, noise_augmentation: int):
|
|
13
|
+
return latent_size + noise_augmentation
|
|
14
|
+
|
|
15
|
+
def amp_to_impulse_response(amp, target_size):
|
|
16
|
+
"""
|
|
17
|
+
transforms frequency amps to ir on the last dimension
|
|
18
|
+
"""
|
|
19
|
+
amp = torch.stack([amp, torch.zeros_like(amp)], -1)
|
|
20
|
+
amp = torch.view_as_complex(amp)
|
|
21
|
+
amp = fft.irfft(amp)
|
|
22
|
+
|
|
23
|
+
filter_size = amp.shape[-1]
|
|
24
|
+
|
|
25
|
+
amp = torch.roll(amp, filter_size // 2, -1)
|
|
26
|
+
win = torch.hann_window(filter_size, dtype=amp.dtype, device=amp.device)
|
|
27
|
+
|
|
28
|
+
amp = amp * win
|
|
29
|
+
|
|
30
|
+
amp = F.pad(
|
|
31
|
+
amp,
|
|
32
|
+
(0, int(target_size) - int(filter_size)),
|
|
33
|
+
)
|
|
34
|
+
amp = torch.roll(amp, -filter_size // 2, -1)
|
|
35
|
+
|
|
36
|
+
return amp
|
|
37
|
+
|
|
38
|
+
def fft_convolve(signal, kernel):
|
|
39
|
+
"""
|
|
40
|
+
convolves signal by kernel on the last dimension
|
|
41
|
+
"""
|
|
42
|
+
signal = F.pad(signal, (0, signal.shape[-1]))
|
|
43
|
+
kernel = F.pad(kernel, (kernel.shape[-1], 0))
|
|
44
|
+
output = fft.irfft(fft.rfft(signal) * fft.rfft(kernel))
|
|
45
|
+
output = output[..., output.shape[-1] // 2:]
|
|
46
|
+
return output
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from torch.nn.utils.parametrizations import weight_norm
|
|
4
|
+
from torch.nn import Conv1d, Sequential
|
|
5
|
+
|
|
6
|
+
class Discriminator(nn.Module):
|
|
7
|
+
def __init__(self, in_channels:int, out_channels:int, n_layers:int, stride:int):
|
|
8
|
+
super().__init__()
|
|
9
|
+
layers = []
|
|
10
|
+
for i in range(n_layers):
|
|
11
|
+
layers.append(
|
|
12
|
+
Sequential(
|
|
13
|
+
weight_norm(
|
|
14
|
+
Conv1d(in_channels, out_channels,
|
|
15
|
+
15, stride, padding = 7)
|
|
16
|
+
),
|
|
17
|
+
nn.LeakyReLU(0.2)
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
in_channels = out_channels
|
|
21
|
+
out_channels = out_channels * 2
|
|
22
|
+
layers.append(Conv1d(in_channels, 1, 1))
|
|
23
|
+
self.layers = Sequential(*layers)
|
|
24
|
+
|
|
25
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
26
|
+
features = []
|
|
27
|
+
for layer in self.layers:
|
|
28
|
+
x = layer(x)
|
|
29
|
+
# the original RAVE appends the outputs of convs
|
|
30
|
+
# here we follow hifigan and use the output of the LeakyReLU
|
|
31
|
+
features.append(x)
|
|
32
|
+
return features
|
|
33
|
+
|
|
34
|
+
class MultiScaleDiscriminator(nn.Module):
|
|
35
|
+
|
|
36
|
+
def __init__(self, in_channels:int, out_channels:int, n_scales:int = 3):
|
|
37
|
+
super().__init__()
|
|
38
|
+
self.n_scales = n_scales
|
|
39
|
+
self.layers = nn.ModuleList([
|
|
40
|
+
Discriminator(in_channels, out_channels, 4, 4) for _ in range(n_scales)
|
|
41
|
+
])
|
|
42
|
+
def forward(self, x:torch.Tensor)->list[torch.Tensor]:
|
|
43
|
+
features = []
|
|
44
|
+
for layer in self.layers:
|
|
45
|
+
features.append(layer(x))
|
|
46
|
+
x = nn.functional.avg_pool1d(x, 2)
|
|
47
|
+
return features
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from torch.nn import Conv1d, Sequential
|
|
4
|
+
import torch.nn.functional as F
|
|
5
|
+
|
|
6
|
+
class Encoder(nn.Module):
|
|
7
|
+
def __init__(self, n_bands:int, capacity:int,
|
|
8
|
+
latent_dim:int, ratios:list[int], n_out:int):
|
|
9
|
+
super().__init__()
|
|
10
|
+
self.input = nn.Conv1d(n_bands, capacity, 7 , padding = 3)
|
|
11
|
+
self.block = lambda n_in, n_out, ratio: Sequential(*[
|
|
12
|
+
nn.BatchNorm1d(n_in),
|
|
13
|
+
nn.LeakyReLU(.2),
|
|
14
|
+
Conv1d(n_in, n_out, 2 * ratio + 1,
|
|
15
|
+
padding = ratio, stride = ratio)
|
|
16
|
+
])
|
|
17
|
+
self.output = Conv1d(
|
|
18
|
+
2 ** len(ratios) * capacity, latent_dim * n_out, 5,
|
|
19
|
+
padding = 2, groups = n_out,
|
|
20
|
+
)
|
|
21
|
+
layers = [self.input]
|
|
22
|
+
for i, r in enumerate(ratios):
|
|
23
|
+
layers += self.block( 2**i * capacity, 2**(i + 1) * capacity, r)
|
|
24
|
+
layers += [nn.LeakyReLU(.2), self.output]
|
|
25
|
+
self.net = Sequential(*layers)
|
|
26
|
+
|
|
27
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
28
|
+
return self.net(x)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
from torch.nn import Conv1d, ConvTranspose1d, Sequential
|
|
4
|
+
import torch.nn.functional as F
|
|
5
|
+
from torch.nn.utils.parametrizations import weight_norm
|
|
6
|
+
import numpy as np
|
|
7
|
+
from .core_funcs import mod_sigmoid, amp_to_impulse_response, fft_convolve
|
|
8
|
+
|
|
9
|
+
class ResidualLayer(nn.Module):
|
|
10
|
+
def __init__(self, dim:int, kernel_size:int, dilations:list[int]):
|
|
11
|
+
super().__init__()
|
|
12
|
+
layers = []
|
|
13
|
+
for d in dilations:
|
|
14
|
+
layers+=[nn.LeakyReLU(0.2),
|
|
15
|
+
weight_norm(Conv1d(dim, dim, kernel_size,
|
|
16
|
+
padding = d, dilation = d))]
|
|
17
|
+
self.net = Sequential(*layers)
|
|
18
|
+
|
|
19
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
20
|
+
return x + self.net(x)
|
|
21
|
+
|
|
22
|
+
class ResidualStack(nn.Module):
|
|
23
|
+
def __init__(self,
|
|
24
|
+
dim,
|
|
25
|
+
kernel_size,
|
|
26
|
+
dilations_list):
|
|
27
|
+
super().__init__()
|
|
28
|
+
self.net = Sequential(*[
|
|
29
|
+
ResidualLayer(
|
|
30
|
+
dim,
|
|
31
|
+
kernel_size,
|
|
32
|
+
dilations
|
|
33
|
+
) for dilations in dilations_list]
|
|
34
|
+
)
|
|
35
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
36
|
+
return self.net(x)
|
|
37
|
+
|
|
38
|
+
class NoiseGenerator(nn.Module):
|
|
39
|
+
def __init__(self, in_size:int, n_bands:int, ratios:list[int], noise_bands:int):
|
|
40
|
+
super().__init__()
|
|
41
|
+
net = []
|
|
42
|
+
channels = [in_size] * len(ratios) + [n_bands * noise_bands]
|
|
43
|
+
for i, r in enumerate(ratios):
|
|
44
|
+
net.append(
|
|
45
|
+
Conv1d(channels[i], channels[i + 1], 3, stride=r))
|
|
46
|
+
if i != len(ratios) - 1:
|
|
47
|
+
net.append(nn.LeakyReLU(.2))
|
|
48
|
+
self.net = Sequential(*net)
|
|
49
|
+
self.n_bands = n_bands
|
|
50
|
+
self.register_buffer(
|
|
51
|
+
"target_size",
|
|
52
|
+
torch.tensor(np.prod(ratios)).long(),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
56
|
+
amp = mod_sigmoid(self.net(x) - 5)
|
|
57
|
+
amp = amp.permute(0, 2, 1)
|
|
58
|
+
amp = amp.reshape(amp.shape[0], amp.shape[1], self.n_bands, -1)
|
|
59
|
+
ir = amp_to_impulse_response(amp, self.target_size)
|
|
60
|
+
noise = torch.rand_like(ir) * 2 - 1
|
|
61
|
+
noise = fft_convolve(noise, ir).permute(0, 2, 1, 3)
|
|
62
|
+
noise = noise.reshape(noise.shape[0], noise.shape[1], -1)
|
|
63
|
+
return noise
|
|
64
|
+
|
|
65
|
+
class Generator(nn.Module):
|
|
66
|
+
def __init__(self, latent_dim:int, capacity:int,
|
|
67
|
+
n_bands:int, ratios:list[int]):
|
|
68
|
+
super().__init__()
|
|
69
|
+
self.input = weight_norm(
|
|
70
|
+
Conv1d(
|
|
71
|
+
latent_dim, 2 ** len(ratios) * capacity,
|
|
72
|
+
7, padding = 3
|
|
73
|
+
))
|
|
74
|
+
self.block = lambda n_in, n_out, ratio: Sequential(*[
|
|
75
|
+
nn.LeakyReLU(.2),
|
|
76
|
+
ConvTranspose1d(n_in, n_out, 2 * ratio, ratio, ratio // 2),
|
|
77
|
+
ResidualStack(n_out,[3], [[1, 1], [3, 1], [5, 1]])
|
|
78
|
+
])
|
|
79
|
+
self.wave_gen = weight_norm(
|
|
80
|
+
Conv1d(capacity, n_bands, 7, padding = 3)
|
|
81
|
+
)
|
|
82
|
+
self.loud_gen = weight_norm(
|
|
83
|
+
Conv1d(capacity, 1, 3, padding = 1)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.noise_gen = NoiseGenerator(capacity, n_bands, [4, 4, 4], 5)
|
|
87
|
+
|
|
88
|
+
layers = [self.input]
|
|
89
|
+
for i, r in enumerate(ratios):
|
|
90
|
+
layers += self.block( 2**(len(ratios) - i) * capacity, 2**(len(ratios) - i - 1) * capacity, r)
|
|
91
|
+
self.net = Sequential(*layers)
|
|
92
|
+
self.branches = [self.wave_gen, self.loud_gen, self.noise_gen]
|
|
93
|
+
self.add_noise = False
|
|
94
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
95
|
+
x = self.net(x)
|
|
96
|
+
waveform = self.wave_gen(x)
|
|
97
|
+
loudness = self.loud_gen(x)
|
|
98
|
+
noise = self.noise_gen(x)
|
|
99
|
+
loudness = loudness.reshape(x.shape[0], 1, -1)
|
|
100
|
+
waveform = torch.tanh(waveform) * mod_sigmoid(loudness)
|
|
101
|
+
if self.add_noise: waveform += noise
|
|
102
|
+
return waveform
|
fakesound/rave/model.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
from .encoder import Encoder
|
|
5
|
+
from .generator import Generator
|
|
6
|
+
|
|
7
|
+
class Rave(nn.Module):
|
|
8
|
+
def __init__(self, n_bands:int, capacity:int,
|
|
9
|
+
latent_dim:int, ratios:list[int], n_out:int, beta:float = 1.):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.encoder = Encoder(n_bands, capacity, latent_dim, ratios, n_out)
|
|
12
|
+
self.generator = Generator(latent_dim, capacity, n_bands, ratios)
|
|
13
|
+
self.beta = beta
|
|
14
|
+
|
|
15
|
+
def encode(self, x:torch.Tensor)->tuple[torch.Tensor, torch.Tensor]:
|
|
16
|
+
z = self.encoder(x)
|
|
17
|
+
mean, scale = z.chunk(2, 1)
|
|
18
|
+
std = F.softplus(scale) + 1e-4
|
|
19
|
+
return mean, std
|
|
20
|
+
|
|
21
|
+
def decode(self, x:torch.Tensor)->torch.Tensor:
|
|
22
|
+
return self.generator(x)
|
|
23
|
+
|
|
24
|
+
def reparametrize(self, mean:torch.Tensor, std:torch.Tensor)->torch.Tensor:
|
|
25
|
+
z = mean + torch.randn_like(mean) * std
|
|
26
|
+
return z
|
|
27
|
+
|
|
28
|
+
def forward(self, x:torch.Tensor)->torch.Tensor:
|
|
29
|
+
mean, logvar = self.encode(x)
|
|
30
|
+
z = self.reparametrize(mean, logvar)
|
|
31
|
+
return self.decode(z)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
|
|
5
|
+
class SampleLevelModule(nn.Module):
|
|
6
|
+
def __init__(self, frame_size:int, embedding_size:int, dim:int, num_levels:int):
|
|
7
|
+
nn.Module.__init__(self)
|
|
8
|
+
self.num_levels = num_levels
|
|
9
|
+
self.embedding = nn.Embedding(
|
|
10
|
+
num_levels,
|
|
11
|
+
embedding_size
|
|
12
|
+
)
|
|
13
|
+
self.input = nn.Conv1d(num_levels, dim, frame_size, bias = False)
|
|
14
|
+
self.hidden = nn.Sequential(
|
|
15
|
+
nn.Conv1d(dim, dim, 1),
|
|
16
|
+
nn.ReLU(),
|
|
17
|
+
nn.Conv1d(dim, dim,1),
|
|
18
|
+
nn.ReLU()
|
|
19
|
+
)
|
|
20
|
+
self.output = nn.Conv1d(dim, num_levels, 1)
|
|
21
|
+
|
|
22
|
+
def forward(self, x:torch.Tensor, cond:torch.Tensor):
|
|
23
|
+
x = self.embedding(x)
|
|
24
|
+
# the following steps are implemented using Conv1d,
|
|
25
|
+
# so here per-sample vector becomes channels
|
|
26
|
+
x = x.permute(0, 2, 1)
|
|
27
|
+
cond = cond.permute(0, 2, 1)
|
|
28
|
+
x = self.input(x)
|
|
29
|
+
x = x + cond
|
|
30
|
+
x = self.hidden(x)
|
|
31
|
+
x = self.output(x)
|
|
32
|
+
# back to samples * levels
|
|
33
|
+
x = x.permute(0, 2, 1)
|
|
34
|
+
return x
|
|
35
|
+
|
|
36
|
+
class FrameLevelModule(nn.Module):
|
|
37
|
+
def __init__(self, frame_size:int, num_steps:int,
|
|
38
|
+
upsampling_factor:int, num_layers:int, dim:int):
|
|
39
|
+
nn.Module.__init__(self)
|
|
40
|
+
self.frame_size = frame_size
|
|
41
|
+
self.state = None
|
|
42
|
+
self.num_layers = num_layers
|
|
43
|
+
self.num_steps = num_steps
|
|
44
|
+
self.upsampling_factor = upsampling_factor
|
|
45
|
+
self.dim = dim
|
|
46
|
+
self.input = nn.Linear(
|
|
47
|
+
frame_size,
|
|
48
|
+
dim,
|
|
49
|
+
bias = False
|
|
50
|
+
)
|
|
51
|
+
self.rnn = nn.GRU(dim, dim, num_layers,
|
|
52
|
+
bias = True, batch_first = True)
|
|
53
|
+
self.upsampling = nn.ConvTranspose1d(dim, dim, upsampling_factor, upsampling_factor, bias = False)
|
|
54
|
+
|
|
55
|
+
def forward(self, x:torch.tensor, reset:bool, cond:torch.Tensor)->torch.Tensor:
|
|
56
|
+
x = self.input(x) + (cond if cond is not None else 0)
|
|
57
|
+
# reset applies to whole batch
|
|
58
|
+
if reset or self.state == None:
|
|
59
|
+
batch_size = x.shape[0]
|
|
60
|
+
self.state = torch.zeros(self.num_layers, batch_size, self.dim)
|
|
61
|
+
x, h = self.rnn(x, self.state)
|
|
62
|
+
self.state = h.detach()
|
|
63
|
+
# ConvTranspose1D upsamples on last dimension
|
|
64
|
+
x = self.upsampling(x.permute(0, 2, 1)).permute(0, 2, 1)
|
|
65
|
+
return x
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
import torch
|
|
3
|
+
from torch import nn
|
|
4
|
+
from torch.nn import functional as F
|
|
5
|
+
from .blocks import FrameLevelModule, SampleLevelModule
|
|
6
|
+
|
|
7
|
+
class SampleRNN(nn.Module):
|
|
8
|
+
def __init__(self, seq_len:int, sizes:list[int], dim:int,
|
|
9
|
+
rnn_layers:int, num_levels:int):
|
|
10
|
+
nn.Module.__init__(self)
|
|
11
|
+
self.dim = dim
|
|
12
|
+
self.num_levels = num_levels
|
|
13
|
+
self.top_frame = sizes[-1]
|
|
14
|
+
self.bottom_frame = sizes[0]
|
|
15
|
+
self.seq_len = seq_len
|
|
16
|
+
|
|
17
|
+
self.rnns = nn.ModuleList()
|
|
18
|
+
steps_below = self.seq_len
|
|
19
|
+
for frame_size in sizes: # from bottom to top rnn
|
|
20
|
+
num_steps = self.seq_len // frame_size
|
|
21
|
+
self.rnns.append(FrameLevelModule(frame_size,
|
|
22
|
+
num_steps,
|
|
23
|
+
steps_below// num_steps,
|
|
24
|
+
rnn_layers,
|
|
25
|
+
dim))
|
|
26
|
+
steps_below = num_steps
|
|
27
|
+
self.mlp = SampleLevelModule(self.bottom_frame,
|
|
28
|
+
self.num_levels, dim, self.num_levels)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def lookback(self):
|
|
32
|
+
return self.top_frame
|
|
33
|
+
|
|
34
|
+
def reset(self):
|
|
35
|
+
for rnn in self.rnns: rnn.state = None
|
|
36
|
+
|
|
37
|
+
def forward(self, x:torch.Tensor, original:torch.Tensor, reset = True)->torch.Tensor:
|
|
38
|
+
assert(x.shape[1] == self.seq_len+self.top_frame-1)
|
|
39
|
+
batch_size = x.shape[0]
|
|
40
|
+
cond = None
|
|
41
|
+
for rnn in reversed(self.rnns):
|
|
42
|
+
start = self.top_frame - rnn.frame_size
|
|
43
|
+
end = -rnn.frame_size + 1
|
|
44
|
+
rnn_input = original[:, start:end]
|
|
45
|
+
rnn_input = rnn_input.contiguous().view(batch_size, -1, rnn.frame_size)
|
|
46
|
+
cond = rnn(rnn_input, reset, cond)
|
|
47
|
+
out = self.mlp(x[:,self.top_frame - self.bottom_frame:], cond)
|
|
48
|
+
return out
|
|
49
|
+
|
|
50
|
+
def generate(self, batch_size:int, seq_len:int, decoder:Callable, temp:float = 1.0)->torch.Tensor:
|
|
51
|
+
device = next(self.parameters()).device
|
|
52
|
+
input_size = seq_len + self.lookback
|
|
53
|
+
samples = torch.full((batch_size, input_size), self.num_levels// 2, device = device)
|
|
54
|
+
frame_outs = [None for _ in self.rnns]
|
|
55
|
+
cond = None
|
|
56
|
+
self.reset()
|
|
57
|
+
for i in range(self.lookback, self.lookback + seq_len):
|
|
58
|
+
for (tier, rnn) in reversed(list(enumerate(self.rnns))):
|
|
59
|
+
if i % rnn.frame_size != 0:
|
|
60
|
+
continue
|
|
61
|
+
prev_samples = decoder(samples[:, i - rnn.frame_size : i])
|
|
62
|
+
if tier == len(self.rnns) - 1:
|
|
63
|
+
cond = None
|
|
64
|
+
else:
|
|
65
|
+
frame_index = (i // rnn.frame_size) % self.rnns[tier + 1].upsampling_factor
|
|
66
|
+
cond = frame_outs[tier + 1][:, frame_index, :].unsqueeze(1)
|
|
67
|
+
rnn_input = prev_samples.contiguous().view(batch_size, -1, rnn.frame_size)
|
|
68
|
+
frame_outs[tier] = rnn(rnn_input, False, cond)
|
|
69
|
+
mlp_input = samples[:, i - self.bottom_frame : i]
|
|
70
|
+
cond = frame_outs[0][:, i % self.bottom_frame, :].unsqueeze(1)
|
|
71
|
+
out = self.mlp(mlp_input, cond)
|
|
72
|
+
out = out.softmax(2) / temp
|
|
73
|
+
samples[:, i] = out.squeeze(1).multinomial(1).squeeze(1)
|
|
74
|
+
self.reset() # allow generation of different batch size
|
|
75
|
+
return samples[:, self.lookback :]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import sys, json, torch
|
|
2
|
+
from collections import namedtuple
|
|
3
|
+
|
|
4
|
+
def get_config(default_filename:str):
|
|
5
|
+
config_file = default_filename
|
|
6
|
+
if len(sys.argv) > 1: config_file = sys.argv[1]
|
|
7
|
+
f = open(config_file)
|
|
8
|
+
try:
|
|
9
|
+
data = json.load(f)
|
|
10
|
+
except:
|
|
11
|
+
print("Error parsing configuration file")
|
|
12
|
+
sys.exit()
|
|
13
|
+
|
|
14
|
+
return namedtuple('Config', data.keys())(**data)
|
|
15
|
+
|
|
16
|
+
def save_model(model:torch.nn.Module,
|
|
17
|
+
optimizer:torch.optim.Optimizer,
|
|
18
|
+
step:int, path:str):
|
|
19
|
+
torch.save({
|
|
20
|
+
'model': model.state_dict(),
|
|
21
|
+
'optimizer': optimizer.state_dict(),
|
|
22
|
+
'step': step,
|
|
23
|
+
}, path)
|
|
24
|
+
|
|
25
|
+
def load_model(path:str, model:torch.nn.Module,
|
|
26
|
+
optimizer:torch.optim.Optimizer):
|
|
27
|
+
checkpoint = torch.load(path)
|
|
28
|
+
model.load_state_dict(checkpoint['model'])
|
|
29
|
+
optimizer.load_state_dict(checkpoint['optimizer'])
|
|
30
|
+
step = checkpoint['step']
|
|
31
|
+
return step
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
from .layers import GatedDilatedConv1d
|
|
5
|
+
|
|
6
|
+
class WavenetBlock (nn.Module):
|
|
7
|
+
def __init__(self, dilation_channels, residual_channels, skip_channels,
|
|
8
|
+
dilations, kernel_size = 2, bias = False):
|
|
9
|
+
super().__init__()
|
|
10
|
+
self.layers = nn.ModuleList([
|
|
11
|
+
GatedDilatedConv1d(dilation_channels, residual_channels, skip_channels,
|
|
12
|
+
d, kernel_size, bias)
|
|
13
|
+
for d in dilations])
|
|
14
|
+
|
|
15
|
+
def forward(self, x:torch.Tensor, skip)->torch.Tensor:
|
|
16
|
+
for l in self.layers:
|
|
17
|
+
x, skip = l(x, skip)
|
|
18
|
+
return x, skip
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import torch.nn as nn
|
|
2
|
+
import torch.nn.functional as F
|
|
3
|
+
import torch
|
|
4
|
+
class CausalConv1d(nn.Module):
|
|
5
|
+
def __init__(self, in_channels:int, out_channels:int, kernel_size:int = 2 , bias:bool = False):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.pad = (1, -1) # enforce causality
|
|
8
|
+
self.conv = nn.Conv1d(
|
|
9
|
+
in_channels,
|
|
10
|
+
out_channels,
|
|
11
|
+
kernel_size,
|
|
12
|
+
bias = bias
|
|
13
|
+
)
|
|
14
|
+
def forward(self, x:torch.Tensor, pad = True)->torch.Tensor:
|
|
15
|
+
if pad:
|
|
16
|
+
return self.conv(F.pad(x, self.pad))
|
|
17
|
+
else:
|
|
18
|
+
return self.conv(x)
|
|
19
|
+
|
|
20
|
+
class GatedDilatedConv1d(nn.Module):
|
|
21
|
+
# AKA Wavenet Layer, with residual and skip connections
|
|
22
|
+
def __init__(self, dilation_channels:int, residual_channels:int, skip_channels:int,
|
|
23
|
+
dilation:int, kernel_size:int = 2, bias:bool = False):
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.pad = ((kernel_size - 1) * dilation, 0)
|
|
26
|
+
self.conv1d = lambda in_c, out_c: nn.Conv1d(in_c, out_c, kernel_size,
|
|
27
|
+
bias = bias, dilation = dilation)
|
|
28
|
+
self.conv1d_1x1 = lambda in_c, out_c: nn.Conv1d(in_c, out_c, 1,
|
|
29
|
+
bias = bias, dilation = dilation)
|
|
30
|
+
self.filter_conv = self.conv1d(residual_channels, dilation_channels)
|
|
31
|
+
self.gate_conv = self.conv1d(residual_channels, dilation_channels)
|
|
32
|
+
self.residual_conv = self.conv1d_1x1(dilation_channels, residual_channels)
|
|
33
|
+
self.skip_conv = self.conv1d_1x1(dilation_channels, skip_channels)
|
|
34
|
+
self.test_conv = nn.Conv1d(16, 32, kernel_size)
|
|
35
|
+
|
|
36
|
+
def forward(self, x:torch.Tensor, skip)->tuple[torch.Tensor,torch.Tensor]:
|
|
37
|
+
padded = F.pad(x, self.pad)
|
|
38
|
+
out = F.tanh(self.filter_conv(padded)) * F.sigmoid(self.gate_conv(padded))
|
|
39
|
+
skip_slice = out[:,:,-skip.shape[2]:]
|
|
40
|
+
skip += self.skip_conv(skip_slice)
|
|
41
|
+
return self.residual_conv(out) + x, skip
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch import nn
|
|
3
|
+
import numpy as np
|
|
4
|
+
from .blocks import WavenetBlock
|
|
5
|
+
from .layers import CausalConv1d
|
|
6
|
+
from torch.distributions import Categorical
|
|
7
|
+
|
|
8
|
+
class WaveNet (nn.Module):
|
|
9
|
+
def __init__(self, dilation_channels:int, residual_channels:int, skip_channels:int,
|
|
10
|
+
num_blocks:int, layers_per_block:int, output_length:int,
|
|
11
|
+
dilation_factor:int = 2, kernel_size:int = 2, bias:bool = False, num_classes:int = 256):
|
|
12
|
+
nn.Module.__init__(self)
|
|
13
|
+
self.output_length:int = output_length
|
|
14
|
+
self.num_classes = num_classes
|
|
15
|
+
self.skip_channels:int = skip_channels
|
|
16
|
+
block_dilations = [dilation_factor ** i for i in range(layers_per_block)]
|
|
17
|
+
self.receptive_field:int = (kernel_size - 1) * num_blocks * sum(block_dilations) + 1
|
|
18
|
+
self.causal_conv:CausalConv1d = CausalConv1d(num_classes, residual_channels, kernel_size, bias)
|
|
19
|
+
self.blocks:nn.ModuleList = nn.ModuleList([WavenetBlock(dilation_channels, residual_channels, skip_channels,
|
|
20
|
+
block_dilations, kernel_size, bias)
|
|
21
|
+
for _ in range(num_blocks)])
|
|
22
|
+
self.end_seq = nn.Sequential(
|
|
23
|
+
nn.ReLU(),
|
|
24
|
+
nn.Conv1d(skip_channels, skip_channels, 1, bias = True),
|
|
25
|
+
nn.ReLU(),
|
|
26
|
+
nn.Conv1d(skip_channels, num_classes, 1, bias = True)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def forward(self, x:torch.Tensor, output_length:int = None):
|
|
30
|
+
if output_length == None: output_length = self.output_length
|
|
31
|
+
skip = torch.zeros(x.shape[0], self.skip_channels, output_length)
|
|
32
|
+
x = self.causal_conv(x, self.training)
|
|
33
|
+
for b in self.blocks:
|
|
34
|
+
x, skip = b(x, skip)
|
|
35
|
+
return self.end_seq(skip)
|
|
36
|
+
|
|
37
|
+
def generate(self, batch_size, num_samples:int)->torch.Tensor:
|
|
38
|
+
input_size = self.receptive_field
|
|
39
|
+
device = next(self.parameters()).device
|
|
40
|
+
generated = torch.full((batch_size, input_size), self.num_classes // 2, device = device)
|
|
41
|
+
model_input = torch.zeros((batch_size, self.num_classes, input_size), device = device)
|
|
42
|
+
|
|
43
|
+
for i in range(num_samples):
|
|
44
|
+
model_input.zero_()
|
|
45
|
+
model_input = model_input.scatter_(1, generated[:, -input_size:].view(-1, 1, input_size), 1.)
|
|
46
|
+
out = self.forward(model_input, 1)[:, :, -1]
|
|
47
|
+
pdf = Categorical(logits = out)
|
|
48
|
+
out = pdf.sample()
|
|
49
|
+
generated = torch.cat([generated, out.unsqueeze(1)], 1)
|
|
50
|
+
return generated
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
fakesound/data/dataset.py,sha256=0rch8V3gDoTqbSvNRFG9fF8PiT_S7A_wv8oHVf8_Hb8,2133
|
|
2
|
+
fakesound/data/mel_bands.py,sha256=cUqA-vkhuaHo2oadzJn8vQufPXJpsSaGM32FaELOlCU,1231
|
|
3
|
+
fakesound/data/pqmf.py,sha256=uT04kwkXd3f9XuFSSVik5M-NX2LK_0fQ4w2x7Ybfuj4,764
|
|
4
|
+
fakesound/data/transforms.py,sha256=aXMYucQMiSfnn0GkDqryZBQY5enAitFyrT9dvJyE5IA,6759
|
|
5
|
+
fakesound/gansynth/dataset.py,sha256=Qhdc0gUHmyS3BZEHL5_DqwDz3S-44LyzffhM_wyHINs,1913
|
|
6
|
+
fakesound/gansynth/models.py,sha256=n9gGBmXxd9B44Cs-Ml5-WOtkR4dyTAIaA2uCIk47ySs,3379
|
|
7
|
+
fakesound/gansynth/utils.py,sha256=a98jcKJKV7EGVdi5BPj-bgbrjOfqwETxAfmyE2CVILA,1411
|
|
8
|
+
fakesound/hifigan/blocks.py,sha256=UtwYbsVDq2xYJrLXmuKW6-afVm8ej3-7c7pN-NVjgeg,2135
|
|
9
|
+
fakesound/hifigan/loss_funcs.py,sha256=CtAaFVbRJY-7Z1jGLVgBAa13N5YZCgiOhr6Ps9SRFHE,996
|
|
10
|
+
fakesound/hifigan/models.py,sha256=CYPCLqRjrgIkc35U3n52G3kFBcoHXBEU-eSf4Tl8Elk,5751
|
|
11
|
+
fakesound/rave/core_funcs.py,sha256=y38SQjHdS3ahALxhJZDt04PgvPW8xpzbiYC16yczoQQ,1248
|
|
12
|
+
fakesound/rave/discriminator.py,sha256=X07NfiWmbmnmlLeR2UTZ3ytRj70GZkOqnTwR4LDmjhc,1653
|
|
13
|
+
fakesound/rave/encoder.py,sha256=agU_87F9eYwYjnlW6zdMT6DIIQP6dtbXak4FLIPT2h8,1038
|
|
14
|
+
fakesound/rave/generator.py,sha256=Pi-c77UO75IBUnOuLChZSnGu3FKxaqpAgLZYPAMKiZo,3850
|
|
15
|
+
fakesound/rave/model.py,sha256=FFv22KD2Zeeh68xbOzAG23hqTN-fxPVBwn97BT2Iqsg,1087
|
|
16
|
+
fakesound/samplernn/blocks.py,sha256=FV3A6y_AwmSfOpkFB5Bi_h06icF-Bh7LRaPEV-v41mo,2369
|
|
17
|
+
fakesound/samplernn/model.py,sha256=AoLw6qmvi8T_cZqXbpIdk8xJBCkHhdNaZMf6U8-kwAQ,3295
|
|
18
|
+
fakesound/util/train_utils.py,sha256=NCGBhQRELdjMJ8W2DdJlw5S3NLUeMALcU9cvYZ8MRcg,960
|
|
19
|
+
fakesound/wavenet/blocks.py,sha256=HXTsPCxjoZdio0XwJvS9iG-pTslS0KCuqvRopOwJ5ZA,655
|
|
20
|
+
fakesound/wavenet/layers.py,sha256=cjp6vcGfcEK5EkVsZ4tCUt0UGTBFgHwRYorXBsXhgBQ,1959
|
|
21
|
+
fakesound/wavenet/model.py,sha256=tz_5yRtBir3L2xXehLkz-45lmGciYROYFS-8ELwuTLQ,2501
|
|
22
|
+
fakesound-0.0.0.dist-info/licenses/LICENSE,sha256=9kw0BDLGvrSEZPBlUO1f7JrMReitfq9e74aIlyixxQk,1062
|
|
23
|
+
fakesound-0.0.0.dist-info/METADATA,sha256=kzoYZVW2xwRLBn94Dh0lZ_2EY49mGSQdPfRbs5Z5kNk,121
|
|
24
|
+
fakesound-0.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
25
|
+
fakesound-0.0.0.dist-info/top_level.txt,sha256=jCW2KhTkYY_3ss1hBHdhf-cpa5x0_obFzV30fE-i-So,10
|
|
26
|
+
fakesound-0.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 groma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fakesound
|