Spaces:
Running on Zero
Running on Zero
Vansh Chugh commited on
Commit ·
7d124ae
1
Parent(s): 28fd8eb
initial deploy
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +3 -0
- README.md +1 -1
- app.py +337 -0
- requirements.txt +19 -0
- unison/__init__.py +44 -0
- unison/commons/__init__.py +242 -0
- unison/commons/infer_state.py +48 -0
- unison/commons/parallel_states.py +85 -0
- unison/config/D20S0_O_40ch.yaml +27 -0
- unison/config/D24S0_O_20ch.yaml +27 -0
- unison/models/__init__.py +16 -0
- unison/models/mmaudio/__init__.py +1 -0
- unison/models/mmaudio/ext/__init__.py +1 -0
- unison/models/mmaudio/ext/autoencoder/__init__.py +1 -0
- unison/models/mmaudio/ext/autoencoder/autoencoder.py +60 -0
- unison/models/mmaudio/ext/autoencoder/distributions.py +45 -0
- unison/models/mmaudio/ext/autoencoder/edm2_utils.py +168 -0
- unison/models/mmaudio/ext/autoencoder/vae.py +363 -0
- unison/models/mmaudio/ext/autoencoder/vae_modules.py +117 -0
- unison/models/mmaudio/ext/bigvgan/LICENSE +21 -0
- unison/models/mmaudio/ext/bigvgan/__init__.py +1 -0
- unison/models/mmaudio/ext/bigvgan/activations.py +120 -0
- unison/models/mmaudio/ext/bigvgan/alias_free_torch/__init__.py +6 -0
- unison/models/mmaudio/ext/bigvgan/alias_free_torch/act.py +28 -0
- unison/models/mmaudio/ext/bigvgan/alias_free_torch/filter.py +95 -0
- unison/models/mmaudio/ext/bigvgan/alias_free_torch/resample.py +49 -0
- unison/models/mmaudio/ext/bigvgan/bigvgan.py +32 -0
- unison/models/mmaudio/ext/bigvgan/bigvgan_vocoder.yml +63 -0
- unison/models/mmaudio/ext/bigvgan/env.py +18 -0
- unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_1 +21 -0
- unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_2 +21 -0
- unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_3 +201 -0
- unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_4 +29 -0
- unison/models/mmaudio/ext/bigvgan/incl_licenses/LICENSE_5 +16 -0
- unison/models/mmaudio/ext/bigvgan/models.py +255 -0
- unison/models/mmaudio/ext/bigvgan/utils.py +31 -0
- unison/models/mmaudio/ext/bigvgan_v2/LICENSE +21 -0
- unison/models/mmaudio/ext/bigvgan_v2/__init__.py +0 -0
- unison/models/mmaudio/ext/bigvgan_v2/activations.py +126 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/__init__.py +0 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/activation1d.py +77 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation.cpp +23 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/anti_alias_activation_cuda.cu +246 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/compat.h +29 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/load.py +86 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/cuda/type_shim.h +92 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/__init__.py +6 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/act.py +32 -0
- unison/models/mmaudio/ext/bigvgan_v2/alias_free_activation/torch/filter.py +101 -0
- 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:
|
| 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
|