Vansh Chugh commited on
Commit
7d124ae
·
1 Parent(s): 28fd8eb

initial deploy

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +3 -0
  2. README.md +1 -1
  3. app.py +337 -0
  4. requirements.txt +19 -0
  5. unison/__init__.py +44 -0
  6. unison/commons/__init__.py +242 -0
  7. unison/commons/infer_state.py +48 -0
  8. unison/commons/parallel_states.py +85 -0
  9. unison/config/D20S0_O_40ch.yaml +27 -0
  10. unison/config/D24S0_O_20ch.yaml +27 -0
  11. unison/models/__init__.py +16 -0
  12. unison/models/mmaudio/__init__.py +1 -0
  13. unison/models/mmaudio/ext/__init__.py +1 -0
  14. unison/models/mmaudio/ext/autoencoder/__init__.py +1 -0
  15. unison/models/mmaudio/ext/autoencoder/autoencoder.py +60 -0
  16. unison/models/mmaudio/ext/autoencoder/distributions.py +45 -0
  17. unison/models/mmaudio/ext/autoencoder/edm2_utils.py +168 -0
  18. unison/models/mmaudio/ext/autoencoder/vae.py +363 -0
  19. unison/models/mmaudio/ext/autoencoder/vae_modules.py +117 -0
  20. unison/models/mmaudio/ext/bigvgan/LICENSE +21 -0
  21. unison/models/mmaudio/ext/bigvgan/__init__.py +1 -0
  22. unison/models/mmaudio/ext/bigvgan/activations.py +120 -0
  23. unison/models/mmaudio/ext/bigvgan/alias_free_torch/__init__.py +6 -0
  24. unison/models/mmaudio/ext/bigvgan/alias_free_torch/act.py +28 -0
  25. unison/models/mmaudio/ext/bigvgan/alias_free_torch/filter.py +95 -0
  26. unison/models/mmaudio/ext/bigvgan/alias_free_torch/resample.py +49 -0
  27. unison/models/mmaudio/ext/bigvgan/bigvgan.py +32 -0
  28. unison/models/mmaudio/ext/bigvgan/bigvgan_vocoder.yml +63 -0
  29. unison/models/mmaudio/ext/bigvgan/env.py +18 -0
  30. unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_1 +21 -0
  31. unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_2 +21 -0
  32. unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_3 +201 -0
  33. unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_4 +29 -0
  34. unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_5 +16 -0
  35. unison/models/mmaudio/ext/bigvgan/models.py +255 -0
  36. unison/models/mmaudio/ext/bigvgan/utils.py +31 -0
  37. unison/models/mmaudio/ext/bigvgan_v2/LICENSE +21 -0
  38. unison/models/mmaudio/ext/bigvgan_v2/__init__.py +0 -0
  39. unison/models/mmaudio/ext/bigvgan_v2/activations.py +126 -0
  40. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/__init__.py +0 -0
  41. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/activation1d.py +77 -0
  42. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation.cpp +23 -0
  43. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation_cuda.cu +246 -0
  44. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/compat.h +29 -0
  45. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/load.py +86 -0
  46. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/type_shim.h +92 -0
  47. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/__init__.py +6 -0
  48. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/act.py +32 -0
  49. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/filter.py +101 -0
  50. unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/resample.py +53 -0
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .DS_Store
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 🐢
4
  colorFrom: red
5
  colorTo: gray
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
  python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
4
  colorFrom: red
5
  colorTo: gray
6
  sdk: gradio
7
+ sdk_version: 5.28.0
8
  python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
app.py ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ sys.stdout.reconfigure(line_buffering=True)
3
+
4
+ import gc
5
+ import tempfile
6
+ import threading
7
+ import traceback
8
+ import types
9
+
10
+ import torch
11
+ import yaml
12
+ import gradio as gr
13
+ from huggingface_hub import hf_hub_download
14
+ from diffusers import FlowMatchEulerDiscreteScheduler
15
+
16
+ try:
17
+ import spaces
18
+ def gpu_decorator(func): return spaces.GPU(func, duration=120)
19
+ except ImportError:
20
+ def gpu_decorator(func): return func
21
+
22
+ from pyharp import ModelCard, build_endpoint
23
+ from unison.models.mmaudio.features_utils import FeaturesUtils
24
+ from unison.pipelines.infer import (
25
+ init_text_hidden_extractor,
26
+ sync_omni_dim_with_text_encoder,
27
+ _load_model,
28
+ sample_latents,
29
+ decode_and_save,
30
+ decode_and_save_full,
31
+ load_source_audio,
32
+ load_ref_audio,
33
+ make_edit_mask,
34
+ downsample_mask,
35
+ join_ref_target_text,
36
+ transcribe_ref_audio,
37
+ MAX_AUDIO_DURATION,
38
+ )
39
+
40
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
41
+ OMNI_MODEL_ID = "Qwen/Qwen2.5-Omni-7B"
42
+ UNISON_REPO = "jac22/UNISON"
43
+ MMAUDIO_REPO = "hkchengrex/MMAudio"
44
+ DEFAULT_VARIANT = "Balanced (44kHz)"
45
+
46
+ VARIANTS = {
47
+ "Balanced (44kHz)": {
48
+ "model_config": "unison/config/D20S0_O_40ch.yaml",
49
+ "ckpt_file": "unison_D20S0_O_40ch/model.safetensors",
50
+ "vae_mode": "44k",
51
+ "vae_ckpt_file": "ext_weights/v1-44.pth",
52
+ "vocoder_ckpt_file": None, # 44k mode auto-pulls BigVGANv2 from HF Hub
53
+ "sample_rate": 44100,
54
+ },
55
+ "High detail (16kHz)": {
56
+ "model_config": "unison/config/D24S0_O_20ch.yaml",
57
+ "ckpt_file": "unison_D24S0_O_20ch/model.safetensors",
58
+ "vae_mode": "16k",
59
+ "vae_ckpt_file": "ext_weights/v1-16.pth",
60
+ "vocoder_ckpt_file": "ext_weights/best_netG.pt",
61
+ "sample_rate": 16000,
62
+ },
63
+ }
64
+
65
+ # Only one variant's full stack (text encoder + DiT + VAE) is kept on the GPU at a
66
+ # time: the two variants need different Qwen2.5-Omni-7B layer-sampling depths, so
67
+ # the encoder can't be shared as-is (QwenOmniThinkerExtractor bakes dit_depth into
68
+ # which LLM layers it extracts at construction time). Switching variants evicts the
69
+ # previous one and rebuilds from the local HF cache (no re-download).
70
+ _active_name = None
71
+ _active_entry = None
72
+ _loading = True
73
+ _load_error = None
74
+
75
+ # Only one request runs at a time. The scheduler object is shared and stateful,
76
+ # so two requests running together would corrupt each other's results. This lock
77
+ # also covers _active_name/_active_entry below, so no separate lock is needed.
78
+ _gpu_lock = threading.Lock()
79
+
80
+
81
+ def _build_variant(name):
82
+ """Download and construct one variant's full stack: text encoder, DiT backbone,
83
+ and VAE. Mirrors the model-loading steps in unison/pipelines/infer.py's main()."""
84
+ spec = VARIANTS[name]
85
+ print(f"Building variant: {name} ...")
86
+
87
+ with open(spec["model_config"]) as f:
88
+ model_config = yaml.safe_load(f)
89
+ dit_depth = model_config.get("mm_double_blocks_depth", 0) + model_config.get("mm_single_blocks_depth", 0)
90
+ omni_last_layer_idx = model_config.get("omni_last_layer_idx", -1)
91
+
92
+ extractor = init_text_hidden_extractor(
93
+ "omni", OMNI_MODEL_ID, None, dit_depth, DEVICE, omni_last_layer_idx=omni_last_layer_idx,
94
+ )
95
+ sync_omni_dim_with_text_encoder(model_config, extractor)
96
+
97
+ ckpt_path = hf_hub_download(repo_id=UNISON_REPO, filename=spec["ckpt_file"])
98
+ model = _load_model(types.SimpleNamespace(model_ckpt=ckpt_path), DEVICE, model_config)
99
+
100
+ vae_ckpt_path = hf_hub_download(repo_id=MMAUDIO_REPO, filename=spec["vae_ckpt_file"])
101
+ vocoder_ckpt_path = (
102
+ hf_hub_download(repo_id=MMAUDIO_REPO, filename=spec["vocoder_ckpt_file"])
103
+ if spec["vocoder_ckpt_file"] else None
104
+ )
105
+ audio_vae = FeaturesUtils(
106
+ tod_vae_ckpt=vae_ckpt_path,
107
+ bigvgan_vocoder_ckpt=vocoder_ckpt_path,
108
+ mode=spec["vae_mode"],
109
+ )
110
+ audio_vae.to(DEVICE).eval()
111
+
112
+ # probe latent length for a MAX_AUDIO_DURATION-long clip (needed for generation mode).
113
+ sample_rate = spec["sample_rate"]
114
+ dummy_len = int(MAX_AUDIO_DURATION * sample_rate)
115
+ with torch.no_grad():
116
+ dummy_lat = audio_vae.wrapped_encode(torch.zeros(1, dummy_len, device=DEVICE))
117
+ gen_target_frames = int(dummy_lat.shape[-1])
118
+
119
+ scheduler = FlowMatchEulerDiscreteScheduler()
120
+ print(f"Variant ready: {name}")
121
+ return (model, extractor, audio_vae, 0.5, sample_rate, gen_target_frames, scheduler)
122
+
123
+
124
+ def load_default_variant():
125
+ """Background-thread target: build DEFAULT_VARIANT at startup and publish it
126
+ as the active variant, so the Space doesn't block its HTTP server on the load."""
127
+ global _active_name, _active_entry, _loading, _load_error
128
+ try:
129
+ entry = _build_variant(DEFAULT_VARIANT)
130
+ # No lock needed: _loading stays True until right after this write, and
131
+ # process_fn won't touch _active_name/_active_entry while _loading is True.
132
+ _active_name, _active_entry = DEFAULT_VARIANT, entry
133
+ except Exception:
134
+ _load_error = traceback.format_exc()
135
+ print(f"Variant load error: {_load_error}")
136
+ finally:
137
+ _loading = False
138
+
139
+
140
+ threading.Thread(target=load_default_variant, daemon=True).start()
141
+
142
+
143
+ def get_variant(name: str):
144
+ """Return the active variant's (model, extractor, vae, ...) tuple, building and
145
+ switching to `name` first if a different variant is currently active.
146
+
147
+ Caller must hold _gpu_lock — that's what makes the unlocked reads/writes of
148
+ _active_name/_active_entry here safe."""
149
+ global _active_name, _active_entry
150
+ if name == _active_name:
151
+ return _active_entry
152
+
153
+ print(f"Switching variant: {_active_name!r} -> {name!r}")
154
+ entry = _build_variant(name)
155
+ _active_name, _active_entry = name, entry
156
+ gc.collect()
157
+ torch.cuda.empty_cache()
158
+ return entry
159
+
160
+
161
+ model_card = ModelCard(
162
+ name="UNISON",
163
+ description=(
164
+ "Unified sound generation and editing: text-to-audio, text-to-speech, "
165
+ "audio-scene editing, and zero-shot voice cloning from a single model."
166
+ ),
167
+ author="Zhaoqing Li, Haoning Xu, Jingran Su, Yaofang Liu, Zhefan Rao, Huimeng Wang, "
168
+ "Jiajun Deng, Tianzi Wang, Zengrui Jin, Rui Liu, Haoxuan Che, Xunying Liu",
169
+ tags=["text-to-audio", "text-to-speech", "audio-editing", "zero-shot-tts"],
170
+ )
171
+
172
+
173
+ @gpu_decorator
174
+ @torch.inference_mode()
175
+ def process_fn(
176
+ input_audio_path: str,
177
+ mode: str,
178
+ sound_type: str,
179
+ voice: str,
180
+ prompt: str,
181
+ background: str,
182
+ ref_text: str,
183
+ model_variant: str,
184
+ steps: int,
185
+ guidance: float,
186
+ duration: float,
187
+ ) -> str:
188
+ if _loading:
189
+ raise gr.Error("Model is still loading, please wait a moment and try again.")
190
+ if _active_entry is None:
191
+ raise gr.Error(f"Model failed to load: {_load_error}")
192
+
193
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
194
+ out_path = f.name
195
+
196
+ with _gpu_lock:
197
+ model, omni_extractor, audio_vae, vae_scale_factor, vae_sample_rate, gen_target_frames, scheduler = get_variant(model_variant)
198
+
199
+ if mode == "Generate":
200
+ # Text-to-audio/speech, no input audio involved. sound_type picks which of
201
+ # the model's trained prompt templates to build (see README task table) —
202
+ # voice/background only apply to the Speech templates, unused otherwise.
203
+ if sound_type == "Sound Effect":
204
+ tagged_prompt = f"[Audio] {prompt}"
205
+ elif sound_type == "Speech":
206
+ tagged_prompt = f'[Speech] A {voice.lower()} voice saying "{prompt}"'
207
+ else: # "Speech + Background"
208
+ tagged_prompt = f'[Speech] A {voice.lower()} voice saying "{prompt}" [Audio] {background}'
209
+
210
+ latents = sample_latents(
211
+ model, scheduler, omni_extractor, [tagged_prompt],
212
+ num_inference_steps=steps, guidance_scale=guidance, device=DEVICE,
213
+ target_frames=gen_target_frames,
214
+ )
215
+ latents = latents * (1.0 / vae_scale_factor)
216
+ decode_and_save(audio_vae, latents, [duration], [out_path], sample_rate=vae_sample_rate)
217
+
218
+ elif mode == "Edit":
219
+ # Source audio + instruction. Mask is all-ones: the whole clip is editable,
220
+ # source_latents just gives the model something to condition on.
221
+ # sound_type again picks [Audio] vs [Speech] as the edit's sub-tag; "Speech
222
+ # + Background" isn't a real edit template, so it also falls back to [Audio].
223
+ if not input_audio_path:
224
+ raise gr.Error("Edit mode requires an input audio track.")
225
+ edit_target = "Speech" if sound_type == "Speech" else "Audio"
226
+ tgt_wav_len = int(MAX_AUDIO_DURATION * vae_sample_rate)
227
+ src_wav = load_source_audio(input_audio_path, target_sr=vae_sample_rate,
228
+ target_length=tgt_wav_len, device=DEVICE)
229
+ src_latent = audio_vae.wrapped_encode(src_wav) * vae_scale_factor
230
+ mask_wav = make_edit_mask(src_wav.shape[-1], DEVICE)
231
+ mask_lat = downsample_mask(mask_wav, src_latent.shape[-1])
232
+
233
+ latents = sample_latents(
234
+ model, scheduler, omni_extractor, [f"[Edit] [{edit_target}] {prompt}"],
235
+ source_latents=src_latent, masks=mask_lat,
236
+ num_inference_steps=steps, guidance_scale=guidance, device=DEVICE,
237
+ )
238
+ latents = latents * (1.0 / vae_scale_factor)
239
+ edit_duration = src_wav.shape[-1] / vae_sample_rate
240
+ decode_and_save(audio_vae, latents, [edit_duration], [out_path], sample_rate=vae_sample_rate)
241
+
242
+ elif mode == "Clone Voice":
243
+ # Reference clip + text to speak in that voice.
244
+ if not input_audio_path:
245
+ raise gr.Error("Clone Voice mode requires a reference audio track.")
246
+
247
+ # 3.0s matches REF_DURATION, the reference-clip length the model was trained with.
248
+ ref_wav = load_ref_audio(input_audio_path, target_sr=vae_sample_rate,
249
+ max_ref_duration=3.0, device=DEVICE)
250
+ ref_audio_duration = ref_wav.shape[-1] / vae_sample_rate
251
+ if ref_audio_duration + 1.0 > duration: # 1.0s floor so some cloned speech always fits
252
+ raise gr.Error(f"Reference clip ({ref_audio_duration:.1f}s) leaves under 1s for "
253
+ f"the cloned speech at Duration={duration:.1f}s. Increase Duration.")
254
+
255
+ # Get the ref transcript (typed one wins over auto-transcription), then
256
+ # combine it with what the user wants said next into one prompt.
257
+ # Exclude load_ref_audio's trailing silence pad (tail_pad_s=0.1) so Whisper
258
+ # doesn't hallucinate tokens over silence.
259
+ speech_samples = max(ref_wav.shape[-1] - int(0.1 * vae_sample_rate), 1)
260
+ resolved_ref_text = ref_text.strip() or transcribe_ref_audio(
261
+ ref_wav[..., :speech_samples], sr=vae_sample_rate,
262
+ )
263
+ combined_text = join_ref_target_text(resolved_ref_text, prompt)
264
+ full_prompt = f"[Speech with voice] {combined_text}"
265
+
266
+ # Build one waveform [ref audio | silence] and encode it as a single clip —
267
+ # the model generates the target portion conditioned on the ref portion.
268
+ total_wav_len = int(duration * vae_sample_rate)
269
+ ref_wav_1d = ref_wav.squeeze(0) if ref_wav.dim() == 2 else ref_wav
270
+ ref_wav_len = min(ref_wav_1d.shape[-1], total_wav_len)
271
+ source_wav = torch.zeros(1, total_wav_len, device=DEVICE)
272
+ source_wav[:, :ref_wav_len] = ref_wav_1d[:ref_wav_len]
273
+ source_latent = audio_vae.wrapped_encode(source_wav) * vae_scale_factor
274
+
275
+ mask_wav = torch.zeros(1, 1, total_wav_len, device=DEVICE)
276
+ mask_wav[:, :, :ref_wav_len] = 2.0 # 2 = reference region, 0 = target (see sample_latents docstring)
277
+ mask_latent = torch.nn.functional.interpolate(
278
+ mask_wav, size=source_latent.shape[-1]
279
+ ).to(torch.bfloat16)
280
+
281
+ latents = sample_latents(
282
+ model, scheduler, omni_extractor, [full_prompt],
283
+ source_latents=source_latent, masks=mask_latent,
284
+ num_inference_steps=steps, guidance_scale=guidance, device=DEVICE,
285
+ )
286
+ latents_full = latents * (1.0 / vae_scale_factor)
287
+
288
+ # Decode the full ref+target latent, then crop out just the target —
289
+ # the decoder needs the ref portion as context to decode cleanly.
290
+ ref_samples = int(ref_audio_duration * vae_sample_rate)
291
+ decode_and_save_full(
292
+ audio_vae, latents_full, ref_samples,
293
+ [duration - ref_audio_duration], [out_path], sample_rate=vae_sample_rate,
294
+ )
295
+
296
+ else:
297
+ raise gr.Error(f"Unknown mode: {mode}")
298
+
299
+ return out_path
300
+
301
+
302
+ with gr.Blocks() as demo:
303
+ input_components = [
304
+ gr.Audio(type="filepath", label="Input Audio").harp_required(False)
305
+ .set_info("Source track for Edit mode, or reference voice for Clone Voice mode. Unused in Generate mode."),
306
+ gr.Dropdown(choices=["Generate", "Edit", "Clone Voice"], value="Generate", label="Mode"),
307
+ gr.Dropdown(choices=["Sound Effect", "Speech", "Speech + Background"], value="Sound Effect",
308
+ label="Sound Type",
309
+ info="Generate/Edit only: what kind of content Prompt describes."),
310
+ # Voice/Background are only meaningful for the Speech sound types. HARP has no
311
+ # way to hide a control based on another control's value, so they're always
312
+ # shown and just ignored (e.g. for Sound Effect) rather than hidden.
313
+ gr.Dropdown(choices=["Female", "Male"], value="Female", label="Voice",
314
+ info="Speech sound types only."),
315
+ gr.Textbox(label="Prompt",
316
+ info="Generate: describe the sound, or what's said. Edit: describe the change. Clone Voice: text to speak."),
317
+ gr.Textbox(label="Background (optional)",
318
+ info="\"Speech + Background\" sound type only: the background sound to mix in."),
319
+ gr.Textbox(label="Reference Transcript (optional)",
320
+ info="Only used in Clone Voice mode. Leave blank to auto-transcribe the input audio."),
321
+ gr.Dropdown(choices=list(VARIANTS), value="Balanced (44kHz)", label="Model"),
322
+ gr.Slider(minimum=10, maximum=100, step=5, value=50, label="Generation Steps"),
323
+ gr.Slider(minimum=1.0, maximum=10.0, step=0.5, value=4.5, label="Prompt Strength"),
324
+ gr.Slider(minimum=1.0, maximum=float(MAX_AUDIO_DURATION), step=0.5, value=10.0, label="Duration (s)"),
325
+ ]
326
+ output_components = [
327
+ gr.Audio(type="filepath", label="Output Audio").set_info("Generated or edited audio."),
328
+ ]
329
+
330
+ build_endpoint(
331
+ model_card=model_card,
332
+ input_components=input_components,
333
+ output_components=output_components,
334
+ process_fn=process_fn,
335
+ )
336
+
337
+ demo.queue().launch(pwa=True)
requirements.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ git+https://github.com/TEAMuP-dev/pyharp.git@v0.3.0
2
+ # model-specific deps below:
3
+ torch>=2.6.0
4
+ torchaudio>=2.6.0
5
+ numpy>=1.26.0
6
+ einops>=0.8.0
7
+ transformers>=4.53.0
8
+ accelerate>=0.34.0
9
+ diffusers>=0.30.0
10
+ safetensors>=0.4.5
11
+ huggingface-hub>=0.34.0
12
+ soundfile>=0.12.0
13
+ librosa>=0.9.0
14
+ scipy>=1.11.0
15
+ openai-whisper>=20240930
16
+ pyyaml>=6.0
17
+ omegaconf>=2.3.0
18
+ loguru>=0.7.0
19
+ tqdm>=4.67.0
unison/__init__.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/LICENSE
6
+ #
7
+ # Unless and only to the extent required by applicable law, the Tencent Hunyuan works and any
8
+ # output and results therefrom are provided "AS IS" without any express or implied warranties of
9
+ # any kind including any warranties of title, merchantability, noninfringement, course of dealing,
10
+ # usage of trade, or fitness for a particular purpose. You are solely responsible for determining the
11
+ # appropriateness of using, reproducing, modifying, performing, displaying or distributing any of
12
+ # the Tencent Hunyuan works or outputs and assume any and all risks associated with your or a
13
+ # third party's use or distribution of any of the Tencent Hunyuan works or outputs and your exercise
14
+ # of rights and permissions under this agreement.
15
+ # See the License for the specific language governing permissions and limitations under the License.
16
+
17
+ import os
18
+ import socket
19
+ from .commons import get_gpu_memory
20
+
21
+
22
+ if 'TOKENIZERS_PARALLELISM' not in os.environ:
23
+ os.environ['TOKENIZERS_PARALLELISM'] = 'false'
24
+
25
+ def find_free_port():
26
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
27
+ sock.bind(('localhost', 0))
28
+ port = sock.getsockname()[1]
29
+ sock.close()
30
+ return port
31
+
32
+ def __initialize_default_distributed_environment():
33
+ if 'RANK' not in os.environ:
34
+ os.environ['RANK'] = '0'
35
+ if 'WORLD_SIZE' not in os.environ:
36
+ os.environ['WORLD_SIZE'] = '1'
37
+ if 'LOCAL_RANK' not in os.environ:
38
+ os.environ['LOCAL_RANK'] = '0'
39
+ if 'MASTER_ADDR' not in os.environ:
40
+ os.environ['MASTER_ADDR'] = 'localhost'
41
+ if 'MASTER_PORT' not in os.environ:
42
+ os.environ['MASTER_PORT'] = str(find_free_port())
43
+
44
+ __initialize_default_distributed_environment()
unison/commons/__init__.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/LICENSE
6
+ #
7
+ # Unless and only to the extent required by applicable law, the Tencent Hunyuan works and any
8
+ # output and results therefrom are provided "AS IS" without any express or implied warranties of
9
+ # any kind including any warranties of title, merchantability, noninfringement, course of dealing,
10
+ # usage of trade, or fitness for a particular purpose. You are solely responsible for determining the
11
+ # appropriateness of using, reproducing, modifying, performing, displaying or distributing any of
12
+ # the Tencent Hunyuan works or outputs and assume any and all risks associated with your or a
13
+ # third party's use or distribution of any of the Tencent Hunyuan works or outputs and your exercise
14
+ # of rights and permissions under this agreement.
15
+ # See the License for the specific language governing permissions and limitations under the License.
16
+
17
+ import os
18
+ import torch
19
+ from itertools import repeat
20
+ from contextlib import contextmanager
21
+ from torch import nn
22
+ import collections.abc
23
+
24
+ def _ntuple(n):
25
+ """Create a function that converts input to n-tuple."""
26
+ def parse(x):
27
+ if isinstance(x, collections.abc.Iterable) and not isinstance(x, str):
28
+ x = tuple(x)
29
+ if len(x) == 1:
30
+ x = tuple(repeat(x[0], n))
31
+ return x
32
+ return tuple(repeat(x, n))
33
+ return parse
34
+
35
+ # Convenience functions for common tuple sizes
36
+ to_1tuple = _ntuple(1)
37
+ to_2tuple = _ntuple(2)
38
+ to_3tuple = _ntuple(3)
39
+ to_4tuple = _ntuple(4)
40
+
41
+ PRECISION_TO_TYPE = {
42
+ 'fp32': torch.float32,
43
+ 'fp16': torch.float16,
44
+ 'bf16': torch.bfloat16,
45
+ }
46
+
47
+ # Default generation pipeline configurations
48
+ PIPELINE_CONFIGS = {
49
+ '480p_t2v': {
50
+ 'guidance_scale': 6.0,
51
+ 'embedded_guidance_scale': None,
52
+ 'flow_shift': 5.0,
53
+ },
54
+ '480p_i2v': {
55
+ 'guidance_scale': 6.0,
56
+ 'embedded_guidance_scale': None,
57
+ 'flow_shift': 5.0,
58
+ },
59
+ '720p_t2v': {
60
+ 'guidance_scale': 6.0,
61
+ 'embedded_guidance_scale': None,
62
+ 'flow_shift': 9.0,
63
+ },
64
+ '720p_i2v': {
65
+ 'guidance_scale': 6.0,
66
+ 'embedded_guidance_scale': None,
67
+ 'flow_shift': 7.0,
68
+ },
69
+ '480p_t2v_distilled': {
70
+ 'guidance_scale': 1.0,
71
+ 'embedded_guidance_scale': None,
72
+ 'flow_shift': 5.0,
73
+ },
74
+ '480p_i2v_distilled': {
75
+ 'guidance_scale': 1.0,
76
+ 'embedded_guidance_scale': None,
77
+ 'flow_shift': 5.0,
78
+ },
79
+ '720p_t2v_distilled': {
80
+ 'guidance_scale': 1.0,
81
+ 'embedded_guidance_scale': None,
82
+ 'flow_shift': 9.0,
83
+ },
84
+ '720p_i2v_distilled': {
85
+ 'guidance_scale': 1.0,
86
+ 'embedded_guidance_scale': None,
87
+ 'flow_shift': 7.0,
88
+ },
89
+ '720p_t2v_distilled_sparse': {
90
+ 'guidance_scale': 1.0,
91
+ 'embedded_guidance_scale': None,
92
+ 'flow_shift': 7.0,
93
+ },
94
+ '720p_i2v_distilled_sparse': {
95
+ 'guidance_scale': 1.0,
96
+ 'embedded_guidance_scale': None,
97
+ 'flow_shift': 9.0,
98
+ },
99
+ }
100
+
101
+ # Default super-resolution pipeline configurations
102
+ SR_PIPELINE_CONFIGS = {
103
+ '720p_sr_distilled': {
104
+ 'flow_shift': 2.0,
105
+ 'base_resolution': '480p',
106
+ 'guidance_scale': 1.0,
107
+ 'embedded_guidance_scale': None,
108
+ 'num_inference_steps': 6,
109
+ },
110
+ '1080p_sr_distilled': {
111
+ 'flow_shift': 2.0,
112
+ 'base_resolution': '720p',
113
+ 'guidance_scale': 1.0,
114
+ 'embedded_guidance_scale': None,
115
+ 'num_inference_steps': 8,
116
+ },
117
+ }
118
+
119
+ TRANSFORMER_VERSION_TO_SR_VERSION = {
120
+ '480p_t2v': '720p_sr_distilled',
121
+ '720p_t2v': '1080p_sr_distilled',
122
+ '480p_i2v': '720p_sr_distilled',
123
+ '720p_i2v': '1080p_sr_distilled',
124
+ '480p_t2v_distilled': '720p_sr_distilled',
125
+ '720p_t2v_distilled': '1080p_sr_distilled',
126
+ '480p_i2v_distilled': '720p_sr_distilled',
127
+ '720p_i2v_distilled': '1080p_sr_distilled',
128
+ '480p_t2v_distilled_sparse': '720p_sr_distilled',
129
+ '720p_t2v_distilled_sparse': '1080p_sr_distilled',
130
+ '480p_i2v_distilled_sparse': '720p_sr_distilled',
131
+ '720p_i2v_distilled_sparse': '1080p_sr_distilled',
132
+ }
133
+
134
+ def is_flash2_available():
135
+ try:
136
+ from flash_attn import flash_attn_varlen_qkvpacked_func
137
+ return True
138
+ except Exception:
139
+ return False
140
+
141
+ def is_flash3_available():
142
+ try:
143
+ from flash_attn_interface import flash_attn_varlen_func as flash_attn_varlen_func_v3 # noqa: F401
144
+ return True
145
+ except Exception:
146
+ return False
147
+
148
+ def is_flash_available():
149
+ return is_flash2_available() or is_flash3_available()
150
+
151
+ def is_sparse_attn_supported():
152
+ return 'nvidia h' in torch.cuda.get_device_properties(0).name.lower()
153
+
154
+ def is_sparse_attn_available():
155
+ if not is_sparse_attn_supported():
156
+ return False
157
+ try:
158
+ from flex_block_attn import flex_block_attn_func # noqa: F401
159
+ return True
160
+ except Exception:
161
+ return False
162
+
163
+ def maybe_fallback_attn_mode(attn_mode, infer_state=None, block_idx=None):
164
+ """
165
+ Determine the final attention mode based on configuration and availability.
166
+
167
+ Args:
168
+ attn_mode: Requested attention mode
169
+ infer_state: Inference configuration object (optional)
170
+ block_idx: Current block index (optional)
171
+
172
+ Returns:
173
+ Final attention mode to use
174
+ """
175
+ import warnings
176
+
177
+ # Check for sageattn and flex-block-attn conflict
178
+ enable_sageattn = False
179
+ if infer_state is not None:
180
+ enable_sageattn = (infer_state.enable_sageattn and
181
+ block_idx in infer_state.sage_blocks_range)
182
+
183
+ assert not (enable_sageattn and attn_mode == 'flex-block-attn'), \
184
+ ("SageAttention cannot be used with flex-block-attn mode. "
185
+ "Please disable enable_sageattn or use a different attention mode.")
186
+
187
+ # Use SageAttention if configured
188
+ if enable_sageattn:
189
+ attn_mode = 'sageattn'
190
+ return attn_mode
191
+
192
+ # Handle flash attention modes
193
+ if attn_mode == 'flash':
194
+ if is_flash3_available():
195
+ attn_mode = 'flash3'
196
+ elif is_flash2_available():
197
+ attn_mode = 'flash2'
198
+ else:
199
+ warnings.warn("flash is not available. Falling back to torch attention.")
200
+ attn_mode = 'torch'
201
+ elif attn_mode == 'flash3':
202
+ if not is_flash3_available():
203
+ warnings.warn("flash3 is not available. Falling back to torch attention.")
204
+ attn_mode = 'torch'
205
+ elif attn_mode == 'flash2':
206
+ if not is_flash2_available():
207
+ warnings.warn("flash2 is not available. Falling back to torch attention.")
208
+ attn_mode = 'torch'
209
+ if attn_mode in ('flex-block-attn'):
210
+ from unison.commons import is_sparse_attn_available
211
+ if not is_sparse_attn_available():
212
+ raise ValueError(f"{attn_mode} is not available for your GPU or flex-block-attn is not properly installed.")
213
+ return attn_mode
214
+
215
+ @contextmanager
216
+ def auto_offload_model(models, device, enabled=True):
217
+ from diffusers.hooks.group_offloading import _is_group_offload_enabled
218
+ if enabled:
219
+ if isinstance(models, nn.Module):
220
+ models = [models]
221
+ for model in models:
222
+ if model is not None:
223
+ model.to(device)
224
+ yield
225
+ if enabled:
226
+ for model in models:
227
+ if model is not None:
228
+ model.to(torch.device('cpu'))
229
+
230
+ def get_gpu_memory(device=None):
231
+ if not torch.cuda.is_available():
232
+ return 0
233
+ device = device if device is not None else torch.cuda.current_device()
234
+ props = torch.cuda.get_device_properties(device)
235
+ if hasattr(torch.cuda, 'get_per_process_memory_fraction'):
236
+ memory_fraction = torch.cuda.get_per_process_memory_fraction()
237
+ else:
238
+ memory_fraction = 1.0
239
+ return props.total_memory * memory_fraction
240
+
241
+ def get_rank():
242
+ return int(os.environ.get('RANK', '0'))
unison/commons/infer_state.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/LICENSE
6
+ #
7
+ # Unless and only to the extent required by applicable law, the Tencent Hunyuan works and any
8
+ # output and results therefrom are provided "AS IS" without any express or implied warranties of
9
+ # any kind including any warranties of title, merchantability, noninfringement, course of dealing,
10
+ # usage of trade, or fitness for a particular purpose. You are solely responsible for determining the
11
+ # appropriateness of using, reproducing, modifying, performing, displaying or distributing any of
12
+ # the Tencent Hunyuan works or outputs and assume any and all risks associated with your or a
13
+ # third party's use or distribution of any of the Tencent Hunyuan works or outputs and your exercise
14
+ # of rights and permissions under this agreement.
15
+ # See the License for the specific language governing permissions and limitations under the License.
16
+
17
+ from typing import Optional
18
+ from dataclasses import dataclass
19
+
20
+ @dataclass
21
+ class InferState:
22
+ enable_sageattn: bool = False # whether to use SageAttention
23
+ sage_blocks_range: Optional[range] = None # block range to use SageAttention
24
+ enable_torch_compile: bool = False # whether to use torch compile
25
+
26
+ __infer_state = None
27
+
28
+ def parse_range(value):
29
+ if '-' in value:
30
+ start, end = map(int, value.split('-'))
31
+ return list(range(start, end + 1))
32
+ else:
33
+ return [int(x) for x in value.split(',')]
34
+
35
+ def initialize_infer_state(args):
36
+ global __infer_state
37
+ sage_blocks_range = parse_range(args.sage_blocks_range)
38
+ # Map CLI argument use_sageattn to internal enable_sageattn field
39
+ use_sageattn = getattr(args, 'use_sageattn', False)
40
+ __infer_state = InferState(
41
+ enable_sageattn = use_sageattn,
42
+ sage_blocks_range = sage_blocks_range,
43
+ enable_torch_compile = args.enable_torch_compile,
44
+ )
45
+ return __infer_state
46
+
47
+ def get_infer_state():
48
+ return __infer_state
unison/commons/parallel_states.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/LICENSE
6
+ #
7
+ # Unless and only to the extent required by applicable law, the Tencent Hunyuan works and any
8
+ # output and results therefrom are provided "AS IS" without any express or implied warranties of
9
+ # any kind including any warranties of title, merchantability, noninfringement, course of dealing,
10
+ # usage of trade, or fitness for a particular purpose. You are solely responsible for determining the
11
+ # appropriateness of using, reproducing, modifying, performing, displaying or distributing any of
12
+ # the Tencent Hunyuan works or outputs and assume any and all risks associated with your or a
13
+ # third party's use or distribution of any of the Tencent Hunyuan works or outputs and your exercise
14
+ # of rights and permissions under this agreement.
15
+ # See the License for the specific language governing permissions and limitations under the License.
16
+
17
+ import os
18
+ from dataclasses import dataclass
19
+
20
+ import torch.distributed as dist
21
+ from torch.distributed.device_mesh import init_device_mesh
22
+
23
+ @dataclass
24
+ class ParallelDims:
25
+ sp: int = 1
26
+ world_size: int = -1
27
+
28
+ def __post_init__(self):
29
+ if self.world_size == -1:
30
+ if dist.is_initialized():
31
+ self.world_size = dist.get_world_size()
32
+ else:
33
+ self.world_size = int(os.getenv("WORLD_SIZE", "1"))
34
+ if dist.is_initialized():
35
+ self.build_mesh("cuda")
36
+ else:
37
+ self.world_mesh = None
38
+
39
+ def build_mesh(self, device_type):
40
+ assert self.world_size % self.sp == 0, "world_size must be divisible by sp"
41
+ mesh = init_device_mesh(
42
+ device_type,
43
+ [self.world_size // self.sp, self.sp],
44
+ mesh_dim_names=["dp", "sp"]
45
+ )
46
+ self.world_mesh = mesh
47
+ return mesh
48
+
49
+ @property
50
+ def sp_enabled(self):
51
+ return self.sp > 1
52
+
53
+ @property
54
+ def sp_group(self):
55
+ return self.world_mesh['sp'].get_group()
56
+
57
+ @property
58
+ def sp_mesh(self):
59
+ return self.world_mesh['sp']
60
+
61
+ @property
62
+ def sp_rank(self):
63
+ if self.sp_enabled:
64
+ return self.world_mesh['sp'].get_local_rank()
65
+ else:
66
+ return dist.get_rank()
67
+
68
+ @property
69
+ def dp_enabled(self):
70
+ return self.sp > 1
71
+
72
+ __parallel_dims = None
73
+
74
+ def initialize_parallel_state(
75
+ sp: int = 1,
76
+ ):
77
+ global __parallel_dims
78
+ __parallel_dims = ParallelDims(sp=sp)
79
+ return __parallel_dims
80
+
81
+ def get_parallel_state():
82
+ if __parallel_dims is None:
83
+ # create default parallel states (without enabling any parallelism)
84
+ initialize_parallel_state()
85
+ return __parallel_dims
unison/config/D20S0_O_40ch.yaml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ in_channels: 40 # MMAudio 44 kHz VAE latent channels (C=40); model receives 2C+1=81 channels when concat_condition=True
2
+ out_channels: 40
3
+ patch_size: [1, 2, 2]
4
+ hidden_size: 1024
5
+ heads_num: 8
6
+ mlp_act_type: gelu_tanh
7
+ mlp_width_ratio: 4.0
8
+ mm_double_blocks_depth: 20
9
+ mm_single_blocks_depth: 0
10
+ qkv_bias: true
11
+ qk_norm: true
12
+ qk_norm_type: rms
13
+ attn_mode: flash
14
+ attn_param: null
15
+ rope_dim_list: [96, 16, 16]
16
+ rope_theta: 10000
17
+ omni_dim: 3584
18
+ is_reshape_temporal_channels: false
19
+ use_duration_embedding: false
20
+ is_audio_type: true
21
+ use_omni_embedding: true
22
+ use_omni_last_embedding: false
23
+ omni_last_layer_idx: -2 # -1 = last LLM layer, -2 = second-to-last
24
+ guidance_embed: false
25
+ temporal_rope_scaling_factor: 1.0
26
+ repa_z_dim: null
27
+ repa_layer_num: null
unison/config/D24S0_O_20ch.yaml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ in_channels: 20 # MMAudio 16 kHz VAE latent channels (C=20); model receives 2C+1=41 channels when concat_condition=True
2
+ out_channels: 20
3
+ patch_size: [1, 2, 2]
4
+ hidden_size: 1024
5
+ heads_num: 8
6
+ mlp_act_type: gelu_tanh
7
+ mlp_width_ratio: 4.0
8
+ mm_double_blocks_depth: 24
9
+ mm_single_blocks_depth: 0
10
+ qkv_bias: true
11
+ qk_norm: true
12
+ qk_norm_type: rms
13
+ attn_mode: flash
14
+ attn_param: null
15
+ rope_dim_list: [96, 16, 16]
16
+ rope_theta: 10000
17
+ omni_dim: 3584
18
+ is_reshape_temporal_channels: false
19
+ use_duration_embedding: false
20
+ is_audio_type: true
21
+ use_omni_embedding: true
22
+ use_omni_last_embedding: false
23
+ omni_last_layer_idx: -2 # -1 = last LLM layer, -2 = second-to-last
24
+ guidance_embed: false
25
+ temporal_rope_scaling_factor: 1.0
26
+ repa_z_dim: null
27
+ repa_layer_num: null
unison/models/__init__.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # https://github.com/Tencent-Hunyuan/HunyuanVideo-1.5/blob/main/LICENSE
6
+ #
7
+ # Unless and only to the extent required by applicable law, the Tencent Hunyuan works and any
8
+ # output and results therefrom are provided "AS IS" without any express or implied warranties of
9
+ # any kind including any warranties of title, merchantability, noninfringement, course of dealing,
10
+ # usage of trade, or fitness for a particular purpose. You are solely responsible for determining the
11
+ # appropriateness of using, reproducing, modifying, performing, displaying or distributing any of
12
+ # the Tencent Hunyuan works or outputs and assume any and all risks associated with your or a
13
+ # third party's use or distribution of any of the Tencent Hunyuan works or outputs and your exercise
14
+ # of rights and permissions under this agreement.
15
+ # See the License for the specific language governing permissions and limitations under the License.
16
+
unison/models/mmaudio/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # MMAudio package
unison/models/mmaudio/ext/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+
unison/models/mmaudio/ext/autoencoder/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .autoencoder import AutoEncoderModule
unison/models/mmaudio/ext/autoencoder/autoencoder.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Literal, Optional
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import numpy as np
6
+
7
+ from .vae import VAE, get_my_vae
8
+ from .distributions import DiagonalGaussianDistribution
9
+ from ..bigvgan import BigVGAN
10
+ from ..bigvgan_v2.bigvgan import BigVGAN as BigVGANv2
11
+
12
+
13
+
14
+
15
+ class AutoEncoderModule(nn.Module):
16
+
17
+ def __init__(self,
18
+ *,
19
+ vae_ckpt_path,
20
+ vocoder_ckpt_path: Optional[str] = None,
21
+ mode: Literal['16k', '44k'],
22
+ need_vae_encoder: bool = True):
23
+ super().__init__()
24
+ self.vae: VAE = get_my_vae(mode).eval()
25
+ vae_state_dict = torch.load(vae_ckpt_path, weights_only=True, map_location='cpu')
26
+ self.vae.load_state_dict(vae_state_dict)
27
+ self.vae.remove_weight_norm()
28
+
29
+ if mode == '16k':
30
+ assert vocoder_ckpt_path is not None
31
+ self.vocoder = BigVGAN(vocoder_ckpt_path).eval()
32
+ elif mode == '44k':
33
+ # vocoder_ckpt_path can be:
34
+ # - None (default): pull 'nvidia/bigvgan_v2_44khz_128band_512x' from HF Hub
35
+ # - HF repo id (e.g., 'nvidia/bigvgan_v2_44khz_128band')
36
+ # - Local directory containing bigvgan_generator.pt + config.json
37
+ bigvgan_v2_id = vocoder_ckpt_path or 'nvidia/bigvgan_v2_44khz_128band_512x'
38
+ self.vocoder = BigVGANv2.from_pretrained(bigvgan_v2_id,
39
+ use_cuda_kernel=False)
40
+ self.vocoder.remove_weight_norm()
41
+ else:
42
+ raise ValueError(f'Unknown mode: {mode}')
43
+
44
+ for param in self.parameters():
45
+ param.requires_grad = False
46
+
47
+ if not need_vae_encoder:
48
+ del self.vae.encoder
49
+
50
+ @torch.inference_mode()
51
+ def encode(self, x: torch.Tensor) -> DiagonalGaussianDistribution:
52
+ return self.vae.encode(x)
53
+
54
+ @torch.inference_mode()
55
+ def decode(self, z: torch.Tensor) -> torch.Tensor:
56
+ return self.vae.decode(z)
57
+
58
+ @torch.inference_mode()
59
+ def vocode(self, spec: torch.Tensor) -> torch.Tensor:
60
+ return self.vocoder(spec)
unison/models/mmaudio/ext/autoencoder/distributions.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+ import torch
3
+ import numpy as np
4
+
5
+
6
+ class DiagonalGaussianDistribution:
7
+
8
+ def __init__(self, parameters, deterministic=False):
9
+ self.parameters = parameters
10
+ self.mean, self.logvar = torch.chunk(parameters, 2, dim=1)
11
+ self.logvar = torch.clamp(self.logvar, -30.0, 20.0)
12
+ self.deterministic = deterministic
13
+ self.std = torch.exp(0.5 * self.logvar)
14
+ self.var = torch.exp(self.logvar)
15
+ if self.deterministic:
16
+ self.var = self.std = torch.zeros_like(self.mean).to(device=self.parameters.device)
17
+
18
+ def sample(self, rng: Optional[torch.Generator] = None):
19
+ # x = self.mean + self.std * torch.randn(self.mean.shape).to(device=self.parameters.device)
20
+
21
+ r = torch.empty_like(self.mean).normal_(generator=rng)
22
+ x = self.mean + self.std * r
23
+
24
+ return x
25
+
26
+ def kl(self, other=None):
27
+ if self.deterministic:
28
+ return torch.Tensor([0.])
29
+ else:
30
+ if other is None:
31
+
32
+ return 0.5 * torch.pow(self.mean, 2) + self.var - 1.0 - self.logvar
33
+ else:
34
+ return 0.5 * (torch.pow(self.mean - other.mean, 2) / other.var +
35
+ self.var / other.var - 1.0 - self.logvar + other.logvar)
36
+
37
+ def nll(self, sample, dims=[1, 2, 3]):
38
+ if self.deterministic:
39
+ return torch.Tensor([0.])
40
+ logtwopi = np.log(2.0 * np.pi)
41
+ return 0.5 * torch.sum(logtwopi + self.logvar + torch.pow(sample - self.mean, 2) / self.var,
42
+ dim=dims)
43
+
44
+ def mode(self):
45
+ return self.mean
unison/models/mmaudio/ext/autoencoder/edm2_utils.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ #
3
+ # This work is licensed under a Creative Commons
4
+ # Attribution-NonCommercial-ShareAlike 4.0 International License.
5
+ # You should have received a copy of the license along with this
6
+ # work. If not, see http://creativecommons.org/licenses/by-nc-sa/4.0/
7
+ """Improved diffusion model architecture proposed in the paper
8
+ "Analyzing and Improving the Training Dynamics of Diffusion Models"."""
9
+
10
+ import numpy as np
11
+ import torch
12
+
13
+ #----------------------------------------------------------------------------
14
+ # Variant of constant() that inherits dtype and device from the given
15
+ # reference tensor by default.
16
+
17
+ _constant_cache = dict()
18
+
19
+
20
+ def constant(value, shape=None, dtype=None, device=None, memory_format=None):
21
+ value = np.asarray(value)
22
+ if shape is not None:
23
+ shape = tuple(shape)
24
+ if dtype is None:
25
+ dtype = torch.get_default_dtype()
26
+ if device is None:
27
+ device = torch.device('cpu')
28
+ if memory_format is None:
29
+ memory_format = torch.contiguous_format
30
+
31
+ key = (value.shape, value.dtype, value.tobytes(), shape, dtype, device, memory_format)
32
+ tensor = _constant_cache.get(key, None)
33
+ if tensor is None:
34
+ tensor = torch.as_tensor(value.copy(), dtype=dtype, device=device)
35
+ if shape is not None:
36
+ tensor, _ = torch.broadcast_tensors(tensor, torch.empty(shape))
37
+ tensor = tensor.contiguous(memory_format=memory_format)
38
+ _constant_cache[key] = tensor
39
+ return tensor
40
+
41
+
42
+ def const_like(ref, value, shape=None, dtype=None, device=None, memory_format=None):
43
+ if dtype is None:
44
+ dtype = ref.dtype
45
+ if device is None:
46
+ device = ref.device
47
+ return constant(value, shape=shape, dtype=dtype, device=device, memory_format=memory_format)
48
+
49
+
50
+ #----------------------------------------------------------------------------
51
+ # Normalize given tensor to unit magnitude with respect to the given
52
+ # dimensions. Default = all dimensions except the first.
53
+
54
+
55
+ def normalize(x, dim=None, eps=1e-4):
56
+ if dim is None:
57
+ dim = list(range(1, x.ndim))
58
+ norm = torch.linalg.vector_norm(x, dim=dim, keepdim=True, dtype=torch.float32)
59
+ norm = torch.add(eps, norm, alpha=np.sqrt(norm.numel() / x.numel()))
60
+ return x / norm.to(x.dtype)
61
+
62
+
63
+ class Normalize(torch.nn.Module):
64
+
65
+ def __init__(self, dim=None, eps=1e-4):
66
+ super().__init__()
67
+ self.dim = dim
68
+ self.eps = eps
69
+
70
+ def forward(self, x):
71
+ return normalize(x, dim=self.dim, eps=self.eps)
72
+
73
+
74
+ #----------------------------------------------------------------------------
75
+ # Upsample or downsample the given tensor with the given filter,
76
+ # or keep it as is.
77
+
78
+
79
+ def resample(x, f=[1, 1], mode='keep'):
80
+ if mode == 'keep':
81
+ return x
82
+ f = np.float32(f)
83
+ assert f.ndim == 1 and len(f) % 2 == 0
84
+ pad = (len(f) - 1) // 2
85
+ f = f / f.sum()
86
+ f = np.outer(f, f)[np.newaxis, np.newaxis, :, :]
87
+ f = const_like(x, f)
88
+ c = x.shape[1]
89
+ if mode == 'down':
90
+ return torch.nn.functional.conv2d(x,
91
+ f.tile([c, 1, 1, 1]),
92
+ groups=c,
93
+ stride=2,
94
+ padding=(pad, ))
95
+ assert mode == 'up'
96
+ return torch.nn.functional.conv_transpose2d(x, (f * 4).tile([c, 1, 1, 1]),
97
+ groups=c,
98
+ stride=2,
99
+ padding=(pad, ))
100
+
101
+
102
+ #----------------------------------------------------------------------------
103
+ # Magnitude-preserving SiLU (Equation 81).
104
+
105
+
106
+ def mp_silu(x):
107
+ return torch.nn.functional.silu(x) / 0.596
108
+
109
+
110
+ class MPSiLU(torch.nn.Module):
111
+
112
+ def forward(self, x):
113
+ return mp_silu(x)
114
+
115
+
116
+ #----------------------------------------------------------------------------
117
+ # Magnitude-preserving sum (Equation 88).
118
+
119
+
120
+ def mp_sum(a, b, t=0.5):
121
+ return a.lerp(b, t) / np.sqrt((1 - t)**2 + t**2)
122
+
123
+
124
+ #----------------------------------------------------------------------------
125
+ # Magnitude-preserving concatenation (Equation 103).
126
+
127
+
128
+ def mp_cat(a, b, dim=1, t=0.5):
129
+ Na = a.shape[dim]
130
+ Nb = b.shape[dim]
131
+ C = np.sqrt((Na + Nb) / ((1 - t)**2 + t**2))
132
+ wa = C / np.sqrt(Na) * (1 - t)
133
+ wb = C / np.sqrt(Nb) * t
134
+ return torch.cat([wa * a, wb * b], dim=dim)
135
+
136
+
137
+ #----------------------------------------------------------------------------
138
+ # Magnitude-preserving convolution or fully-connected layer (Equation 47)
139
+ # with force weight normalization (Equation 66).
140
+
141
+
142
+ class MPConv1D(torch.nn.Module):
143
+
144
+ def __init__(self, in_channels, out_channels, kernel_size):
145
+ super().__init__()
146
+ self.out_channels = out_channels
147
+ self.weight = torch.nn.Parameter(torch.randn(out_channels, in_channels, kernel_size))
148
+
149
+ self.weight_norm_removed = False
150
+
151
+ def forward(self, x, gain=1):
152
+ assert self.weight_norm_removed, 'call remove_weight_norm() before inference'
153
+
154
+ w = self.weight * gain
155
+ if w.ndim == 2:
156
+ return x @ w.t()
157
+ assert w.ndim == 3
158
+ return torch.nn.functional.conv1d(x, w, padding=(w.shape[-1] // 2, ))
159
+
160
+ def remove_weight_norm(self):
161
+ w = self.weight.to(torch.float32)
162
+ w = normalize(w) # traditional weight normalization
163
+ w = w / np.sqrt(w[0].numel())
164
+ w = w.to(self.weight.dtype)
165
+ self.weight.data.copy_(w)
166
+
167
+ self.weight_norm_removed = True
168
+ return self
unison/models/mmaudio/ext/autoencoder/vae.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import Optional
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+
7
+ from .edm2_utils import MPConv1D
8
+ from .vae_modules import (AttnBlock1D, Downsample1D, ResnetBlock1D,
9
+ Upsample1D, nonlinearity)
10
+ from .distributions import DiagonalGaussianDistribution
11
+
12
+ log = logging.getLogger()
13
+
14
+ DATA_MEAN_80D = [
15
+ -1.6058, -1.3676, -1.2520, -1.2453, -1.2078, -1.2224, -1.2419, -1.2439, -1.2922, -1.2927,
16
+ -1.3170, -1.3543, -1.3401, -1.3836, -1.3907, -1.3912, -1.4313, -1.4152, -1.4527, -1.4728,
17
+ -1.4568, -1.5101, -1.5051, -1.5172, -1.5623, -1.5373, -1.5746, -1.5687, -1.6032, -1.6131,
18
+ -1.6081, -1.6331, -1.6489, -1.6489, -1.6700, -1.6738, -1.6953, -1.6969, -1.7048, -1.7280,
19
+ -1.7361, -1.7495, -1.7658, -1.7814, -1.7889, -1.8064, -1.8221, -1.8377, -1.8417, -1.8643,
20
+ -1.8857, -1.8929, -1.9173, -1.9379, -1.9531, -1.9673, -1.9824, -2.0042, -2.0215, -2.0436,
21
+ -2.0766, -2.1064, -2.1418, -2.1855, -2.2319, -2.2767, -2.3161, -2.3572, -2.3954, -2.4282,
22
+ -2.4659, -2.5072, -2.5552, -2.6074, -2.6584, -2.7107, -2.7634, -2.8266, -2.8981, -2.9673
23
+ ]
24
+
25
+ DATA_STD_80D = [
26
+ 1.0291, 1.0411, 1.0043, 0.9820, 0.9677, 0.9543, 0.9450, 0.9392, 0.9343, 0.9297, 0.9276, 0.9263,
27
+ 0.9242, 0.9254, 0.9232, 0.9281, 0.9263, 0.9315, 0.9274, 0.9247, 0.9277, 0.9199, 0.9188, 0.9194,
28
+ 0.9160, 0.9161, 0.9146, 0.9161, 0.9100, 0.9095, 0.9145, 0.9076, 0.9066, 0.9095, 0.9032, 0.9043,
29
+ 0.9038, 0.9011, 0.9019, 0.9010, 0.8984, 0.8983, 0.8986, 0.8961, 0.8962, 0.8978, 0.8962, 0.8973,
30
+ 0.8993, 0.8976, 0.8995, 0.9016, 0.8982, 0.8972, 0.8974, 0.8949, 0.8940, 0.8947, 0.8936, 0.8939,
31
+ 0.8951, 0.8956, 0.9017, 0.9167, 0.9436, 0.9690, 1.0003, 1.0225, 1.0381, 1.0491, 1.0545, 1.0604,
32
+ 1.0761, 1.0929, 1.1089, 1.1196, 1.1176, 1.1156, 1.1117, 1.1070
33
+ ]
34
+
35
+ DATA_MEAN_128D = [
36
+ -3.3462, -2.6723, -2.4893, -2.3143, -2.2664, -2.3317, -2.1802, -2.4006, -2.2357, -2.4597,
37
+ -2.3717, -2.4690, -2.5142, -2.4919, -2.6610, -2.5047, -2.7483, -2.5926, -2.7462, -2.7033,
38
+ -2.7386, -2.8112, -2.7502, -2.9594, -2.7473, -3.0035, -2.8891, -2.9922, -2.9856, -3.0157,
39
+ -3.1191, -2.9893, -3.1718, -3.0745, -3.1879, -3.2310, -3.1424, -3.2296, -3.2791, -3.2782,
40
+ -3.2756, -3.3134, -3.3509, -3.3750, -3.3951, -3.3698, -3.4505, -3.4509, -3.5089, -3.4647,
41
+ -3.5536, -3.5788, -3.5867, -3.6036, -3.6400, -3.6747, -3.7072, -3.7279, -3.7283, -3.7795,
42
+ -3.8259, -3.8447, -3.8663, -3.9182, -3.9605, -3.9861, -4.0105, -4.0373, -4.0762, -4.1121,
43
+ -4.1488, -4.1874, -4.2461, -4.3170, -4.3639, -4.4452, -4.5282, -4.6297, -4.7019, -4.7960,
44
+ -4.8700, -4.9507, -5.0303, -5.0866, -5.1634, -5.2342, -5.3242, -5.4053, -5.4927, -5.5712,
45
+ -5.6464, -5.7052, -5.7619, -5.8410, -5.9188, -6.0103, -6.0955, -6.1673, -6.2362, -6.3120,
46
+ -6.3926, -6.4797, -6.5565, -6.6511, -6.8130, -6.9961, -7.1275, -7.2457, -7.3576, -7.4663,
47
+ -7.6136, -7.7469, -7.8815, -8.0132, -8.1515, -8.3071, -8.4722, -8.7418, -9.3975, -9.6628,
48
+ -9.7671, -9.8863, -9.9992, -10.0860, -10.1709, -10.5418, -11.2795, -11.3861
49
+ ]
50
+
51
+ DATA_STD_128D = [
52
+ 2.3804, 2.4368, 2.3772, 2.3145, 2.2803, 2.2510, 2.2316, 2.2083, 2.1996, 2.1835, 2.1769, 2.1659,
53
+ 2.1631, 2.1618, 2.1540, 2.1606, 2.1571, 2.1567, 2.1612, 2.1579, 2.1679, 2.1683, 2.1634, 2.1557,
54
+ 2.1668, 2.1518, 2.1415, 2.1449, 2.1406, 2.1350, 2.1313, 2.1415, 2.1281, 2.1352, 2.1219, 2.1182,
55
+ 2.1327, 2.1195, 2.1137, 2.1080, 2.1179, 2.1036, 2.1087, 2.1036, 2.1015, 2.1068, 2.0975, 2.0991,
56
+ 2.0902, 2.1015, 2.0857, 2.0920, 2.0893, 2.0897, 2.0910, 2.0881, 2.0925, 2.0873, 2.0960, 2.0900,
57
+ 2.0957, 2.0958, 2.0978, 2.0936, 2.0886, 2.0905, 2.0845, 2.0855, 2.0796, 2.0840, 2.0813, 2.0817,
58
+ 2.0838, 2.0840, 2.0917, 2.1061, 2.1431, 2.1976, 2.2482, 2.3055, 2.3700, 2.4088, 2.4372, 2.4609,
59
+ 2.4731, 2.4847, 2.5072, 2.5451, 2.5772, 2.6147, 2.6529, 2.6596, 2.6645, 2.6726, 2.6803, 2.6812,
60
+ 2.6899, 2.6916, 2.6931, 2.6998, 2.7062, 2.7262, 2.7222, 2.7158, 2.7041, 2.7485, 2.7491, 2.7451,
61
+ 2.7485, 2.7233, 2.7297, 2.7233, 2.7145, 2.6958, 2.6788, 2.6439, 2.6007, 2.4786, 2.2469, 2.1877,
62
+ 2.1392, 2.0717, 2.0107, 1.9676, 1.9140, 1.7102, 0.9101, 0.7164
63
+ ]
64
+
65
+
66
+ class VAE(nn.Module):
67
+
68
+ def __init__(
69
+ self,
70
+ *,
71
+ data_dim: int,
72
+ embed_dim: int,
73
+ hidden_dim: int,
74
+ ):
75
+ super().__init__()
76
+
77
+ if data_dim == 80:
78
+ self.data_mean = nn.Buffer(torch.tensor(DATA_MEAN_80D, dtype=torch.float32))
79
+ self.data_std = nn.Buffer(torch.tensor(DATA_STD_80D, dtype=torch.float32))
80
+ elif data_dim == 128:
81
+ self.data_mean = nn.Buffer(torch.tensor(DATA_MEAN_128D, dtype=torch.float32))
82
+ self.data_std = nn.Buffer(torch.tensor(DATA_STD_128D, dtype=torch.float32))
83
+
84
+ self.data_mean = self.data_mean.view(1, -1, 1)
85
+ self.data_std = self.data_std.view(1, -1, 1)
86
+
87
+ self.encoder = Encoder1D(
88
+ dim=hidden_dim,
89
+ ch_mult=(1, 2, 4),
90
+ num_res_blocks=2,
91
+ attn_layers=[3],
92
+ down_layers=[0],
93
+ in_dim=data_dim,
94
+ embed_dim=embed_dim,
95
+ )
96
+ self.decoder = Decoder1D(
97
+ dim=hidden_dim,
98
+ ch_mult=(1, 2, 4),
99
+ num_res_blocks=2,
100
+ attn_layers=[3],
101
+ down_layers=[0],
102
+ in_dim=data_dim,
103
+ out_dim=data_dim,
104
+ embed_dim=embed_dim,
105
+ )
106
+
107
+ self.embed_dim = embed_dim
108
+ # self.quant_conv = nn.Conv1d(2 * embed_dim, 2 * embed_dim, 1)
109
+ # self.post_quant_conv = nn.Conv1d(embed_dim, embed_dim, 1)
110
+
111
+ self.initialize_weights()
112
+
113
+ def initialize_weights(self):
114
+ pass
115
+
116
+ def encode(self, x: torch.Tensor, normalize: bool = True) -> DiagonalGaussianDistribution:
117
+ if normalize:
118
+ x = self.normalize(x)
119
+ moments = self.encoder(x)
120
+ posterior = DiagonalGaussianDistribution(moments)
121
+ return posterior
122
+
123
+ def decode(self, z: torch.Tensor, unnormalize: bool = True) -> torch.Tensor:
124
+ dec = self.decoder(z)
125
+ if unnormalize:
126
+ dec = self.unnormalize(dec)
127
+ return dec
128
+
129
+ def normalize(self, x: torch.Tensor) -> torch.Tensor:
130
+ return (x - self.data_mean) / self.data_std
131
+
132
+ def unnormalize(self, x: torch.Tensor) -> torch.Tensor:
133
+ return x * self.data_std + self.data_mean
134
+
135
+ def forward(
136
+ self,
137
+ x: torch.Tensor,
138
+ sample_posterior: bool = True,
139
+ rng: Optional[torch.Generator] = None,
140
+ normalize: bool = True,
141
+ unnormalize: bool = True,
142
+ ) -> tuple[torch.Tensor, DiagonalGaussianDistribution]:
143
+
144
+ posterior = self.encode(x, normalize=normalize)
145
+ if sample_posterior:
146
+ z = posterior.sample(rng)
147
+ else:
148
+ z = posterior.mode()
149
+ dec = self.decode(z, unnormalize=unnormalize)
150
+ return dec, posterior
151
+
152
+ def load_weights(self, src_dict) -> None:
153
+ self.load_state_dict(src_dict, strict=True)
154
+
155
+ @property
156
+ def device(self) -> torch.device:
157
+ return next(self.parameters()).device
158
+
159
+ def get_last_layer(self):
160
+ return self.decoder.conv_out.weight
161
+
162
+ def remove_weight_norm(self):
163
+ for name, m in self.named_modules():
164
+ if isinstance(m, MPConv1D):
165
+ m.remove_weight_norm()
166
+ log.debug(f"Removed weight norm from {name}")
167
+ return self
168
+
169
+
170
+ class Encoder1D(nn.Module):
171
+
172
+ def __init__(self,
173
+ *,
174
+ dim: int,
175
+ ch_mult: tuple[int] = (1, 2, 4, 8),
176
+ num_res_blocks: int,
177
+ attn_layers: list[int] = [],
178
+ down_layers: list[int] = [],
179
+ resamp_with_conv: bool = True,
180
+ in_dim: int,
181
+ embed_dim: int,
182
+ double_z: bool = True,
183
+ kernel_size: int = 3,
184
+ clip_act: float = 256.0):
185
+ super().__init__()
186
+ self.dim = dim
187
+ self.num_layers = len(ch_mult)
188
+ self.num_res_blocks = num_res_blocks
189
+ self.in_channels = in_dim
190
+ self.clip_act = clip_act
191
+ self.down_layers = down_layers
192
+ self.attn_layers = attn_layers
193
+ self.conv_in = MPConv1D(in_dim, self.dim, kernel_size=kernel_size)
194
+
195
+ in_ch_mult = (1, ) + tuple(ch_mult)
196
+ self.in_ch_mult = in_ch_mult
197
+ # downsampling
198
+ self.down = nn.ModuleList()
199
+ for i_level in range(self.num_layers):
200
+ block = nn.ModuleList()
201
+ attn = nn.ModuleList()
202
+ block_in = dim * in_ch_mult[i_level]
203
+ block_out = dim * ch_mult[i_level]
204
+ for i_block in range(self.num_res_blocks):
205
+ block.append(
206
+ ResnetBlock1D(in_dim=block_in,
207
+ out_dim=block_out,
208
+ kernel_size=kernel_size,
209
+ use_norm=True))
210
+ block_in = block_out
211
+ if i_level in attn_layers:
212
+ attn.append(AttnBlock1D(block_in))
213
+ down = nn.Module()
214
+ down.block = block
215
+ down.attn = attn
216
+ if i_level in down_layers:
217
+ down.downsample = Downsample1D(block_in, resamp_with_conv)
218
+ self.down.append(down)
219
+
220
+ # middle
221
+ self.mid = nn.Module()
222
+ self.mid.block_1 = ResnetBlock1D(in_dim=block_in,
223
+ out_dim=block_in,
224
+ kernel_size=kernel_size,
225
+ use_norm=True)
226
+ self.mid.attn_1 = AttnBlock1D(block_in)
227
+ self.mid.block_2 = ResnetBlock1D(in_dim=block_in,
228
+ out_dim=block_in,
229
+ kernel_size=kernel_size,
230
+ use_norm=True)
231
+
232
+ # end
233
+ self.conv_out = MPConv1D(block_in,
234
+ 2 * embed_dim if double_z else embed_dim,
235
+ kernel_size=kernel_size)
236
+
237
+ self.learnable_gain = nn.Parameter(torch.zeros([]))
238
+
239
+ def forward(self, x):
240
+
241
+ # downsampling
242
+ hs = [self.conv_in(x)]
243
+ for i_level in range(self.num_layers):
244
+ for i_block in range(self.num_res_blocks):
245
+ h = self.down[i_level].block[i_block](hs[-1])
246
+ if len(self.down[i_level].attn) > 0:
247
+ h = self.down[i_level].attn[i_block](h)
248
+ h = h.clamp(-self.clip_act, self.clip_act)
249
+ hs.append(h)
250
+ if i_level in self.down_layers:
251
+ hs.append(self.down[i_level].downsample(hs[-1]))
252
+
253
+ # middle
254
+ h = hs[-1]
255
+ h = self.mid.block_1(h)
256
+ h = self.mid.attn_1(h)
257
+ h = self.mid.block_2(h)
258
+ h = h.clamp(-self.clip_act, self.clip_act)
259
+
260
+ # end
261
+ h = nonlinearity(h)
262
+ h = self.conv_out(h, gain=(self.learnable_gain + 1))
263
+ return h
264
+
265
+
266
+ class Decoder1D(nn.Module):
267
+
268
+ def __init__(self,
269
+ *,
270
+ dim: int,
271
+ out_dim: int,
272
+ ch_mult: tuple[int] = (1, 2, 4, 8),
273
+ num_res_blocks: int,
274
+ attn_layers: list[int] = [],
275
+ down_layers: list[int] = [],
276
+ kernel_size: int = 3,
277
+ resamp_with_conv: bool = True,
278
+ in_dim: int,
279
+ embed_dim: int,
280
+ clip_act: float = 256.0):
281
+ super().__init__()
282
+ self.ch = dim
283
+ self.num_layers = len(ch_mult)
284
+ self.num_res_blocks = num_res_blocks
285
+ self.in_channels = in_dim
286
+ self.clip_act = clip_act
287
+ self.down_layers = [i + 1 for i in down_layers] # each downlayer add one
288
+
289
+ # compute in_ch_mult, block_in and curr_res at lowest res
290
+ block_in = dim * ch_mult[self.num_layers - 1]
291
+
292
+ # z to block_in
293
+ self.conv_in = MPConv1D(embed_dim, block_in, kernel_size=kernel_size)
294
+
295
+ # middle
296
+ self.mid = nn.Module()
297
+ self.mid.block_1 = ResnetBlock1D(in_dim=block_in, out_dim=block_in, use_norm=True)
298
+ self.mid.attn_1 = AttnBlock1D(block_in)
299
+ self.mid.block_2 = ResnetBlock1D(in_dim=block_in, out_dim=block_in, use_norm=True)
300
+
301
+ # upsampling
302
+ self.up = nn.ModuleList()
303
+ for i_level in reversed(range(self.num_layers)):
304
+ block = nn.ModuleList()
305
+ attn = nn.ModuleList()
306
+ block_out = dim * ch_mult[i_level]
307
+ for i_block in range(self.num_res_blocks + 1):
308
+ block.append(ResnetBlock1D(in_dim=block_in, out_dim=block_out, use_norm=True))
309
+ block_in = block_out
310
+ if i_level in attn_layers:
311
+ attn.append(AttnBlock1D(block_in))
312
+ up = nn.Module()
313
+ up.block = block
314
+ up.attn = attn
315
+ if i_level in self.down_layers:
316
+ up.upsample = Upsample1D(block_in, resamp_with_conv)
317
+ self.up.insert(0, up) # prepend to get consistent order
318
+
319
+ # end
320
+ self.conv_out = MPConv1D(block_in, out_dim, kernel_size=kernel_size)
321
+ self.learnable_gain = nn.Parameter(torch.zeros([]))
322
+
323
+ def forward(self, z):
324
+ # z to block_in
325
+ h = self.conv_in(z)
326
+
327
+ # middle
328
+ h = self.mid.block_1(h)
329
+ h = self.mid.attn_1(h)
330
+ h = self.mid.block_2(h)
331
+ h = h.clamp(-self.clip_act, self.clip_act)
332
+
333
+ # upsampling
334
+ for i_level in reversed(range(self.num_layers)):
335
+ for i_block in range(self.num_res_blocks + 1):
336
+ h = self.up[i_level].block[i_block](h)
337
+ if len(self.up[i_level].attn) > 0:
338
+ h = self.up[i_level].attn[i_block](h)
339
+ h = h.clamp(-self.clip_act, self.clip_act)
340
+ if i_level in self.down_layers:
341
+ h = self.up[i_level].upsample(h)
342
+
343
+ h = nonlinearity(h)
344
+ h = self.conv_out(h, gain=(self.learnable_gain + 1))
345
+ return h
346
+
347
+
348
+ def VAE_16k(**kwargs) -> VAE:
349
+ return VAE(data_dim=80, embed_dim=20, hidden_dim=384, **kwargs)
350
+
351
+
352
+ def VAE_44k(**kwargs) -> VAE:
353
+ return VAE(data_dim=128, embed_dim=40, hidden_dim=512, **kwargs)
354
+
355
+
356
+ def get_my_vae(name: str, **kwargs) -> VAE:
357
+ if name == '16k':
358
+ return VAE_16k(**kwargs)
359
+ if name == '44k':
360
+ return VAE_44k(**kwargs)
361
+ raise ValueError(f'Unknown model: {name}')
362
+
363
+
unison/models/mmaudio/ext/autoencoder/vae_modules.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from einops import rearrange
5
+
6
+ from .edm2_utils import (MPConv1D, mp_silu, mp_sum, normalize)
7
+
8
+
9
+ def nonlinearity(x):
10
+ # swish
11
+ return mp_silu(x)
12
+
13
+
14
+ class ResnetBlock1D(nn.Module):
15
+
16
+ def __init__(self, *, in_dim, out_dim=None, conv_shortcut=False, kernel_size=3, use_norm=True):
17
+ super().__init__()
18
+ self.in_dim = in_dim
19
+ out_dim = in_dim if out_dim is None else out_dim
20
+ self.out_dim = out_dim
21
+ self.use_conv_shortcut = conv_shortcut
22
+ self.use_norm = use_norm
23
+
24
+ self.conv1 = MPConv1D(in_dim, out_dim, kernel_size=kernel_size)
25
+ self.conv2 = MPConv1D(out_dim, out_dim, kernel_size=kernel_size)
26
+ if self.in_dim != self.out_dim:
27
+ if self.use_conv_shortcut:
28
+ self.conv_shortcut = MPConv1D(in_dim, out_dim, kernel_size=kernel_size)
29
+ else:
30
+ self.nin_shortcut = MPConv1D(in_dim, out_dim, kernel_size=1)
31
+
32
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
33
+
34
+ # pixel norm
35
+ if self.use_norm:
36
+ x = normalize(x, dim=1)
37
+
38
+ h = x
39
+ h = nonlinearity(h)
40
+ h = self.conv1(h)
41
+
42
+ h = nonlinearity(h)
43
+ h = self.conv2(h)
44
+
45
+ if self.in_dim != self.out_dim:
46
+ if self.use_conv_shortcut:
47
+ x = self.conv_shortcut(x)
48
+ else:
49
+ x = self.nin_shortcut(x)
50
+
51
+ return mp_sum(x, h, t=0.3)
52
+
53
+
54
+ class AttnBlock1D(nn.Module):
55
+
56
+ def __init__(self, in_channels, num_heads=1):
57
+ super().__init__()
58
+ self.in_channels = in_channels
59
+
60
+ self.num_heads = num_heads
61
+ self.qkv = MPConv1D(in_channels, in_channels * 3, kernel_size=1)
62
+ self.proj_out = MPConv1D(in_channels, in_channels, kernel_size=1)
63
+
64
+ def forward(self, x):
65
+ h = x
66
+ y = self.qkv(h)
67
+ y = y.reshape(y.shape[0], self.num_heads, -1, 3, y.shape[-1])
68
+ q, k, v = normalize(y, dim=2).unbind(3)
69
+
70
+ q = rearrange(q, 'b h c l -> b h l c')
71
+ k = rearrange(k, 'b h c l -> b h l c')
72
+ v = rearrange(v, 'b h c l -> b h l c')
73
+
74
+ h = F.scaled_dot_product_attention(q, k, v)
75
+ h = rearrange(h, 'b h l c -> b (h c) l')
76
+
77
+ h = self.proj_out(h)
78
+
79
+ return mp_sum(x, h, t=0.3)
80
+
81
+
82
+ class Upsample1D(nn.Module):
83
+
84
+ def __init__(self, in_channels, with_conv):
85
+ super().__init__()
86
+ self.with_conv = with_conv
87
+ if self.with_conv:
88
+ self.conv = MPConv1D(in_channels, in_channels, kernel_size=3)
89
+
90
+ def forward(self, x):
91
+ x = F.interpolate(x, scale_factor=2.0, mode='nearest-exact') # support 3D tensor(B,C,T)
92
+ if self.with_conv:
93
+ x = self.conv(x)
94
+ return x
95
+
96
+
97
+ class Downsample1D(nn.Module):
98
+
99
+ def __init__(self, in_channels, with_conv):
100
+ super().__init__()
101
+ self.with_conv = with_conv
102
+ if self.with_conv:
103
+ # no asymmetric padding in torch conv, must do it ourselves
104
+ self.conv1 = MPConv1D(in_channels, in_channels, kernel_size=1)
105
+ self.conv2 = MPConv1D(in_channels, in_channels, kernel_size=1)
106
+
107
+ def forward(self, x):
108
+
109
+ if self.with_conv:
110
+ x = self.conv1(x)
111
+
112
+ x = F.avg_pool1d(x, kernel_size=2, stride=2)
113
+
114
+ if self.with_conv:
115
+ x = self.conv2(x)
116
+
117
+ return x
unison/models/mmaudio/ext/bigvgan/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2022 NVIDIA CORPORATION.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
unison/models/mmaudio/ext/bigvgan/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .bigvgan import BigVGAN
unison/models/mmaudio/ext/bigvgan/activations.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation adapted from https://github.com/EdwardDixon/snake under the MIT license.
2
+ # LICENSE is in incl_licenses directory.
3
+
4
+ import torch
5
+ from torch import nn, sin, pow
6
+ from torch.nn import Parameter
7
+
8
+
9
+ class Snake(nn.Module):
10
+ '''
11
+ Implementation of a sine-based periodic activation function
12
+ Shape:
13
+ - Input: (B, C, T)
14
+ - Output: (B, C, T), same shape as the input
15
+ Parameters:
16
+ - alpha - trainable parameter
17
+ References:
18
+ - This activation function is from this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
19
+ https://arxiv.org/abs/2006.08195
20
+ Examples:
21
+ >>> a1 = snake(256)
22
+ >>> x = torch.randn(256)
23
+ >>> x = a1(x)
24
+ '''
25
+ def __init__(self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False):
26
+ '''
27
+ Initialization.
28
+ INPUT:
29
+ - in_features: shape of the input
30
+ - alpha: trainable parameter
31
+ alpha is initialized to 1 by default, higher values = higher-frequency.
32
+ alpha will be trained along with the rest of your model.
33
+ '''
34
+ super(Snake, self).__init__()
35
+ self.in_features = in_features
36
+
37
+ # initialize alpha
38
+ self.alpha_logscale = alpha_logscale
39
+ if self.alpha_logscale: # log scale alphas initialized to zeros
40
+ self.alpha = Parameter(torch.zeros(in_features) * alpha)
41
+ else: # linear scale alphas initialized to ones
42
+ self.alpha = Parameter(torch.ones(in_features) * alpha)
43
+
44
+ self.alpha.requires_grad = alpha_trainable
45
+
46
+ self.no_div_by_zero = 0.000000001
47
+
48
+ def forward(self, x):
49
+ '''
50
+ Forward pass of the function.
51
+ Applies the function to the input elementwise.
52
+ Snake ∶= x + 1/a * sin^2 (xa)
53
+ '''
54
+ alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T]
55
+ if self.alpha_logscale:
56
+ alpha = torch.exp(alpha)
57
+ x = x + (1.0 / (alpha + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
58
+
59
+ return x
60
+
61
+
62
+ class SnakeBeta(nn.Module):
63
+ '''
64
+ A modified Snake function which uses separate parameters for the magnitude of the periodic components
65
+ Shape:
66
+ - Input: (B, C, T)
67
+ - Output: (B, C, T), same shape as the input
68
+ Parameters:
69
+ - alpha - trainable parameter that controls frequency
70
+ - beta - trainable parameter that controls magnitude
71
+ References:
72
+ - This activation function is a modified version based on this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
73
+ https://arxiv.org/abs/2006.08195
74
+ Examples:
75
+ >>> a1 = snakebeta(256)
76
+ >>> x = torch.randn(256)
77
+ >>> x = a1(x)
78
+ '''
79
+ def __init__(self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False):
80
+ '''
81
+ Initialization.
82
+ INPUT:
83
+ - in_features: shape of the input
84
+ - alpha - trainable parameter that controls frequency
85
+ - beta - trainable parameter that controls magnitude
86
+ alpha is initialized to 1 by default, higher values = higher-frequency.
87
+ beta is initialized to 1 by default, higher values = higher-magnitude.
88
+ alpha will be trained along with the rest of your model.
89
+ '''
90
+ super(SnakeBeta, self).__init__()
91
+ self.in_features = in_features
92
+
93
+ # initialize alpha
94
+ self.alpha_logscale = alpha_logscale
95
+ if self.alpha_logscale: # log scale alphas initialized to zeros
96
+ self.alpha = Parameter(torch.zeros(in_features) * alpha)
97
+ self.beta = Parameter(torch.zeros(in_features) * alpha)
98
+ else: # linear scale alphas initialized to ones
99
+ self.alpha = Parameter(torch.ones(in_features) * alpha)
100
+ self.beta = Parameter(torch.ones(in_features) * alpha)
101
+
102
+ self.alpha.requires_grad = alpha_trainable
103
+ self.beta.requires_grad = alpha_trainable
104
+
105
+ self.no_div_by_zero = 0.000000001
106
+
107
+ def forward(self, x):
108
+ '''
109
+ Forward pass of the function.
110
+ Applies the function to the input elementwise.
111
+ SnakeBeta ∶= x + 1/b * sin^2 (xa)
112
+ '''
113
+ alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T]
114
+ beta = self.beta.unsqueeze(0).unsqueeze(-1)
115
+ if self.alpha_logscale:
116
+ alpha = torch.exp(alpha)
117
+ beta = torch.exp(beta)
118
+ x = x + (1.0 / (beta + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
119
+
120
+ return x
unison/models/mmaudio/ext/bigvgan/alias_free_torch/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
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 *
6
+ from .act import *
unison/models/mmaudio/ext/bigvgan/alias_free_torch/act.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 .resample import UpSample1d, DownSample1d
6
+
7
+
8
+ class Activation1d(nn.Module):
9
+ def __init__(self,
10
+ activation,
11
+ up_ratio: int = 2,
12
+ down_ratio: int = 2,
13
+ up_kernel_size: int = 12,
14
+ down_kernel_size: int = 12):
15
+ super().__init__()
16
+ self.up_ratio = up_ratio
17
+ self.down_ratio = down_ratio
18
+ self.act = activation
19
+ self.upsample = UpSample1d(up_ratio, up_kernel_size)
20
+ self.downsample = DownSample1d(down_ratio, down_kernel_size)
21
+
22
+ # x: [B,C,T]
23
+ def forward(self, x):
24
+ x = self.upsample(x)
25
+ x = self.act(x)
26
+ x = self.downsample(x)
27
+
28
+ return x
unison/models/mmaudio/ext/bigvgan/alias_free_torch/filter.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
unison/models/mmaudio/ext/bigvgan/alias_free_torch/resample.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
unison/models/mmaudio/ext/bigvgan/bigvgan.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ from omegaconf import OmegaConf
6
+
7
+ from .models import BigVGANVocoder
8
+
9
+ _bigvgan_vocoder_path = Path(__file__).parent / 'bigvgan_vocoder.yml'
10
+
11
+
12
+ class BigVGAN(nn.Module):
13
+
14
+ def __init__(self, ckpt_path, config_path=_bigvgan_vocoder_path):
15
+ super().__init__()
16
+ vocoder_cfg = OmegaConf.load(config_path)
17
+ self.vocoder = BigVGANVocoder(vocoder_cfg).eval()
18
+ vocoder_ckpt = torch.load(ckpt_path, map_location='cpu', weights_only=True)['generator']
19
+ self.vocoder.load_state_dict(vocoder_ckpt)
20
+
21
+ self.weight_norm_removed = False
22
+ self.remove_weight_norm()
23
+
24
+ @torch.inference_mode()
25
+ def forward(self, x):
26
+ assert self.weight_norm_removed, 'call remove_weight_norm() before inference'
27
+ return self.vocoder(x)
28
+
29
+ def remove_weight_norm(self):
30
+ self.vocoder.remove_weight_norm()
31
+ self.weight_norm_removed = True
32
+ return self
unison/models/mmaudio/ext/bigvgan/bigvgan_vocoder.yml ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ resblock: '1'
2
+ num_gpus: 0
3
+ batch_size: 64
4
+ num_mels: 80
5
+ learning_rate: 0.0001
6
+ adam_b1: 0.8
7
+ adam_b2: 0.99
8
+ lr_decay: 0.999
9
+ seed: 1234
10
+ upsample_rates:
11
+ - 4
12
+ - 4
13
+ - 2
14
+ - 2
15
+ - 2
16
+ - 2
17
+ upsample_kernel_sizes:
18
+ - 8
19
+ - 8
20
+ - 4
21
+ - 4
22
+ - 4
23
+ - 4
24
+ upsample_initial_channel: 1536
25
+ resblock_kernel_sizes:
26
+ - 3
27
+ - 7
28
+ - 11
29
+ resblock_dilation_sizes:
30
+ - - 1
31
+ - 3
32
+ - 5
33
+ - - 1
34
+ - 3
35
+ - 5
36
+ - - 1
37
+ - 3
38
+ - 5
39
+ activation: snakebeta
40
+ snake_logscale: true
41
+ resolutions:
42
+ - - 1024
43
+ - 120
44
+ - 600
45
+ - - 2048
46
+ - 240
47
+ - 1200
48
+ - - 512
49
+ - 50
50
+ - 240
51
+ mpd_reshapes:
52
+ - 2
53
+ - 3
54
+ - 5
55
+ - 7
56
+ - 11
57
+ use_spectral_norm: false
58
+ discriminator_channel_mult: 1
59
+ num_workers: 4
60
+ dist_config:
61
+ dist_backend: nccl
62
+ dist_url: tcp://localhost:54341
63
+ world_size: 1
unison/models/mmaudio/ext/bigvgan/env.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/jik876/hifi-gan under the MIT license.
2
+ # LICENSE is in incl_licenses directory.
3
+
4
+ import os
5
+ import shutil
6
+
7
+
8
+ class AttrDict(dict):
9
+ def __init__(self, *args, **kwargs):
10
+ super(AttrDict, self).__init__(*args, **kwargs)
11
+ self.__dict__ = self
12
+
13
+
14
+ def build_env(config, config_name, path):
15
+ t_path = os.path.join(path, config_name)
16
+ if config != t_path:
17
+ os.makedirs(path, exist_ok=True)
18
+ shutil.copyfile(config, os.path.join(path, config_name))
unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_1 ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Jungil Kong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_2 ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Edward Dixon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_3 ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_4 ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2019, Seungwon Park 박승원
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_5 ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright 2020 Alexandre Défossez
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
4
+ associated documentation files (the "Software"), to deal in the Software without restriction,
5
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7
+ furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or
10
+ substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
13
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
unison/models/mmaudio/ext/bigvgan/models.py ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2022 NVIDIA CORPORATION.
2
+ # Licensed under the MIT license.
3
+
4
+ # Adapted from https://github.com/jik876/hifi-gan under the MIT license.
5
+ # LICENSE is in incl_licenses directory.
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from torch.nn import Conv1d, ConvTranspose1d
10
+ from torch.nn.utils.parametrizations import weight_norm
11
+ from torch.nn.utils.parametrize import remove_parametrizations
12
+
13
+ from . import activations
14
+ from .alias_free_torch import *
15
+ from .utils import get_padding, init_weights
16
+
17
+ LRELU_SLOPE = 0.1
18
+
19
+
20
+ class AMPBlock1(torch.nn.Module):
21
+
22
+ def __init__(self, h, channels, kernel_size=3, dilation=(1, 3, 5), activation=None):
23
+ super(AMPBlock1, self).__init__()
24
+ self.h = h
25
+
26
+ self.convs1 = nn.ModuleList([
27
+ weight_norm(
28
+ Conv1d(channels,
29
+ channels,
30
+ kernel_size,
31
+ 1,
32
+ dilation=dilation[0],
33
+ padding=get_padding(kernel_size, dilation[0]))),
34
+ weight_norm(
35
+ Conv1d(channels,
36
+ channels,
37
+ kernel_size,
38
+ 1,
39
+ dilation=dilation[1],
40
+ padding=get_padding(kernel_size, dilation[1]))),
41
+ weight_norm(
42
+ Conv1d(channels,
43
+ channels,
44
+ kernel_size,
45
+ 1,
46
+ dilation=dilation[2],
47
+ padding=get_padding(kernel_size, dilation[2])))
48
+ ])
49
+ self.convs1.apply(init_weights)
50
+
51
+ self.convs2 = nn.ModuleList([
52
+ weight_norm(
53
+ Conv1d(channels,
54
+ channels,
55
+ kernel_size,
56
+ 1,
57
+ dilation=1,
58
+ padding=get_padding(kernel_size, 1))),
59
+ weight_norm(
60
+ Conv1d(channels,
61
+ channels,
62
+ kernel_size,
63
+ 1,
64
+ dilation=1,
65
+ padding=get_padding(kernel_size, 1))),
66
+ weight_norm(
67
+ Conv1d(channels,
68
+ channels,
69
+ kernel_size,
70
+ 1,
71
+ dilation=1,
72
+ padding=get_padding(kernel_size, 1)))
73
+ ])
74
+ self.convs2.apply(init_weights)
75
+
76
+ self.num_layers = len(self.convs1) + len(self.convs2) # total number of conv layers
77
+
78
+ if activation == 'snake': # periodic nonlinearity with snake function and anti-aliasing
79
+ self.activations = nn.ModuleList([
80
+ Activation1d(
81
+ activation=activations.Snake(channels, alpha_logscale=h.snake_logscale))
82
+ for _ in range(self.num_layers)
83
+ ])
84
+ elif activation == 'snakebeta': # periodic nonlinearity with snakebeta function and anti-aliasing
85
+ self.activations = nn.ModuleList([
86
+ Activation1d(
87
+ activation=activations.SnakeBeta(channels, alpha_logscale=h.snake_logscale))
88
+ for _ in range(self.num_layers)
89
+ ])
90
+ else:
91
+ raise NotImplementedError(
92
+ "activation incorrectly specified. check the config file and look for 'activation'."
93
+ )
94
+
95
+ def forward(self, x):
96
+ acts1, acts2 = self.activations[::2], self.activations[1::2]
97
+ for c1, c2, a1, a2 in zip(self.convs1, self.convs2, acts1, acts2):
98
+ xt = a1(x)
99
+ xt = c1(xt)
100
+ xt = a2(xt)
101
+ xt = c2(xt)
102
+ x = xt + x
103
+
104
+ return x
105
+
106
+ def remove_weight_norm(self):
107
+ for l in self.convs1:
108
+ remove_parametrizations(l, 'weight')
109
+ for l in self.convs2:
110
+ remove_parametrizations(l, 'weight')
111
+
112
+
113
+ class AMPBlock2(torch.nn.Module):
114
+
115
+ def __init__(self, h, channels, kernel_size=3, dilation=(1, 3), activation=None):
116
+ super(AMPBlock2, self).__init__()
117
+ self.h = h
118
+
119
+ self.convs = nn.ModuleList([
120
+ weight_norm(
121
+ Conv1d(channels,
122
+ channels,
123
+ kernel_size,
124
+ 1,
125
+ dilation=dilation[0],
126
+ padding=get_padding(kernel_size, dilation[0]))),
127
+ weight_norm(
128
+ Conv1d(channels,
129
+ channels,
130
+ kernel_size,
131
+ 1,
132
+ dilation=dilation[1],
133
+ padding=get_padding(kernel_size, dilation[1])))
134
+ ])
135
+ self.convs.apply(init_weights)
136
+
137
+ self.num_layers = len(self.convs) # total number of conv layers
138
+
139
+ if activation == 'snake': # periodic nonlinearity with snake function and anti-aliasing
140
+ self.activations = nn.ModuleList([
141
+ Activation1d(
142
+ activation=activations.Snake(channels, alpha_logscale=h.snake_logscale))
143
+ for _ in range(self.num_layers)
144
+ ])
145
+ elif activation == 'snakebeta': # periodic nonlinearity with snakebeta function and anti-aliasing
146
+ self.activations = nn.ModuleList([
147
+ Activation1d(
148
+ activation=activations.SnakeBeta(channels, alpha_logscale=h.snake_logscale))
149
+ for _ in range(self.num_layers)
150
+ ])
151
+ else:
152
+ raise NotImplementedError(
153
+ "activation incorrectly specified. check the config file and look for 'activation'."
154
+ )
155
+
156
+ def forward(self, x):
157
+ for c, a in zip(self.convs, self.activations):
158
+ xt = a(x)
159
+ xt = c(xt)
160
+ x = xt + x
161
+
162
+ return x
163
+
164
+ def remove_weight_norm(self):
165
+ for l in self.convs:
166
+ remove_parametrizations(l, 'weight')
167
+
168
+
169
+ class BigVGANVocoder(torch.nn.Module):
170
+ # this is our main BigVGAN model. Applies anti-aliased periodic activation for resblocks.
171
+ def __init__(self, h):
172
+ super().__init__()
173
+ self.h = h
174
+
175
+ self.num_kernels = len(h.resblock_kernel_sizes)
176
+ self.num_upsamples = len(h.upsample_rates)
177
+
178
+ # pre conv
179
+ self.conv_pre = weight_norm(Conv1d(h.num_mels, h.upsample_initial_channel, 7, 1, padding=3))
180
+
181
+ # define which AMPBlock to use. BigVGAN uses AMPBlock1 as default
182
+ resblock = AMPBlock1 if h.resblock == '1' else AMPBlock2
183
+
184
+ # transposed conv-based upsamplers. does not apply anti-aliasing
185
+ self.ups = nn.ModuleList()
186
+ for i, (u, k) in enumerate(zip(h.upsample_rates, h.upsample_kernel_sizes)):
187
+ self.ups.append(
188
+ nn.ModuleList([
189
+ weight_norm(
190
+ ConvTranspose1d(h.upsample_initial_channel // (2**i),
191
+ h.upsample_initial_channel // (2**(i + 1)),
192
+ k,
193
+ u,
194
+ padding=(k - u) // 2))
195
+ ]))
196
+
197
+ # residual blocks using anti-aliased multi-periodicity composition modules (AMP)
198
+ self.resblocks = nn.ModuleList()
199
+ for i in range(len(self.ups)):
200
+ ch = h.upsample_initial_channel // (2**(i + 1))
201
+ for j, (k, d) in enumerate(zip(h.resblock_kernel_sizes, h.resblock_dilation_sizes)):
202
+ self.resblocks.append(resblock(h, ch, k, d, activation=h.activation))
203
+
204
+ # post conv
205
+ if h.activation == "snake": # periodic nonlinearity with snake function and anti-aliasing
206
+ activation_post = activations.Snake(ch, alpha_logscale=h.snake_logscale)
207
+ self.activation_post = Activation1d(activation=activation_post)
208
+ elif h.activation == "snakebeta": # periodic nonlinearity with snakebeta function and anti-aliasing
209
+ activation_post = activations.SnakeBeta(ch, alpha_logscale=h.snake_logscale)
210
+ self.activation_post = Activation1d(activation=activation_post)
211
+ else:
212
+ raise NotImplementedError(
213
+ "activation incorrectly specified. check the config file and look for 'activation'."
214
+ )
215
+
216
+ self.conv_post = weight_norm(Conv1d(ch, 1, 7, 1, padding=3))
217
+
218
+ # weight initialization
219
+ for i in range(len(self.ups)):
220
+ self.ups[i].apply(init_weights)
221
+ self.conv_post.apply(init_weights)
222
+
223
+ def forward(self, x):
224
+ # pre conv
225
+ x = self.conv_pre(x)
226
+
227
+ for i in range(self.num_upsamples):
228
+ # upsampling
229
+ for i_up in range(len(self.ups[i])):
230
+ x = self.ups[i][i_up](x)
231
+ # AMP blocks
232
+ xs = None
233
+ for j in range(self.num_kernels):
234
+ if xs is None:
235
+ xs = self.resblocks[i * self.num_kernels + j](x)
236
+ else:
237
+ xs += self.resblocks[i * self.num_kernels + j](x)
238
+ x = xs / self.num_kernels
239
+
240
+ # post conv
241
+ x = self.activation_post(x)
242
+ x = self.conv_post(x)
243
+ x = torch.tanh(x)
244
+
245
+ return x
246
+
247
+ def remove_weight_norm(self):
248
+ print('Removing weight norm...')
249
+ for l in self.ups:
250
+ for l_i in l:
251
+ remove_parametrizations(l_i, 'weight')
252
+ for l in self.resblocks:
253
+ l.remove_weight_norm()
254
+ remove_parametrizations(self.conv_pre, 'weight')
255
+ remove_parametrizations(self.conv_post, 'weight')
unison/models/mmaudio/ext/bigvgan/utils.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/jik876/hifi-gan under the MIT license.
2
+ # LICENSE is in incl_licenses directory.
3
+
4
+ import os
5
+
6
+ import torch
7
+ from torch.nn.utils.parametrizations import weight_norm
8
+
9
+
10
+ def init_weights(m, mean=0.0, std=0.01):
11
+ classname = m.__class__.__name__
12
+ if classname.find("Conv") != -1:
13
+ m.weight.data.normal_(mean, std)
14
+
15
+
16
+ def apply_weight_norm(m):
17
+ classname = m.__class__.__name__
18
+ if classname.find("Conv") != -1:
19
+ weight_norm(m)
20
+
21
+
22
+ def get_padding(kernel_size, dilation=1):
23
+ return int((kernel_size * dilation - dilation) / 2)
24
+
25
+
26
+ def load_checkpoint(filepath, device):
27
+ assert os.path.isfile(filepath)
28
+ print("Loading '{}'".format(filepath))
29
+ checkpoint_dict = torch.load(filepath, map_location=device)
30
+ print("Complete.")
31
+ return checkpoint_dict
unison/models/mmaudio/ext/bigvgan_v2/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 NVIDIA CORPORATION.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
unison/models/mmaudio/ext/bigvgan_v2/__init__.py ADDED
File without changes
unison/models/mmaudio/ext/bigvgan_v2/activations.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation adapted from https://github.com/EdwardDixon/snake under the MIT license.
2
+ # LICENSE is in incl_licenses directory.
3
+
4
+ import torch
5
+ from torch import nn, sin, pow
6
+ from torch.nn import Parameter
7
+
8
+
9
+ class Snake(nn.Module):
10
+ """
11
+ Implementation of a sine-based periodic activation function
12
+ Shape:
13
+ - Input: (B, C, T)
14
+ - Output: (B, C, T), same shape as the input
15
+ Parameters:
16
+ - alpha - trainable parameter
17
+ References:
18
+ - This activation function is from this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
19
+ https://arxiv.org/abs/2006.08195
20
+ Examples:
21
+ >>> a1 = snake(256)
22
+ >>> x = torch.randn(256)
23
+ >>> x = a1(x)
24
+ """
25
+
26
+ def __init__(
27
+ self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False
28
+ ):
29
+ """
30
+ Initialization.
31
+ INPUT:
32
+ - in_features: shape of the input
33
+ - alpha: trainable parameter
34
+ alpha is initialized to 1 by default, higher values = higher-frequency.
35
+ alpha will be trained along with the rest of your model.
36
+ """
37
+ super(Snake, self).__init__()
38
+ self.in_features = in_features
39
+
40
+ # Initialize alpha
41
+ self.alpha_logscale = alpha_logscale
42
+ if self.alpha_logscale: # Log scale alphas initialized to zeros
43
+ self.alpha = Parameter(torch.zeros(in_features) * alpha)
44
+ else: # Linear scale alphas initialized to ones
45
+ self.alpha = Parameter(torch.ones(in_features) * alpha)
46
+
47
+ self.alpha.requires_grad = alpha_trainable
48
+
49
+ self.no_div_by_zero = 0.000000001
50
+
51
+ def forward(self, x):
52
+ """
53
+ Forward pass of the function.
54
+ Applies the function to the input elementwise.
55
+ Snake ∶= x + 1/a * sin^2 (xa)
56
+ """
57
+ alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # Line up with x to [B, C, T]
58
+ if self.alpha_logscale:
59
+ alpha = torch.exp(alpha)
60
+ x = x + (1.0 / (alpha + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
61
+
62
+ return x
63
+
64
+
65
+ class SnakeBeta(nn.Module):
66
+ """
67
+ A modified Snake function which uses separate parameters for the magnitude of the periodic components
68
+ Shape:
69
+ - Input: (B, C, T)
70
+ - Output: (B, C, T), same shape as the input
71
+ Parameters:
72
+ - alpha - trainable parameter that controls frequency
73
+ - beta - trainable parameter that controls magnitude
74
+ References:
75
+ - This activation function is a modified version based on this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
76
+ https://arxiv.org/abs/2006.08195
77
+ Examples:
78
+ >>> a1 = snakebeta(256)
79
+ >>> x = torch.randn(256)
80
+ >>> x = a1(x)
81
+ """
82
+
83
+ def __init__(
84
+ self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False
85
+ ):
86
+ """
87
+ Initialization.
88
+ INPUT:
89
+ - in_features: shape of the input
90
+ - alpha - trainable parameter that controls frequency
91
+ - beta - trainable parameter that controls magnitude
92
+ alpha is initialized to 1 by default, higher values = higher-frequency.
93
+ beta is initialized to 1 by default, higher values = higher-magnitude.
94
+ alpha will be trained along with the rest of your model.
95
+ """
96
+ super(SnakeBeta, self).__init__()
97
+ self.in_features = in_features
98
+
99
+ # Initialize alpha
100
+ self.alpha_logscale = alpha_logscale
101
+ if self.alpha_logscale: # Log scale alphas initialized to zeros
102
+ self.alpha = Parameter(torch.zeros(in_features) * alpha)
103
+ self.beta = Parameter(torch.zeros(in_features) * alpha)
104
+ else: # Linear scale alphas initialized to ones
105
+ self.alpha = Parameter(torch.ones(in_features) * alpha)
106
+ self.beta = Parameter(torch.ones(in_features) * alpha)
107
+
108
+ self.alpha.requires_grad = alpha_trainable
109
+ self.beta.requires_grad = alpha_trainable
110
+
111
+ self.no_div_by_zero = 0.000000001
112
+
113
+ def forward(self, x):
114
+ """
115
+ Forward pass of the function.
116
+ Applies the function to the input elementwise.
117
+ SnakeBeta ∶= x + 1/b * sin^2 (xa)
118
+ """
119
+ alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # Line up with x to [B, C, T]
120
+ beta = self.beta.unsqueeze(0).unsqueeze(-1)
121
+ if self.alpha_logscale:
122
+ alpha = torch.exp(alpha)
123
+ beta = torch.exp(beta)
124
+ x = x + (1.0 / (beta + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
125
+
126
+ return x
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/__init__.py ADDED
File without changes
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/activation1d.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024 NVIDIA CORPORATION.
2
+ # Licensed under the MIT license.
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ from alias_free_activation.torch.resample import UpSample1d, DownSample1d
7
+
8
+ # load fused CUDA kernel: this enables importing anti_alias_activation_cuda
9
+ from alias_free_activation.cuda import load
10
+
11
+ anti_alias_activation_cuda = load.load()
12
+
13
+
14
+ class FusedAntiAliasActivation(torch.autograd.Function):
15
+ """
16
+ Assumes filter size 12, replication padding on upsampling/downsampling, and logscale alpha/beta parameters as inputs.
17
+ The hyperparameters are hard-coded in the kernel to maximize speed.
18
+ NOTE: The fused kenrel is incorrect for Activation1d with different hyperparameters.
19
+ """
20
+
21
+ @staticmethod
22
+ def forward(ctx, inputs, up_ftr, down_ftr, alpha, beta):
23
+ activation_results = anti_alias_activation_cuda.forward(
24
+ inputs, up_ftr, down_ftr, alpha, beta
25
+ )
26
+
27
+ return activation_results
28
+
29
+ @staticmethod
30
+ def backward(ctx, output_grads):
31
+ raise NotImplementedError
32
+ return output_grads, None, None
33
+
34
+
35
+ class Activation1d(nn.Module):
36
+ def __init__(
37
+ self,
38
+ activation,
39
+ up_ratio: int = 2,
40
+ down_ratio: int = 2,
41
+ up_kernel_size: int = 12,
42
+ down_kernel_size: int = 12,
43
+ fused: bool = True,
44
+ ):
45
+ super().__init__()
46
+ self.up_ratio = up_ratio
47
+ self.down_ratio = down_ratio
48
+ self.act = activation
49
+ self.upsample = UpSample1d(up_ratio, up_kernel_size)
50
+ self.downsample = DownSample1d(down_ratio, down_kernel_size)
51
+
52
+ self.fused = fused # Whether to use fused CUDA kernel or not
53
+
54
+ def forward(self, x):
55
+ if not self.fused:
56
+ x = self.upsample(x)
57
+ x = self.act(x)
58
+ x = self.downsample(x)
59
+ return x
60
+ else:
61
+ if self.act.__class__.__name__ == "Snake":
62
+ beta = self.act.alpha.data # Snake uses same params for alpha and beta
63
+ else:
64
+ beta = (
65
+ self.act.beta.data
66
+ ) # Snakebeta uses different params for alpha and beta
67
+ alpha = self.act.alpha.data
68
+ if (
69
+ not self.act.alpha_logscale
70
+ ): # Exp baked into cuda kernel, cancel it out with a log
71
+ alpha = torch.log(alpha)
72
+ beta = torch.log(beta)
73
+
74
+ x = FusedAntiAliasActivation.apply(
75
+ x, self.upsample.filter, self.downsample.lowpass.filter, alpha, beta
76
+ )
77
+ return x
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation.cpp ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* coding=utf-8
2
+ * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <torch/extension.h>
18
+
19
+ extern "C" torch::Tensor fwd_cuda(torch::Tensor const &input, torch::Tensor const &up_filter, torch::Tensor const &down_filter, torch::Tensor const &alpha, torch::Tensor const &beta);
20
+
21
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
22
+ m.def("forward", &fwd_cuda, "Anti-Alias Activation forward (CUDA)");
23
+ }
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation_cuda.cu ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* coding=utf-8
2
+ * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <ATen/ATen.h>
18
+ #include <cuda.h>
19
+ #include <cuda_runtime.h>
20
+ #include <cuda_fp16.h>
21
+ #include <cuda_profiler_api.h>
22
+ #include <ATen/cuda/CUDAContext.h>
23
+ #include <torch/extension.h>
24
+ #include "type_shim.h"
25
+ #include <assert.h>
26
+ #include <cfloat>
27
+ #include <limits>
28
+ #include <stdint.h>
29
+ #include <c10/macros/Macros.h>
30
+
31
+ namespace
32
+ {
33
+ // Hard-coded hyperparameters
34
+ // WARP_SIZE and WARP_BATCH must match the return values batches_per_warp and
35
+ constexpr int ELEMENTS_PER_LDG_STG = 1; //(WARP_ITERATIONS < 4) ? 1 : 4;
36
+ constexpr int BUFFER_SIZE = 32;
37
+ constexpr int FILTER_SIZE = 12;
38
+ constexpr int HALF_FILTER_SIZE = 6;
39
+ constexpr int UPSAMPLE_REPLICATION_PAD = 5; // 5 on each side, matching torch impl
40
+ constexpr int DOWNSAMPLE_REPLICATION_PAD_LEFT = 5; // matching torch impl
41
+ constexpr int DOWNSAMPLE_REPLICATION_PAD_RIGHT = 6; // matching torch impl
42
+
43
+ template <typename input_t, typename output_t, typename acc_t>
44
+ __global__ void anti_alias_activation_forward(
45
+ output_t *dst,
46
+ const input_t *src,
47
+ const input_t *up_ftr,
48
+ const input_t *down_ftr,
49
+ const input_t *alpha,
50
+ const input_t *beta,
51
+ int batch_size,
52
+ int channels,
53
+ int seq_len)
54
+ {
55
+ // Up and downsample filters
56
+ input_t up_filter[FILTER_SIZE];
57
+ input_t down_filter[FILTER_SIZE];
58
+
59
+ // Load data from global memory including extra indices reserved for replication paddings
60
+ input_t elements[2 * FILTER_SIZE + 2 * BUFFER_SIZE + 2 * UPSAMPLE_REPLICATION_PAD] = {0};
61
+ input_t intermediates[2 * FILTER_SIZE + 2 * BUFFER_SIZE + DOWNSAMPLE_REPLICATION_PAD_LEFT + DOWNSAMPLE_REPLICATION_PAD_RIGHT] = {0};
62
+
63
+ // Output stores downsampled output before writing to dst
64
+ output_t output[BUFFER_SIZE];
65
+
66
+ // blockDim/threadIdx = (128, 1, 1)
67
+ // gridDim/blockIdx = (seq_blocks, channels, batches)
68
+ int block_offset = (blockIdx.x * 128 * BUFFER_SIZE + seq_len * (blockIdx.y + gridDim.y * blockIdx.z));
69
+ int local_offset = threadIdx.x * BUFFER_SIZE;
70
+ int seq_offset = blockIdx.x * 128 * BUFFER_SIZE + local_offset;
71
+
72
+ // intermediate have double the seq_len
73
+ int intermediate_local_offset = threadIdx.x * BUFFER_SIZE * 2;
74
+ int intermediate_seq_offset = blockIdx.x * 128 * BUFFER_SIZE * 2 + intermediate_local_offset;
75
+
76
+ // Get values needed for replication padding before moving pointer
77
+ const input_t *right_most_pntr = src + (seq_len * (blockIdx.y + gridDim.y * blockIdx.z));
78
+ input_t seq_left_most_value = right_most_pntr[0];
79
+ input_t seq_right_most_value = right_most_pntr[seq_len - 1];
80
+
81
+ // Move src and dst pointers
82
+ src += block_offset + local_offset;
83
+ dst += block_offset + local_offset;
84
+
85
+ // Alpha and beta values for snake activatons. Applies exp by default
86
+ alpha = alpha + blockIdx.y;
87
+ input_t alpha_val = expf(alpha[0]);
88
+ beta = beta + blockIdx.y;
89
+ input_t beta_val = expf(beta[0]);
90
+
91
+ #pragma unroll
92
+ for (int it = 0; it < FILTER_SIZE; it += 1)
93
+ {
94
+ up_filter[it] = up_ftr[it];
95
+ down_filter[it] = down_ftr[it];
96
+ }
97
+
98
+ // Apply replication padding for upsampling, matching torch impl
99
+ #pragma unroll
100
+ for (int it = -HALF_FILTER_SIZE; it < BUFFER_SIZE + HALF_FILTER_SIZE; it += 1)
101
+ {
102
+ int element_index = seq_offset + it; // index for element
103
+ if ((element_index < 0) && (element_index >= -UPSAMPLE_REPLICATION_PAD))
104
+ {
105
+ elements[2 * (HALF_FILTER_SIZE + it)] = 2 * seq_left_most_value;
106
+ }
107
+ if ((element_index >= seq_len) && (element_index < seq_len + UPSAMPLE_REPLICATION_PAD))
108
+ {
109
+ elements[2 * (HALF_FILTER_SIZE + it)] = 2 * seq_right_most_value;
110
+ }
111
+ if ((element_index >= 0) && (element_index < seq_len))
112
+ {
113
+ elements[2 * (HALF_FILTER_SIZE + it)] = 2 * src[it];
114
+ }
115
+ }
116
+
117
+ // Apply upsampling strided convolution and write to intermediates. It reserves DOWNSAMPLE_REPLICATION_PAD_LEFT for replication padding of the downsampilng conv later
118
+ #pragma unroll
119
+ for (int it = 0; it < (2 * BUFFER_SIZE + 2 * FILTER_SIZE); it += 1)
120
+ {
121
+ input_t acc = 0.0;
122
+ int element_index = intermediate_seq_offset + it; // index for intermediate
123
+ #pragma unroll
124
+ for (int f_idx = 0; f_idx < FILTER_SIZE; f_idx += 1)
125
+ {
126
+ if ((element_index + f_idx) >= 0)
127
+ {
128
+ acc += up_filter[f_idx] * elements[it + f_idx];
129
+ }
130
+ }
131
+ intermediates[it + DOWNSAMPLE_REPLICATION_PAD_LEFT] = acc;
132
+ }
133
+
134
+ // Apply activation function. It reserves DOWNSAMPLE_REPLICATION_PAD_LEFT and DOWNSAMPLE_REPLICATION_PAD_RIGHT for replication padding of the downsampilng conv later
135
+ double no_div_by_zero = 0.000000001;
136
+ #pragma unroll
137
+ for (int it = 0; it < 2 * BUFFER_SIZE + 2 * FILTER_SIZE; it += 1)
138
+ {
139
+ intermediates[it + DOWNSAMPLE_REPLICATION_PAD_LEFT] += (1.0 / (beta_val + no_div_by_zero)) * sinf(intermediates[it + DOWNSAMPLE_REPLICATION_PAD_LEFT] * alpha_val) * sinf(intermediates[it + DOWNSAMPLE_REPLICATION_PAD_LEFT] * alpha_val);
140
+ }
141
+
142
+ // Apply replication padding before downsampling conv from intermediates
143
+ #pragma unroll
144
+ for (int it = 0; it < DOWNSAMPLE_REPLICATION_PAD_LEFT; it += 1)
145
+ {
146
+ intermediates[it] = intermediates[DOWNSAMPLE_REPLICATION_PAD_LEFT];
147
+ }
148
+ #pragma unroll
149
+ for (int it = DOWNSAMPLE_REPLICATION_PAD_LEFT + 2 * BUFFER_SIZE + 2 * FILTER_SIZE; it < DOWNSAMPLE_REPLICATION_PAD_LEFT + 2 * BUFFER_SIZE + 2 * FILTER_SIZE + DOWNSAMPLE_REPLICATION_PAD_RIGHT; it += 1)
150
+ {
151
+ intermediates[it] = intermediates[DOWNSAMPLE_REPLICATION_PAD_LEFT + 2 * BUFFER_SIZE + 2 * FILTER_SIZE - 1];
152
+ }
153
+
154
+ // Apply downsample strided convolution (assuming stride=2) from intermediates
155
+ #pragma unroll
156
+ for (int it = 0; it < BUFFER_SIZE; it += 1)
157
+ {
158
+ input_t acc = 0.0;
159
+ #pragma unroll
160
+ for (int f_idx = 0; f_idx < FILTER_SIZE; f_idx += 1)
161
+ {
162
+ // Add constant DOWNSAMPLE_REPLICATION_PAD_RIGHT to match torch implementation
163
+ acc += down_filter[f_idx] * intermediates[it * 2 + f_idx + DOWNSAMPLE_REPLICATION_PAD_RIGHT];
164
+ }
165
+ output[it] = acc;
166
+ }
167
+
168
+ // Write output to dst
169
+ #pragma unroll
170
+ for (int it = 0; it < BUFFER_SIZE; it += ELEMENTS_PER_LDG_STG)
171
+ {
172
+ int element_index = seq_offset + it;
173
+ if (element_index < seq_len)
174
+ {
175
+ dst[it] = output[it];
176
+ }
177
+ }
178
+
179
+ }
180
+
181
+ template <typename input_t, typename output_t, typename acc_t>
182
+ void dispatch_anti_alias_activation_forward(
183
+ output_t *dst,
184
+ const input_t *src,
185
+ const input_t *up_ftr,
186
+ const input_t *down_ftr,
187
+ const input_t *alpha,
188
+ const input_t *beta,
189
+ int batch_size,
190
+ int channels,
191
+ int seq_len)
192
+ {
193
+ if (seq_len == 0)
194
+ {
195
+ return;
196
+ }
197
+ else
198
+ {
199
+ // Use 128 threads per block to maximimize gpu utilization
200
+ constexpr int threads_per_block = 128;
201
+ constexpr int seq_len_per_block = 4096;
202
+ int blocks_per_seq_len = (seq_len + seq_len_per_block - 1) / seq_len_per_block;
203
+ dim3 blocks(blocks_per_seq_len, channels, batch_size);
204
+ dim3 threads(threads_per_block, 1, 1);
205
+
206
+ anti_alias_activation_forward<input_t, output_t, acc_t>
207
+ <<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(dst, src, up_ftr, down_ftr, alpha, beta, batch_size, channels, seq_len);
208
+ }
209
+ }
210
+ }
211
+
212
+ extern "C" torch::Tensor fwd_cuda(torch::Tensor const &input, torch::Tensor const &up_filter, torch::Tensor const &down_filter, torch::Tensor const &alpha, torch::Tensor const &beta)
213
+ {
214
+ // Input is a 3d tensor with dimensions [batches, channels, seq_len]
215
+ const int batches = input.size(0);
216
+ const int channels = input.size(1);
217
+ const int seq_len = input.size(2);
218
+
219
+ // Output
220
+ auto act_options = input.options().requires_grad(false);
221
+
222
+ torch::Tensor anti_alias_activation_results =
223
+ torch::empty({batches, channels, seq_len}, act_options);
224
+
225
+ void *input_ptr = static_cast<void *>(input.data_ptr());
226
+ void *up_filter_ptr = static_cast<void *>(up_filter.data_ptr());
227
+ void *down_filter_ptr = static_cast<void *>(down_filter.data_ptr());
228
+ void *alpha_ptr = static_cast<void *>(alpha.data_ptr());
229
+ void *beta_ptr = static_cast<void *>(beta.data_ptr());
230
+ void *anti_alias_activation_results_ptr = static_cast<void *>(anti_alias_activation_results.data_ptr());
231
+
232
+ DISPATCH_FLOAT_HALF_AND_BFLOAT(
233
+ input.scalar_type(),
234
+ "dispatch anti alias activation_forward",
235
+ dispatch_anti_alias_activation_forward<scalar_t, scalar_t, float>(
236
+ reinterpret_cast<scalar_t *>(anti_alias_activation_results_ptr),
237
+ reinterpret_cast<const scalar_t *>(input_ptr),
238
+ reinterpret_cast<const scalar_t *>(up_filter_ptr),
239
+ reinterpret_cast<const scalar_t *>(down_filter_ptr),
240
+ reinterpret_cast<const scalar_t *>(alpha_ptr),
241
+ reinterpret_cast<const scalar_t *>(beta_ptr),
242
+ batches,
243
+ channels,
244
+ seq_len););
245
+ return anti_alias_activation_results;
246
+ }
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/compat.h ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* coding=utf-8
2
+ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /*This code is copied fron NVIDIA apex:
18
+ * https://github.com/NVIDIA/apex
19
+ * with minor changes. */
20
+
21
+ #ifndef TORCH_CHECK
22
+ #define TORCH_CHECK AT_CHECK
23
+ #endif
24
+
25
+ #ifdef VERSION_GE_1_3
26
+ #define DATA_PTR data_ptr
27
+ #else
28
+ #define DATA_PTR data
29
+ #endif
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/load.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024 NVIDIA CORPORATION.
2
+ # Licensed under the MIT license.
3
+
4
+ import os
5
+ import pathlib
6
+ import subprocess
7
+
8
+ from torch.utils import cpp_extension
9
+
10
+ """
11
+ Setting this param to a list has a problem of generating different compilation commands (with diferent order of architectures) and leading to recompilation of fused kernels.
12
+ Set it to empty stringo avoid recompilation and assign arch flags explicity in extra_cuda_cflags below
13
+ """
14
+ os.environ["TORCH_CUDA_ARCH_LIST"] = ""
15
+
16
+
17
+ def load():
18
+ # Check if cuda 11 is installed for compute capability 8.0
19
+ cc_flag = []
20
+ _, bare_metal_major, _ = _get_cuda_bare_metal_version(cpp_extension.CUDA_HOME)
21
+ if int(bare_metal_major) >= 11:
22
+ cc_flag.append("-gencode")
23
+ cc_flag.append("arch=compute_80,code=sm_80")
24
+
25
+ # Build path
26
+ srcpath = pathlib.Path(__file__).parent.absolute()
27
+ buildpath = srcpath / "build"
28
+ _create_build_dir(buildpath)
29
+
30
+ # Helper function to build the kernels.
31
+ def _cpp_extention_load_helper(name, sources, extra_cuda_flags):
32
+ return cpp_extension.load(
33
+ name=name,
34
+ sources=sources,
35
+ build_directory=buildpath,
36
+ extra_cflags=[
37
+ "-O3",
38
+ ],
39
+ extra_cuda_cflags=[
40
+ "-O3",
41
+ "-gencode",
42
+ "arch=compute_70,code=sm_70",
43
+ "--use_fast_math",
44
+ ]
45
+ + extra_cuda_flags
46
+ + cc_flag,
47
+ verbose=True,
48
+ )
49
+
50
+ extra_cuda_flags = [
51
+ "-U__CUDA_NO_HALF_OPERATORS__",
52
+ "-U__CUDA_NO_HALF_CONVERSIONS__",
53
+ "--expt-relaxed-constexpr",
54
+ "--expt-extended-lambda",
55
+ ]
56
+
57
+ sources = [
58
+ srcpath / "anti_alias_activation.cpp",
59
+ srcpath / "anti_alias_activation_cuda.cu",
60
+ ]
61
+ anti_alias_activation_cuda = _cpp_extention_load_helper(
62
+ "anti_alias_activation_cuda", sources, extra_cuda_flags
63
+ )
64
+
65
+ return anti_alias_activation_cuda
66
+
67
+
68
+ def _get_cuda_bare_metal_version(cuda_dir):
69
+ raw_output = subprocess.check_output(
70
+ [cuda_dir + "/bin/nvcc", "-V"], universal_newlines=True
71
+ )
72
+ output = raw_output.split()
73
+ release_idx = output.index("release") + 1
74
+ release = output[release_idx].split(".")
75
+ bare_metal_major = release[0]
76
+ bare_metal_minor = release[1][0]
77
+
78
+ return raw_output, bare_metal_major, bare_metal_minor
79
+
80
+
81
+ def _create_build_dir(buildpath):
82
+ try:
83
+ os.mkdir(buildpath)
84
+ except OSError:
85
+ if not os.path.isdir(buildpath):
86
+ print(f"Creation of the build directory {buildpath} failed")
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/type_shim.h ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* coding=utf-8
2
+ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <ATen/ATen.h>
18
+ #include "compat.h"
19
+
20
+ #define DISPATCH_FLOAT_HALF_AND_BFLOAT(TYPE, NAME, ...) \
21
+ switch (TYPE) \
22
+ { \
23
+ case at::ScalarType::Float: \
24
+ { \
25
+ using scalar_t = float; \
26
+ __VA_ARGS__; \
27
+ break; \
28
+ } \
29
+ case at::ScalarType::Half: \
30
+ { \
31
+ using scalar_t = at::Half; \
32
+ __VA_ARGS__; \
33
+ break; \
34
+ } \
35
+ case at::ScalarType::BFloat16: \
36
+ { \
37
+ using scalar_t = at::BFloat16; \
38
+ __VA_ARGS__; \
39
+ break; \
40
+ } \
41
+ default: \
42
+ AT_ERROR(#NAME, " not implemented for '", toString(TYPE), "'"); \
43
+ }
44
+
45
+ #define DISPATCH_FLOAT_HALF_AND_BFLOAT_INOUT_TYPES(TYPEIN, TYPEOUT, NAME, ...) \
46
+ switch (TYPEIN) \
47
+ { \
48
+ case at::ScalarType::Float: \
49
+ { \
50
+ using scalar_t_in = float; \
51
+ switch (TYPEOUT) \
52
+ { \
53
+ case at::ScalarType::Float: \
54
+ { \
55
+ using scalar_t_out = float; \
56
+ __VA_ARGS__; \
57
+ break; \
58
+ } \
59
+ case at::ScalarType::Half: \
60
+ { \
61
+ using scalar_t_out = at::Half; \
62
+ __VA_ARGS__; \
63
+ break; \
64
+ } \
65
+ case at::ScalarType::BFloat16: \
66
+ { \
67
+ using scalar_t_out = at::BFloat16; \
68
+ __VA_ARGS__; \
69
+ break; \
70
+ } \
71
+ default: \
72
+ AT_ERROR(#NAME, " not implemented for '", toString(TYPEOUT), "'"); \
73
+ } \
74
+ break; \
75
+ } \
76
+ case at::ScalarType::Half: \
77
+ { \
78
+ using scalar_t_in = at::Half; \
79
+ using scalar_t_out = at::Half; \
80
+ __VA_ARGS__; \
81
+ break; \
82
+ } \
83
+ case at::ScalarType::BFloat16: \
84
+ { \
85
+ using scalar_t_in = at::BFloat16; \
86
+ using scalar_t_out = at::BFloat16; \
87
+ __VA_ARGS__; \
88
+ break; \
89
+ } \
90
+ default: \
91
+ AT_ERROR(#NAME, " not implemented for '", toString(TYPEIN), "'"); \
92
+ }
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
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 *
6
+ from .act import *
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/act.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
6
+ from .resample import (DownSample1d, UpSample1d)
7
+
8
+
9
+ class Activation1d(nn.Module):
10
+
11
+ def __init__(
12
+ self,
13
+ activation,
14
+ up_ratio: int = 2,
15
+ down_ratio: int = 2,
16
+ up_kernel_size: int = 12,
17
+ down_kernel_size: int = 12,
18
+ ):
19
+ super().__init__()
20
+ self.up_ratio = up_ratio
21
+ self.down_ratio = down_ratio
22
+ self.act = activation
23
+ self.upsample = UpSample1d(up_ratio, up_kernel_size)
24
+ self.downsample = DownSample1d(down_ratio, down_kernel_size)
25
+
26
+ # x: [B,C,T]
27
+ def forward(self, x):
28
+ x = self.upsample(x)
29
+ x = self.act(x)
30
+ x = self.downsample(x)
31
+
32
+ return x
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/filter.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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(
21
+ x == 0,
22
+ torch.tensor(1.0, device=x.device, dtype=x.dtype),
23
+ torch.sin(math.pi * x) / math.pi / x,
24
+ )
25
+
26
+
27
+ # This code is adopted from adefossez's julius.lowpass.LowPassFilters under the MIT License
28
+ # https://adefossez.github.io/julius/julius/lowpass.html
29
+ # LICENSE is in incl_licenses directory.
30
+ def kaiser_sinc_filter1d(
31
+ cutoff, half_width, kernel_size
32
+ ): # return filter [1,1,kernel_size]
33
+ even = kernel_size % 2 == 0
34
+ half_size = kernel_size // 2
35
+
36
+ # For kaiser window
37
+ delta_f = 4 * half_width
38
+ A = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
39
+ if A > 50.0:
40
+ beta = 0.1102 * (A - 8.7)
41
+ elif A >= 21.0:
42
+ beta = 0.5842 * (A - 21) ** 0.4 + 0.07886 * (A - 21.0)
43
+ else:
44
+ beta = 0.0
45
+ window = torch.kaiser_window(kernel_size, beta=beta, periodic=False)
46
+
47
+ # ratio = 0.5/cutoff -> 2 * cutoff = 1 / ratio
48
+ if even:
49
+ time = torch.arange(-half_size, half_size) + 0.5
50
+ else:
51
+ time = torch.arange(kernel_size) - half_size
52
+ if cutoff == 0:
53
+ filter_ = torch.zeros_like(time)
54
+ else:
55
+ filter_ = 2 * cutoff * window * sinc(2 * cutoff * time)
56
+ """
57
+ Normalize filter to have sum = 1, otherwise we will have a small leakage of the constant component in the input signal.
58
+ """
59
+ filter_ /= filter_.sum()
60
+ filter = filter_.view(1, 1, kernel_size)
61
+
62
+ return filter
63
+
64
+
65
+ class LowPassFilter1d(nn.Module):
66
+ def __init__(
67
+ self,
68
+ cutoff=0.5,
69
+ half_width=0.6,
70
+ stride: int = 1,
71
+ padding: bool = True,
72
+ padding_mode: str = "replicate",
73
+ kernel_size: int = 12,
74
+ ):
75
+ """
76
+ kernel_size should be even number for stylegan3 setup, in this implementation, odd number is also possible.
77
+ """
78
+ super().__init__()
79
+ if cutoff < -0.0:
80
+ raise ValueError("Minimum cutoff must be larger than zero.")
81
+ if cutoff > 0.5:
82
+ raise ValueError("A cutoff above 0.5 does not make sense.")
83
+ self.kernel_size = kernel_size
84
+ self.even = kernel_size % 2 == 0
85
+ self.pad_left = kernel_size // 2 - int(self.even)
86
+ self.pad_right = kernel_size // 2
87
+ self.stride = stride
88
+ self.padding = padding
89
+ self.padding_mode = padding_mode
90
+ filter = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
91
+ self.register_buffer("filter", filter)
92
+
93
+ # Input [B, C, T]
94
+ def forward(self, x):
95
+ _, C, _ = x.shape
96
+
97
+ if self.padding:
98
+ x = F.pad(x, (self.pad_left, self.pad_right), mode=self.padding_mode)
99
+ out = F.conv1d(x, self.filter.expand(C, -1, -1), stride=self.stride, groups=C)
100
+
101
+ return out
unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/resample.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
7
+ from .filter import (LowPassFilter1d, kaiser_sinc_filter1d)
8
+
9
+
10
+ class UpSample1d(nn.Module):
11
+
12
+ def __init__(self, ratio=2, kernel_size=None):
13
+ super().__init__()
14
+ self.ratio = ratio
15
+ self.kernel_size = (int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size)
16
+ self.stride = ratio
17
+ self.pad = self.kernel_size // ratio - 1
18
+ self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
19
+ self.pad_right = (self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2)
20
+ filter = kaiser_sinc_filter1d(cutoff=0.5 / ratio,
21
+ half_width=0.6 / ratio,
22
+ kernel_size=self.kernel_size)
23
+ self.register_buffer("filter", filter)
24
+
25
+ # x: [B, C, T]
26
+ def forward(self, x):
27
+ _, C, _ = x.shape
28
+
29
+ x = F.pad(x, (self.pad, self.pad), mode="replicate")
30
+ x = self.ratio * F.conv_transpose1d(
31
+ x, self.filter.expand(C, -1, -1), stride=self.stride, groups=C)
32
+ x = x[..., self.pad_left:-self.pad_right]
33
+
34
+ return x
35
+
36
+
37
+ class DownSample1d(nn.Module):
38
+
39
+ def __init__(self, ratio=2, kernel_size=None):
40
+ super().__init__()
41
+ self.ratio = ratio
42
+ self.kernel_size = (int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size)
43
+ self.lowpass = LowPassFilter1d(
44
+ cutoff=0.5 / ratio,
45
+ half_width=0.6 / ratio,
46
+ stride=ratio,
47
+ kernel_size=self.kernel_size,
48
+ )
49
+
50
+ def forward(self, x):
51
+ xx = self.lowpass(x)
52
+
53
+ return xx