Spaces:
Runtime error
Runtime error
Deploy hf-space @ c63b38a: batch export + ZeroGPU dynamic duration
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +17 -1
- LICENSE +25 -0
- README.md +3 -1
- app.py +458 -125
- export_utils.py +206 -0
- src/SongFormer/infer.sh +3 -1
- src/SongFormer/infer/infer.py +149 -6
- src/third_party/MuQ/.gitattributes +0 -2
- src/third_party/MuQ/.gitignore +0 -46
- src/third_party/MuQ/.gitmodules +0 -3
- src/third_party/MuQ/LICENSE +0 -21
- src/third_party/MuQ/LICENSE_weights +0 -399
- src/third_party/MuQ/README.md +0 -129
- src/third_party/MuQ/images/muq-logo.jpeg +0 -0
- src/third_party/MuQ/images/radar.jpg +0 -0
- src/third_party/MuQ/images/tab-marble.jpg +0 -3
- src/third_party/MuQ/images/tab-mulan.png +0 -0
- src/third_party/MuQ/images/tagging.jpg +0 -0
- src/third_party/MuQ/requirements.txt +0 -11
- src/third_party/MuQ/setup.py +0 -34
- src/third_party/MuQ/src/muq/__init__.py +0 -2
- src/third_party/MuQ/src/muq/muq/__init__.py +0 -1
- src/third_party/MuQ/src/muq/muq/models/__init__.py +0 -0
- src/third_party/MuQ/src/muq/muq/models/muq_model.py +0 -366
- src/third_party/MuQ/src/muq/muq/modules/__init__.py +0 -2
- src/third_party/MuQ/src/muq/muq/modules/conv.py +0 -77
- src/third_party/MuQ/src/muq/muq/modules/features.py +0 -37
- src/third_party/MuQ/src/muq/muq/modules/flash_conformer.py +0 -2114
- src/third_party/MuQ/src/muq/muq/modules/random_quantizer.py +0 -68
- src/third_party/MuQ/src/muq/muq/modules/rvq.py +0 -314
- src/third_party/MuQ/src/muq/muq/muq.py +0 -90
- src/third_party/MuQ/src/muq/muq_mulan/__init__.py +0 -1
- src/third_party/MuQ/src/muq/muq_mulan/models/__init__.py +0 -0
- src/third_party/MuQ/src/muq/muq_mulan/models/audio.py +0 -294
- src/third_party/MuQ/src/muq/muq_mulan/models/mulan.py +0 -148
- src/third_party/MuQ/src/muq/muq_mulan/models/text.py +0 -241
- src/third_party/MuQ/src/muq/muq_mulan/modules/__init__.py +0 -0
- src/third_party/MuQ/src/muq/muq_mulan/modules/contrastive.py +0 -238
- src/third_party/MuQ/src/muq/muq_mulan/modules/distributed.py +0 -83
- src/third_party/MuQ/src/muq/muq_mulan/modules/extend_distributed.py +0 -604
- src/third_party/MuQ/src/muq/muq_mulan/modules/transformer.py +0 -185
- src/third_party/MuQ/src/muq/muq_mulan/modules/utils.py +0 -45
- src/third_party/MuQ/src/muq/muq_mulan/muq_mulan.py +0 -271
- src/third_party/MuQ/src/recipes/contrastive_learning/README.md +0 -107
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/2gpu.yaml +0 -17
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node.yaml +0 -19
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node_fp16.yaml +0 -19
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node_zero2.yaml +0 -25
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/8gpu_fp16.yaml +0 -17
- src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/8gpu_fp16_zero2.yaml +0 -22
.gitignore
CHANGED
|
@@ -8,7 +8,6 @@ ENV/
|
|
| 8 |
env/
|
| 9 |
.venv/
|
| 10 |
.ENV/
|
| 11 |
-
|
| 12 |
# Python IDEs
|
| 13 |
.idea/
|
| 14 |
.vscode/
|
|
@@ -29,6 +28,17 @@ tensorboard_logs/
|
|
| 29 |
.DS_Store
|
| 30 |
Thumbs.db
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
# Compiled extension modules
|
| 33 |
*.so
|
| 34 |
*.dylib
|
|
@@ -40,3 +50,9 @@ cython_debug/
|
|
| 40 |
# Other custom ignore rules
|
| 41 |
*.bak
|
| 42 |
*.swp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
env/
|
| 9 |
.venv/
|
| 10 |
.ENV/
|
|
|
|
| 11 |
# Python IDEs
|
| 12 |
.idea/
|
| 13 |
.vscode/
|
|
|
|
| 28 |
.DS_Store
|
| 29 |
Thumbs.db
|
| 30 |
|
| 31 |
+
# PyCharm files
|
| 32 |
+
*.iml
|
| 33 |
+
.idea/
|
| 34 |
+
|
| 35 |
+
# Coverage and testing tools
|
| 36 |
+
.coverage
|
| 37 |
+
nosetests.xml
|
| 38 |
+
coverage.xml
|
| 39 |
+
*.cover
|
| 40 |
+
*.log
|
| 41 |
+
|
| 42 |
# Compiled extension modules
|
| 43 |
*.so
|
| 44 |
*.dylib
|
|
|
|
| 50 |
# Other custom ignore rules
|
| 51 |
*.bak
|
| 52 |
*.swp
|
| 53 |
+
|
| 54 |
+
.ruff_cache/
|
| 55 |
+
|
| 56 |
+
# Model checkpoints (downloaded at runtime)
|
| 57 |
+
ckpts/
|
| 58 |
+
.gradio/
|
LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Creative Commons Attribution 4.0 International Public License
|
| 2 |
+
|
| 3 |
+
By exercising the Licensed Rights (defined below), You accept and agree
|
| 4 |
+
to be bound by the terms and conditions of this Creative Commons
|
| 5 |
+
Attribution 4.0 International Public License ("Public License").
|
| 6 |
+
To the extent this Public License may be interpreted as a contract,
|
| 7 |
+
You are granted the Licensed Rights in consideration of Your acceptance
|
| 8 |
+
of these terms and conditions, and the Licensor grants You such rights
|
| 9 |
+
in consideration of benefits the Licensor receives from making
|
| 10 |
+
the Licensed Material available under these terms and conditions.
|
| 11 |
+
|
| 12 |
+
You are free to:
|
| 13 |
+
- Share — copy and redistribute the material in any medium or format
|
| 14 |
+
- Adapt — remix, transform, and build upon the material for any purpose, even commercially.
|
| 15 |
+
|
| 16 |
+
Under the following terms:
|
| 17 |
+
- Attribution — You must give appropriate credit, provide a link to the license,
|
| 18 |
+
and indicate if changes were made. You may do so in any reasonable manner,
|
| 19 |
+
but not in any way that suggests the licensor endorses you or your use.
|
| 20 |
+
|
| 21 |
+
No additional restrictions — You may not apply legal terms or
|
| 22 |
+
technological measures that legally restrict others from doing
|
| 23 |
+
anything the license permits.
|
| 24 |
+
|
| 25 |
+
Full license text: https://creativecommons.org/licenses/by/4.0/legalcode
|
README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
---
|
| 2 |
title: SongFormer
|
| 3 |
-
emoji: "
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: gradio
|
|
@@ -40,6 +40,8 @@ Chunbo Hao<sup>*</sup>, Ruibin Yuan<sup>*</sup>, Jixun Yao, Qixin Deng,
|
|
| 40 |
|
| 41 |
SongFormer is a music structure analysis framework that leverages multi-resolution self-supervised representations and heterogeneous supervision, accompanied by the large-scale multilingual dataset SongFormDB and the high-quality benchmark SongFormBench to foster fair and reproducible research.
|
| 42 |
|
|
|
|
|
|
|
| 43 |

|
| 44 |
|
| 45 |
## Citation
|
|
|
|
| 1 |
---
|
| 2 |
title: SongFormer
|
| 3 |
+
emoji: "🎵"
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: gradio
|
|
|
|
| 40 |
|
| 41 |
SongFormer is a music structure analysis framework that leverages multi-resolution self-supervised representations and heterogeneous supervision, accompanied by the large-scale multilingual dataset SongFormDB and the high-quality benchmark SongFormBench to foster fair and reproducible research.
|
| 42 |
|
| 43 |
+
**This Space offers two modes:** analyze a *Single File* with downloadable results (JSON / MSA / CSV / plot / ZIP), or use the *Batch* tab to process multiple files with live per-file status, a combined ZIP (downloadable mid-run), and a per-file inspector with audio playback. Runs on ZeroGPU — each analyzed file consumes daily GPU quota.
|
| 44 |
+
|
| 45 |

|
| 46 |
|
| 47 |
## Citation
|
app.py
CHANGED
|
@@ -1,30 +1,9 @@
|
|
| 1 |
import os
|
| 2 |
import sys
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
songformer_path = os.path.join(current_dir, "src", "SongFormer")
|
| 8 |
-
if os.path.exists(songformer_path):
|
| 9 |
-
os.chdir(songformer_path)
|
| 10 |
-
else:
|
| 11 |
-
print(f"The target working directory does not exist: {songformer_path}")
|
| 12 |
-
|
| 13 |
-
working_dir = os.getcwd()
|
| 14 |
-
|
| 15 |
-
third_party_path = os.path.join(current_dir, "src", "third_party")
|
| 16 |
-
if os.path.exists(third_party_path):
|
| 17 |
-
sys.path.insert(0, third_party_path)
|
| 18 |
-
sys.path.insert(0, working_dir)
|
| 19 |
-
|
| 20 |
-
musicfm_paths = [
|
| 21 |
-
os.path.join(current_dir, "src"),
|
| 22 |
-
os.path.join(current_dir, "third_party"),
|
| 23 |
-
os.path.join(current_dir, "src", "SongFormer"),
|
| 24 |
-
]
|
| 25 |
-
for path in musicfm_paths:
|
| 26 |
-
if os.path.exists(path):
|
| 27 |
-
sys.path.insert(0, path)
|
| 28 |
|
| 29 |
# monkey patch to fix issues in msaf
|
| 30 |
import scipy
|
|
@@ -39,7 +18,8 @@ import json
|
|
| 39 |
import math
|
| 40 |
import importlib
|
| 41 |
import matplotlib
|
| 42 |
-
|
|
|
|
| 43 |
import matplotlib.pyplot as plt
|
| 44 |
import matplotlib.ticker as ticker
|
| 45 |
from pathlib import Path
|
|
@@ -51,6 +31,11 @@ from musicfm.model.musicfm_25hz import MusicFM25Hz
|
|
| 51 |
from postprocessing.functional import postprocess_functional_structure
|
| 52 |
from dataset.label2id import DATASET_ID_ALLOWED_LABEL_IDS, DATASET_LABEL_TO_DATASET_ID
|
| 53 |
from utils.fetch_pretrained import download_all
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
import spaces
|
| 55 |
|
| 56 |
# Constants
|
|
@@ -69,6 +54,23 @@ msa_model = None
|
|
| 69 |
device = None
|
| 70 |
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
def load_checkpoint(checkpoint_path, device=None):
|
| 73 |
"""Load checkpoint from path"""
|
| 74 |
if device is None:
|
|
@@ -90,7 +92,7 @@ def initialize_models(model_name: str, checkpoint: str, config_path: str):
|
|
| 90 |
global muq_model, musicfm_model, msa_model, device
|
| 91 |
|
| 92 |
# Set device
|
| 93 |
-
device =
|
| 94 |
|
| 95 |
# Load MuQ
|
| 96 |
muq_model = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")
|
|
@@ -123,17 +125,26 @@ def initialize_models(model_name: str, checkpoint: str, config_path: str):
|
|
| 123 |
return hp
|
| 124 |
|
| 125 |
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
def process_audio(audio_path, win_size=420, hop_size=420, num_classes=128):
|
| 128 |
"""Process audio file and return structure analysis results"""
|
| 129 |
global muq_model, musicfm_model, msa_model, device
|
| 130 |
|
| 131 |
if muq_model is None:
|
| 132 |
-
hp = initialize_models(
|
| 133 |
-
model_name="SongFormer",
|
| 134 |
-
checkpoint="SongFormer.safetensors",
|
| 135 |
-
config_path="SongFormer.yaml",
|
| 136 |
-
)
|
| 137 |
else:
|
| 138 |
hp = OmegaConf.load(os.path.join("configs", "SongFormer.yaml"))
|
| 139 |
|
|
@@ -180,14 +191,14 @@ def process_audio(audio_path, win_size=420, hop_size=420, num_classes=128):
|
|
| 180 |
muq_output = muq_model(audio_seg.unsqueeze(0), output_hidden_states=True)
|
| 181 |
muq_embd_420s = muq_output["hidden_states"][10]
|
| 182 |
del muq_output
|
| 183 |
-
|
| 184 |
|
| 185 |
_, musicfm_hidden_states = musicfm_model.get_predictions(
|
| 186 |
audio_seg.unsqueeze(0)
|
| 187 |
)
|
| 188 |
musicfm_embd_420s = musicfm_hidden_states[10]
|
| 189 |
del musicfm_hidden_states
|
| 190 |
-
|
| 191 |
|
| 192 |
# Process 30-second segments
|
| 193 |
wraped_muq_embd_30s = []
|
|
@@ -211,14 +222,14 @@ def process_audio(audio_path, win_size=420, hop_size=420, num_classes=128):
|
|
| 211 |
output_hidden_states=True,
|
| 212 |
)["hidden_states"][10]
|
| 213 |
)
|
| 214 |
-
|
| 215 |
|
| 216 |
wraped_musicfm_embd_30s.append(
|
| 217 |
musicfm_model.get_predictions(
|
| 218 |
audio[start_idx_30s:end_idx_30s].unsqueeze(0)
|
| 219 |
)[1][10]
|
| 220 |
)
|
| 221 |
-
|
| 222 |
|
| 223 |
if wraped_muq_embd_30s:
|
| 224 |
wraped_muq_embd_30s = torch.concatenate(wraped_muq_embd_30s, dim=1)
|
|
@@ -325,6 +336,7 @@ def create_visualization(
|
|
| 325 |
logits, msa_output, label_num=8, frame_rates=AFTER_DOWNSAMPLING_FRAME_RATES
|
| 326 |
):
|
| 327 |
"""Create visualization plot"""
|
|
|
|
| 328 |
try:
|
| 329 |
from dataset.label2id import ID_TO_LABEL
|
| 330 |
except:
|
|
@@ -420,48 +432,241 @@ def rule_post_processing(msa_list):
|
|
| 420 |
return result
|
| 421 |
|
| 422 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
def process_and_analyze(audio_file):
|
| 424 |
"""Main processing function"""
|
| 425 |
|
| 426 |
-
def format_time(t: float) -> str:
|
| 427 |
-
minutes = int(t // 60)
|
| 428 |
-
seconds = t % 60
|
| 429 |
-
return f"{minutes:02d}:{seconds:06.3f}"
|
| 430 |
-
|
| 431 |
if audio_file is None:
|
| 432 |
-
return None, "", "", None
|
| 433 |
|
| 434 |
try:
|
| 435 |
-
#
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
msa_format = format_as_msa(msa_output)
|
| 442 |
-
json_format = format_as_json(segments)
|
| 443 |
|
| 444 |
# Create table data
|
| 445 |
-
table_data =
|
| 446 |
-
[
|
| 447 |
-
f"{float(seg['start']):.2f} ({format_time(float(seg['start']))})",
|
| 448 |
-
f"{float(seg['end']):.2f} ({format_time(float(seg['end']))})",
|
| 449 |
-
seg["label"],
|
| 450 |
-
]
|
| 451 |
-
for seg in segments
|
| 452 |
-
]
|
| 453 |
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
|
| 459 |
except Exception as e:
|
| 460 |
import traceback
|
| 461 |
|
| 462 |
error_msg = f"Error: {str(e)}\n{traceback.format_exc()}"
|
| 463 |
-
print(error_msg)
|
| 464 |
-
return None, "", error_msg, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 465 |
|
| 466 |
|
| 467 |
# Create Gradio interface
|
|
@@ -503,78 +708,173 @@ with gr.Blocks(
|
|
| 503 |
# Links
|
| 504 |
gr.HTML("""
|
| 505 |
<div class="links-container">
|
| 506 |
-
<
|
| 507 |
-
<
|
| 508 |
-
<a href="https://arxiv.org/abs/2510.02797">
|
| 509 |
-
<
|
| 510 |
-
<
|
| 511 |
-
<a href="https://
|
| 512 |
-
<
|
| 513 |
-
<
|
| 514 |
-
<a href="https://
|
| 515 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 516 |
</div>
|
| 517 |
""")
|
| 518 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 519 |
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 526 |
|
| 527 |
-
|
| 528 |
-
gr.
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
["examples/BC_282ece.mp3"],
|
| 533 |
-
["examples/BHX_0158_letitrock.wav"],
|
| 534 |
-
["examples/BHX_0374_drunkonyou.wav"],
|
| 535 |
-
],
|
| 536 |
-
inputs=[audio_input],
|
| 537 |
-
label="Click to load example",
|
| 538 |
-
)
|
| 539 |
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 545 |
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
)
|
| 555 |
-
with gr.Column(scale=8):
|
| 556 |
with gr.Row():
|
| 557 |
-
with gr.
|
| 558 |
-
|
| 559 |
-
label="
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
interactive=False,
|
| 563 |
-
show_copy_button=True,
|
| 564 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
with gr.Row():
|
| 566 |
-
with gr.
|
| 567 |
-
|
| 568 |
-
label="
|
| 569 |
-
|
| 570 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 571 |
interactive=False,
|
| 572 |
-
show_copy_button=True,
|
| 573 |
)
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
gr.HTML("""
|
| 580 |
<div style="display: flex; justify-content: center; align-items: center;">
|
|
@@ -586,7 +886,39 @@ with gr.Blocks(
|
|
| 586 |
analyze_btn.click(
|
| 587 |
fn=process_and_analyze,
|
| 588 |
inputs=[audio_input],
|
| 589 |
-
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
)
|
| 591 |
|
| 592 |
if __name__ == "__main__":
|
|
@@ -601,5 +933,6 @@ if __name__ == "__main__":
|
|
| 601 |
)
|
| 602 |
print("Models loaded successfully!")
|
| 603 |
|
| 604 |
-
# Launch interface
|
|
|
|
| 605 |
demo.launch()
|
|
|
|
| 1 |
import os
|
| 2 |
import sys
|
| 3 |
|
| 4 |
+
os.chdir(os.path.join("src", "SongFormer"))
|
| 5 |
+
sys.path.append(os.path.join("..", "third_party"))
|
| 6 |
+
sys.path.append(".")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
# monkey patch to fix issues in msaf
|
| 9 |
import scipy
|
|
|
|
| 18 |
import math
|
| 19 |
import importlib
|
| 20 |
import matplotlib
|
| 21 |
+
|
| 22 |
+
matplotlib.use("Agg") # non-interactive backend: safe for rendering plots off the main thread
|
| 23 |
import matplotlib.pyplot as plt
|
| 24 |
import matplotlib.ticker as ticker
|
| 25 |
from pathlib import Path
|
|
|
|
| 31 |
from postprocessing.functional import postprocess_functional_structure
|
| 32 |
from dataset.label2id import DATASET_ID_ALLOWED_LABEL_IDS, DATASET_LABEL_TO_DATASET_ID
|
| 33 |
from utils.fetch_pretrained import download_all
|
| 34 |
+
|
| 35 |
+
import export_utils
|
| 36 |
+
|
| 37 |
+
# ZeroGPU (Hugging Face Spaces). Preinstalled on the Space; this branch
|
| 38 |
+
# is Space-only and never runs locally.
|
| 39 |
import spaces
|
| 40 |
|
| 41 |
# Constants
|
|
|
|
| 54 |
device = None
|
| 55 |
|
| 56 |
|
| 57 |
+
def get_device():
|
| 58 |
+
"""Select the best available device: MPS (Apple Silicon), CUDA, or CPU."""
|
| 59 |
+
if torch.cuda.is_available():
|
| 60 |
+
return torch.device("cuda")
|
| 61 |
+
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
| 62 |
+
return torch.device("mps")
|
| 63 |
+
return torch.device("cpu")
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def clear_device_cache(device):
|
| 67 |
+
"""Clear GPU memory cache for the given device type."""
|
| 68 |
+
if device.type == "cuda":
|
| 69 |
+
torch.cuda.empty_cache()
|
| 70 |
+
elif device.type == "mps":
|
| 71 |
+
torch.mps.empty_cache()
|
| 72 |
+
|
| 73 |
+
|
| 74 |
def load_checkpoint(checkpoint_path, device=None):
|
| 75 |
"""Load checkpoint from path"""
|
| 76 |
if device is None:
|
|
|
|
| 92 |
global muq_model, musicfm_model, msa_model, device
|
| 93 |
|
| 94 |
# Set device
|
| 95 |
+
device = get_device()
|
| 96 |
|
| 97 |
# Load MuQ
|
| 98 |
muq_model = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")
|
|
|
|
| 125 |
return hp
|
| 126 |
|
| 127 |
|
| 128 |
+
def _gpu_duration(audio_path, win_size=420, hop_size=420, num_classes=128):
|
| 129 |
+
"""Estimate GPU seconds for one file (ZeroGPU dynamic duration).
|
| 130 |
+
|
| 131 |
+
Conservative: 30s base + 0.2s per audio second, clamped to [60, 300].
|
| 132 |
+
Tune the constants from observed Space timings.
|
| 133 |
+
"""
|
| 134 |
+
try:
|
| 135 |
+
audio_secs = librosa.get_duration(path=audio_path)
|
| 136 |
+
except Exception:
|
| 137 |
+
return 120
|
| 138 |
+
return int(min(300, max(60, 30 + 0.2 * audio_secs)))
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
@spaces.GPU(duration=_gpu_duration)
|
| 142 |
def process_audio(audio_path, win_size=420, hop_size=420, num_classes=128):
|
| 143 |
"""Process audio file and return structure analysis results"""
|
| 144 |
global muq_model, musicfm_model, msa_model, device
|
| 145 |
|
| 146 |
if muq_model is None:
|
| 147 |
+
hp = initialize_models()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
else:
|
| 149 |
hp = OmegaConf.load(os.path.join("configs", "SongFormer.yaml"))
|
| 150 |
|
|
|
|
| 191 |
muq_output = muq_model(audio_seg.unsqueeze(0), output_hidden_states=True)
|
| 192 |
muq_embd_420s = muq_output["hidden_states"][10]
|
| 193 |
del muq_output
|
| 194 |
+
clear_device_cache(device)
|
| 195 |
|
| 196 |
_, musicfm_hidden_states = musicfm_model.get_predictions(
|
| 197 |
audio_seg.unsqueeze(0)
|
| 198 |
)
|
| 199 |
musicfm_embd_420s = musicfm_hidden_states[10]
|
| 200 |
del musicfm_hidden_states
|
| 201 |
+
clear_device_cache(device)
|
| 202 |
|
| 203 |
# Process 30-second segments
|
| 204 |
wraped_muq_embd_30s = []
|
|
|
|
| 222 |
output_hidden_states=True,
|
| 223 |
)["hidden_states"][10]
|
| 224 |
)
|
| 225 |
+
clear_device_cache(device)
|
| 226 |
|
| 227 |
wraped_musicfm_embd_30s.append(
|
| 228 |
musicfm_model.get_predictions(
|
| 229 |
audio[start_idx_30s:end_idx_30s].unsqueeze(0)
|
| 230 |
)[1][10]
|
| 231 |
)
|
| 232 |
+
clear_device_cache(device)
|
| 233 |
|
| 234 |
if wraped_muq_embd_30s:
|
| 235 |
wraped_muq_embd_30s = torch.concatenate(wraped_muq_embd_30s, dim=1)
|
|
|
|
| 336 |
logits, msa_output, label_num=8, frame_rates=AFTER_DOWNSAMPLING_FRAME_RATES
|
| 337 |
):
|
| 338 |
"""Create visualization plot"""
|
| 339 |
+
# Assume ID_TO_LABEL mapping exists
|
| 340 |
try:
|
| 341 |
from dataset.label2id import ID_TO_LABEL
|
| 342 |
except:
|
|
|
|
| 432 |
return result
|
| 433 |
|
| 434 |
|
| 435 |
+
def analyze_one(audio_file, out_dir, stem=None):
|
| 436 |
+
"""Run the full per-file analysis pipeline and write export files.
|
| 437 |
+
|
| 438 |
+
Shared by the single-file and batch handlers so the two paths cannot
|
| 439 |
+
drift. Returns (segments, json_str, msa_str, fig, export_paths). The
|
| 440 |
+
caller owns the returned figure (single-file displays it via gr.Plot;
|
| 441 |
+
batch saves+closes it); on a write failure the figure is closed here
|
| 442 |
+
before re-raising so it never leaks.
|
| 443 |
+
"""
|
| 444 |
+
logits, msa_output = process_audio(audio_file)
|
| 445 |
+
# Apply rule-based post-processing, if not needed, use in cli infer
|
| 446 |
+
msa_output = rule_post_processing(msa_output)
|
| 447 |
+
segments = format_as_segments(msa_output)
|
| 448 |
+
msa_str = format_as_msa(msa_output)
|
| 449 |
+
json_str = format_as_json(segments)
|
| 450 |
+
fig = create_visualization(logits, msa_output)
|
| 451 |
+
try:
|
| 452 |
+
export_paths = export_utils.write_exports(
|
| 453 |
+
audio_file, segments, json_str, msa_str, fig, out_dir, stem=stem
|
| 454 |
+
)
|
| 455 |
+
except Exception:
|
| 456 |
+
plt.close(fig)
|
| 457 |
+
raise
|
| 458 |
+
return segments, json_str, msa_str, fig, export_paths
|
| 459 |
+
|
| 460 |
+
|
| 461 |
def process_and_analyze(audio_file):
|
| 462 |
"""Main processing function"""
|
| 463 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
if audio_file is None:
|
| 465 |
+
return None, "", "", None, None, None, None, None, None
|
| 466 |
|
| 467 |
try:
|
| 468 |
+
# Shared pipeline; exports land in a fresh per-run temp directory
|
| 469 |
+
# (stale runs are swept automatically by the bootstrap).
|
| 470 |
+
out_dir = export_utils.new_run_dir()
|
| 471 |
+
segments, json_format, msa_format, fig, export_paths = analyze_one(
|
| 472 |
+
audio_file, out_dir
|
| 473 |
+
)
|
|
|
|
|
|
|
| 474 |
|
| 475 |
# Create table data
|
| 476 |
+
table_data = export_utils.segments_to_table(segments)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
|
| 478 |
+
zip_path = os.path.join(
|
| 479 |
+
out_dir, export_utils.stem_of(audio_file) + "_songformer.zip"
|
| 480 |
+
)
|
| 481 |
+
export_utils.make_zip(list(export_paths.values()), zip_path)
|
| 482 |
+
|
| 483 |
+
return (
|
| 484 |
+
table_data,
|
| 485 |
+
json_format,
|
| 486 |
+
msa_format,
|
| 487 |
+
fig,
|
| 488 |
+
export_paths["json"],
|
| 489 |
+
export_paths["msa"],
|
| 490 |
+
export_paths["csv"],
|
| 491 |
+
export_paths["png"],
|
| 492 |
+
zip_path,
|
| 493 |
+
)
|
| 494 |
|
| 495 |
except Exception as e:
|
| 496 |
import traceback
|
| 497 |
|
| 498 |
error_msg = f"Error: {str(e)}\n{traceback.format_exc()}"
|
| 499 |
+
print(error_msg) # 在命令行输出完整错误
|
| 500 |
+
return None, "", error_msg, None, None, None, None, None, None
|
| 501 |
+
|
| 502 |
+
|
| 503 |
+
def process_batch(files):
|
| 504 |
+
"""Analyze multiple files sequentially, yielding live status.
|
| 505 |
+
|
| 506 |
+
The status table itself is the progress display: every file is listed
|
| 507 |
+
as queued upfront, flips to processing, then to done/failed. Dropdown
|
| 508 |
+
choices update as files finish so completed results can be inspected
|
| 509 |
+
while the rest of the batch is still running.
|
| 510 |
+
|
| 511 |
+
Outputs (per yield): status rows, ZIP download update, file-selector
|
| 512 |
+
update, per-file results dict (for the detail viewer).
|
| 513 |
+
"""
|
| 514 |
+
if not files:
|
| 515 |
+
yield (
|
| 516 |
+
[["(no files uploaded)", "", "", ""]],
|
| 517 |
+
gr.update(value=None),
|
| 518 |
+
gr.update(choices=[], value=None),
|
| 519 |
+
{},
|
| 520 |
+
)
|
| 521 |
+
return
|
| 522 |
+
|
| 523 |
+
run_dir = export_utils.new_run_dir()
|
| 524 |
+
bundle = os.path.join(run_dir, "bundle")
|
| 525 |
+
os.makedirs(bundle, exist_ok=True)
|
| 526 |
+
|
| 527 |
+
# De-duplicate stems upfront so same-named uploads don't overwrite each
|
| 528 |
+
# other and the queued list shows the final names.
|
| 529 |
+
used_stems = set()
|
| 530 |
+
queue = []
|
| 531 |
+
for audio_file in files:
|
| 532 |
+
base = export_utils.stem_of(audio_file)
|
| 533 |
+
stem = base
|
| 534 |
+
n = 2
|
| 535 |
+
while stem in used_stems:
|
| 536 |
+
stem = f"{base}_{n}"
|
| 537 |
+
n += 1
|
| 538 |
+
used_stems.add(stem)
|
| 539 |
+
queue.append((audio_file, stem))
|
| 540 |
+
|
| 541 |
+
status_rows = [[stem, "⏳ queued", "", ""] for _, stem in queue]
|
| 542 |
+
results = {}
|
| 543 |
+
zipped_count = 0 # how many files the on-disk ZIP actually contains
|
| 544 |
+
zip_path = os.path.join(run_dir, "songformer_batch.zip")
|
| 545 |
+
|
| 546 |
+
def _rebuild_bundle_zip():
|
| 547 |
+
"""Rewrite manifests and atomically swap in an updated ZIP.
|
| 548 |
+
|
| 549 |
+
Called after each completed file so the download button always
|
| 550 |
+
serves "everything so far". os.replace is atomic, so a click can
|
| 551 |
+
never observe a half-written archive. The (stem, segments) pairs
|
| 552 |
+
are derived from `results` — the single source of truth.
|
| 553 |
+
"""
|
| 554 |
+
named = [(s, r["segments"]) for s, r in results.items()]
|
| 555 |
+
with open(
|
| 556 |
+
os.path.join(bundle, "summary.csv"), "w", encoding="utf-8", newline=""
|
| 557 |
+
) as f:
|
| 558 |
+
f.write(export_utils.segments_to_combined_csv(named))
|
| 559 |
+
with open(
|
| 560 |
+
os.path.join(bundle, "combined.json"), "w", encoding="utf-8"
|
| 561 |
+
) as f:
|
| 562 |
+
f.write(export_utils.combined_json(named))
|
| 563 |
+
part = zip_path + ".part"
|
| 564 |
+
export_utils.zip_dir(bundle, part)
|
| 565 |
+
os.replace(part, zip_path)
|
| 566 |
+
|
| 567 |
+
# List every file as queued; clear any previous run's results
|
| 568 |
+
yield (
|
| 569 |
+
status_rows,
|
| 570 |
+
gr.update(value=None, interactive=False, label="⬇️ Download all (ZIP)"),
|
| 571 |
+
gr.update(choices=[], value=None),
|
| 572 |
+
{},
|
| 573 |
+
)
|
| 574 |
+
|
| 575 |
+
for idx, (audio_file, stem) in enumerate(queue):
|
| 576 |
+
status_rows[idx] = [stem, "🔄 processing…", "", ""]
|
| 577 |
+
yield status_rows, gr.update(), gr.update(), results
|
| 578 |
+
try:
|
| 579 |
+
file_dir = os.path.join(bundle, stem)
|
| 580 |
+
os.makedirs(file_dir, exist_ok=True)
|
| 581 |
+
segments, json_str, msa_str, fig, paths = analyze_one(
|
| 582 |
+
audio_file, file_dir, stem=stem
|
| 583 |
+
)
|
| 584 |
+
plt.close(fig)
|
| 585 |
+
duration = (
|
| 586 |
+
export_utils.format_time(float(segments[-1]["end"]))
|
| 587 |
+
if segments
|
| 588 |
+
else ""
|
| 589 |
+
)
|
| 590 |
+
status_rows[idx] = [stem, "✅", len(segments), duration]
|
| 591 |
+
results[stem] = {
|
| 592 |
+
"segments": segments,
|
| 593 |
+
"json": json_str,
|
| 594 |
+
"msa": msa_str,
|
| 595 |
+
"png": paths["png"],
|
| 596 |
+
"audio": audio_file,
|
| 597 |
+
}
|
| 598 |
+
except Exception as e:
|
| 599 |
+
import traceback
|
| 600 |
+
|
| 601 |
+
print(f"Batch error for {stem}:\n{traceback.format_exc()}")
|
| 602 |
+
status_rows[idx] = [stem, "❌ " + str(e)[:80], 0, ""]
|
| 603 |
+
# ZeroGPU quota exhausted: every remaining file would fail the
|
| 604 |
+
# same way, so skip them. (Message heuristic — ZeroGPU does not
|
| 605 |
+
# document a stable exception class.)
|
| 606 |
+
if "quota" in str(e).lower():
|
| 607 |
+
for j in range(idx + 1, len(queue)):
|
| 608 |
+
status_rows[j] = [queue[j][1], "⏭️ skipped (GPU quota)", "", ""]
|
| 609 |
+
yield (
|
| 610 |
+
status_rows,
|
| 611 |
+
gr.update(),
|
| 612 |
+
gr.update(choices=list(results.keys())),
|
| 613 |
+
results,
|
| 614 |
+
)
|
| 615 |
+
break
|
| 616 |
+
else:
|
| 617 |
+
# A ZIP rebuild failure must NOT mark the analyzed file as
|
| 618 |
+
# failed: its exports exist and the next successful rebuild
|
| 619 |
+
# will include it (pairs derive from `results`).
|
| 620 |
+
try:
|
| 621 |
+
# Keep the ZIP downloadable mid-run with everything so far
|
| 622 |
+
_rebuild_bundle_zip()
|
| 623 |
+
zipped_count = len(results)
|
| 624 |
+
except Exception:
|
| 625 |
+
import traceback
|
| 626 |
+
|
| 627 |
+
print(f"ZIP rebuild error after {stem}:\n{traceback.format_exc()}")
|
| 628 |
+
if zipped_count:
|
| 629 |
+
zip_update = gr.update(
|
| 630 |
+
value=zip_path,
|
| 631 |
+
interactive=True,
|
| 632 |
+
label=f"⬇️ Download all (ZIP) — {zipped_count}/{len(queue)} files",
|
| 633 |
+
)
|
| 634 |
+
else:
|
| 635 |
+
zip_update = gr.update()
|
| 636 |
+
# Completed files become inspectable while the batch continues
|
| 637 |
+
yield status_rows, zip_update, gr.update(choices=list(results.keys())), results
|
| 638 |
+
|
| 639 |
+
# Manifests + ZIP were rebuilt incrementally per file; just normalize
|
| 640 |
+
# the button label now that the batch is complete. The button is only
|
| 641 |
+
# active if at least one rebuild actually produced a ZIP on disk.
|
| 642 |
+
yield (
|
| 643 |
+
status_rows,
|
| 644 |
+
gr.update(
|
| 645 |
+
value=zip_path if zipped_count else None,
|
| 646 |
+
interactive=bool(zipped_count),
|
| 647 |
+
label="⬇️ Download all (ZIP)",
|
| 648 |
+
),
|
| 649 |
+
gr.update(choices=list(results.keys())),
|
| 650 |
+
results,
|
| 651 |
+
)
|
| 652 |
+
|
| 653 |
+
|
| 654 |
+
def on_select_file(stem, results):
|
| 655 |
+
"""Render a previously-computed file's result in the batch detail viewer."""
|
| 656 |
+
# A selection can race an in-flight batch iteration under rare scheduler
|
| 657 |
+
# timings (choices reach the browser just before the state lands); the
|
| 658 |
+
# guard degrades to an empty view, recoverable by re-selecting.
|
| 659 |
+
results = results or {}
|
| 660 |
+
if not stem or stem not in results:
|
| 661 |
+
return None, "", "", None, None
|
| 662 |
+
r = results[stem]
|
| 663 |
+
return (
|
| 664 |
+
export_utils.segments_to_table(r["segments"]),
|
| 665 |
+
r["json"],
|
| 666 |
+
r["msa"],
|
| 667 |
+
r["png"],
|
| 668 |
+
r.get("audio"),
|
| 669 |
+
)
|
| 670 |
|
| 671 |
|
| 672 |
# Create Gradio interface
|
|
|
|
| 708 |
# Links
|
| 709 |
gr.HTML("""
|
| 710 |
<div class="links-container">
|
| 711 |
+
<img src="https://img.shields.io/badge/Python-3.10-brightgreen" alt="Python">
|
| 712 |
+
<img src="https://img.shields.io/badge/License-CC%20BY%204.0-lightblue" alt="License">
|
| 713 |
+
<a href="https://arxiv.org/abs/2510.02797">
|
| 714 |
+
<img src="https://img.shields.io/badge/arXiv-2510.02797-blue" alt="arXiv">
|
| 715 |
+
</a>
|
| 716 |
+
<a href="https://github.com/ASLP-lab/SongFormer">
|
| 717 |
+
<img src="https://img.shields.io/badge/GitHub-SongFormer-black" alt="GitHub">
|
| 718 |
+
</a>
|
| 719 |
+
<a href="https://huggingface.co/spaces/SidSaxena/SongFormer">
|
| 720 |
+
<img src="https://img.shields.io/badge/HuggingFace-space-yellow" alt="HuggingFace Space">
|
| 721 |
+
</a>
|
| 722 |
+
<a href="https://huggingface.co/ASLP-lab/SongFormer">
|
| 723 |
+
<img src="https://img.shields.io/badge/HuggingFace-model-blue" alt="HuggingFace Model">
|
| 724 |
+
</a>
|
| 725 |
+
<a href="https://huggingface.co/datasets/ASLP-lab/SongFormDB">
|
| 726 |
+
<img src="https://img.shields.io/badge/HF%20Dataset-SongFormDB-green" alt="Dataset SongFormDB">
|
| 727 |
+
</a>
|
| 728 |
+
<a href="https://huggingface.co/datasets/ASLP-lab/SongFormBench">
|
| 729 |
+
<img src="https://img.shields.io/badge/HF%20Dataset-SongFormBench-orange" alt="Dataset SongFormBench">
|
| 730 |
+
</a>
|
| 731 |
+
<a href="https://discord.gg/p5uBryC4Zs">
|
| 732 |
+
<img src="https://img.shields.io/badge/Discord-join%20us-purple?logo=discord&logoColor=white" alt="Discord">
|
| 733 |
+
</a>
|
| 734 |
+
<a href="http://www.npu-aslp.org/">
|
| 735 |
+
<img src="https://img.shields.io/badge/🏫-ASLP-grey?labelColor=lightgrey" alt="ASLP">
|
| 736 |
+
</a>
|
| 737 |
</div>
|
| 738 |
""")
|
| 739 |
|
| 740 |
+
with gr.Tabs():
|
| 741 |
+
with gr.Tab("Single File"):
|
| 742 |
+
# Main input area
|
| 743 |
+
with gr.Row():
|
| 744 |
+
with gr.Column(scale=3):
|
| 745 |
+
audio_input = gr.Audio(
|
| 746 |
+
label="Upload Audio File", type="filepath", elem_id="audio-input"
|
| 747 |
+
)
|
| 748 |
|
| 749 |
+
with gr.Column(scale=1):
|
| 750 |
+
gr.Markdown("### 📌 Examples")
|
| 751 |
+
gr.Examples(
|
| 752 |
+
examples=[
|
| 753 |
+
["examples/BC_5cd6a6.mp3"],
|
| 754 |
+
["examples/BC_282ece.mp3"],
|
| 755 |
+
["examples/BHX_0158_letitrock.wav"],
|
| 756 |
+
["examples/BHX_0374_drunkonyou.wav"],
|
| 757 |
+
],
|
| 758 |
+
inputs=[audio_input],
|
| 759 |
+
label="Click to load example",
|
| 760 |
+
)
|
| 761 |
|
| 762 |
+
# Analyze button
|
| 763 |
+
with gr.Row():
|
| 764 |
+
analyze_btn = gr.Button(
|
| 765 |
+
"🚀 Analyze Music Structure", variant="primary", scale=1
|
| 766 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
|
| 768 |
+
# Results display area
|
| 769 |
+
with gr.Row():
|
| 770 |
+
with gr.Column(scale=13):
|
| 771 |
+
segments_table = gr.Dataframe(
|
| 772 |
+
headers=["Start / s (m:s.ms)", "End / s (m:s.ms)", "Label"],
|
| 773 |
+
label="Detected Music Segments",
|
| 774 |
+
interactive=False,
|
| 775 |
+
elem_id="result-table",
|
| 776 |
+
)
|
| 777 |
+
with gr.Column(scale=8):
|
| 778 |
+
with gr.Row():
|
| 779 |
+
with gr.Accordion("📄 JSON Output", open=False):
|
| 780 |
+
json_output = gr.Textbox(
|
| 781 |
+
label="JSON Format",
|
| 782 |
+
lines=15,
|
| 783 |
+
max_lines=20,
|
| 784 |
+
interactive=False,
|
| 785 |
+
show_copy_button=True,
|
| 786 |
+
)
|
| 787 |
+
with gr.Row():
|
| 788 |
+
with gr.Accordion("📋 MSA Text Output", open=False):
|
| 789 |
+
msa_output = gr.Textbox(
|
| 790 |
+
label="MSA Format",
|
| 791 |
+
lines=15,
|
| 792 |
+
max_lines=20,
|
| 793 |
+
interactive=False,
|
| 794 |
+
show_copy_button=True,
|
| 795 |
+
)
|
| 796 |
+
|
| 797 |
+
# Visualization plot
|
| 798 |
+
with gr.Row():
|
| 799 |
+
plot_output = gr.Plot(label="Activation Curves Visualization")
|
| 800 |
|
| 801 |
+
# Export / download buttons (populated after analysis)
|
| 802 |
+
with gr.Row():
|
| 803 |
+
download_json_btn = gr.DownloadButton("⬇️ JSON")
|
| 804 |
+
download_msa_btn = gr.DownloadButton("⬇️ MSA (.txt)")
|
| 805 |
+
download_csv_btn = gr.DownloadButton("⬇️ CSV")
|
| 806 |
+
download_png_btn = gr.DownloadButton("⬇️ Plot (.png)")
|
| 807 |
+
download_zip_btn = gr.DownloadButton(
|
| 808 |
+
"⬇️ Download all (ZIP)", variant="primary"
|
| 809 |
+
)
|
| 810 |
+
|
| 811 |
+
with gr.Tab("Batch"):
|
| 812 |
+
gr.Markdown(
|
| 813 |
+
"Upload multiple audio files, analyze them sequentially, "
|
| 814 |
+
"and download all results as a single ZIP.\n\n"
|
| 815 |
+
"*This Space runs on ZeroGPU: each file consumes your daily "
|
| 816 |
+
"GPU quota (2–40 min depending on account tier). The ZIP "
|
| 817 |
+
"below always contains everything analyzed so far.*"
|
| 818 |
)
|
|
|
|
| 819 |
with gr.Row():
|
| 820 |
+
with gr.Column(scale=3):
|
| 821 |
+
batch_files = gr.File(
|
| 822 |
+
label="Upload Audio Files",
|
| 823 |
+
file_count="multiple",
|
| 824 |
+
type="filepath",
|
|
|
|
|
|
|
| 825 |
)
|
| 826 |
+
with gr.Column(scale=1):
|
| 827 |
+
batch_analyze_btn = gr.Button(
|
| 828 |
+
"🚀 Analyze Batch", variant="primary"
|
| 829 |
+
)
|
| 830 |
+
batch_zip_btn = gr.DownloadButton(
|
| 831 |
+
"⬇️ Download all (ZIP)", variant="primary", interactive=False
|
| 832 |
+
)
|
| 833 |
+
with gr.Row():
|
| 834 |
+
batch_status = gr.Dataframe(
|
| 835 |
+
headers=["File", "Status", "Segments", "Duration"],
|
| 836 |
+
label="Batch Status",
|
| 837 |
+
interactive=False,
|
| 838 |
+
)
|
| 839 |
+
batch_results_state = gr.State({})
|
| 840 |
+
gr.Markdown("### Inspect a file")
|
| 841 |
with gr.Row():
|
| 842 |
+
with gr.Column(scale=1):
|
| 843 |
+
batch_file_selector = gr.Dropdown(
|
| 844 |
+
label="Processed File", choices=[], interactive=True
|
| 845 |
+
)
|
| 846 |
+
with gr.Column(scale=2):
|
| 847 |
+
batch_detail_audio = gr.Audio(
|
| 848 |
+
label="Listen", type="filepath", interactive=False
|
| 849 |
+
)
|
| 850 |
+
with gr.Row():
|
| 851 |
+
with gr.Column(scale=13):
|
| 852 |
+
batch_detail_table = gr.Dataframe(
|
| 853 |
+
headers=["Start / s (m:s.ms)", "End / s (m:s.ms)", "Label"],
|
| 854 |
+
label="Detected Music Segments",
|
| 855 |
interactive=False,
|
|
|
|
| 856 |
)
|
| 857 |
+
with gr.Column(scale=8):
|
| 858 |
+
with gr.Row():
|
| 859 |
+
with gr.Accordion("📄 JSON Output", open=False):
|
| 860 |
+
batch_detail_json = gr.Textbox(
|
| 861 |
+
label="JSON Format",
|
| 862 |
+
lines=15,
|
| 863 |
+
max_lines=20,
|
| 864 |
+
interactive=False,
|
| 865 |
+
show_copy_button=True,
|
| 866 |
+
)
|
| 867 |
+
with gr.Row():
|
| 868 |
+
with gr.Accordion("📋 MSA Text Output", open=False):
|
| 869 |
+
batch_detail_msa = gr.Textbox(
|
| 870 |
+
label="MSA Format",
|
| 871 |
+
lines=15,
|
| 872 |
+
max_lines=20,
|
| 873 |
+
interactive=False,
|
| 874 |
+
show_copy_button=True,
|
| 875 |
+
)
|
| 876 |
+
with gr.Row():
|
| 877 |
+
batch_detail_plot = gr.Image(label="Activation Curves Visualization")
|
| 878 |
|
| 879 |
gr.HTML("""
|
| 880 |
<div style="display: flex; justify-content: center; align-items: center;">
|
|
|
|
| 886 |
analyze_btn.click(
|
| 887 |
fn=process_and_analyze,
|
| 888 |
inputs=[audio_input],
|
| 889 |
+
outputs=[
|
| 890 |
+
segments_table,
|
| 891 |
+
json_output,
|
| 892 |
+
msa_output,
|
| 893 |
+
plot_output,
|
| 894 |
+
download_json_btn,
|
| 895 |
+
download_msa_btn,
|
| 896 |
+
download_csv_btn,
|
| 897 |
+
download_png_btn,
|
| 898 |
+
download_zip_btn,
|
| 899 |
+
],
|
| 900 |
+
)
|
| 901 |
+
batch_analyze_btn.click(
|
| 902 |
+
fn=process_batch,
|
| 903 |
+
inputs=[batch_files],
|
| 904 |
+
outputs=[
|
| 905 |
+
batch_status,
|
| 906 |
+
batch_zip_btn,
|
| 907 |
+
batch_file_selector,
|
| 908 |
+
batch_results_state,
|
| 909 |
+
],
|
| 910 |
+
show_progress="minimal",
|
| 911 |
+
)
|
| 912 |
+
batch_file_selector.change(
|
| 913 |
+
fn=on_select_file,
|
| 914 |
+
inputs=[batch_file_selector, batch_results_state],
|
| 915 |
+
outputs=[
|
| 916 |
+
batch_detail_table,
|
| 917 |
+
batch_detail_json,
|
| 918 |
+
batch_detail_msa,
|
| 919 |
+
batch_detail_plot,
|
| 920 |
+
batch_detail_audio,
|
| 921 |
+
],
|
| 922 |
)
|
| 923 |
|
| 924 |
if __name__ == "__main__":
|
|
|
|
| 933 |
)
|
| 934 |
print("Models loaded successfully!")
|
| 935 |
|
| 936 |
+
# Launch interface (Spaces injects its own server settings; an explicit
|
| 937 |
+
# port would break the platform health check)
|
| 938 |
demo.launch()
|
export_utils.py
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Serialize SongFormer analysis results to downloadable files.
|
| 2 |
+
|
| 3 |
+
Pure, UI-agnostic helpers used by app.py. No model or Gradio imports, so
|
| 4 |
+
these can be unit-tested without loading any checkpoint.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import csv
|
| 8 |
+
import io
|
| 9 |
+
import json
|
| 10 |
+
import os
|
| 11 |
+
import shutil
|
| 12 |
+
import tempfile
|
| 13 |
+
import time
|
| 14 |
+
import zipfile
|
| 15 |
+
|
| 16 |
+
# Per-run export directories older than this (seconds) are swept at the start
|
| 17 |
+
# of each analysis. Recent runs are kept so their download files stay servable.
|
| 18 |
+
DEFAULT_EXPORT_TTL_SECONDS = 3600
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def format_time(t: float) -> str:
|
| 22 |
+
"""Render seconds as mm:ss.mmm (e.g. 61.5 -> '01:01.500')."""
|
| 23 |
+
minutes = int(t // 60)
|
| 24 |
+
seconds = t % 60
|
| 25 |
+
return f"{minutes:02d}:{seconds:06.3f}"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def stem_of(audio_path: str) -> str:
|
| 29 |
+
"""Return the audio filename without directory or extension."""
|
| 30 |
+
return os.path.splitext(os.path.basename(audio_path))[0]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def segments_to_table(segments) -> list:
|
| 34 |
+
"""Build display table rows: [start "(mm:ss.mmm)", end "(mm:ss.mmm)", label]."""
|
| 35 |
+
rows = []
|
| 36 |
+
for seg in segments:
|
| 37 |
+
start = float(seg["start"])
|
| 38 |
+
end = float(seg["end"])
|
| 39 |
+
rows.append(
|
| 40 |
+
[
|
| 41 |
+
f"{start:.2f} ({format_time(start)})",
|
| 42 |
+
f"{end:.2f} ({format_time(end)})",
|
| 43 |
+
seg["label"],
|
| 44 |
+
]
|
| 45 |
+
)
|
| 46 |
+
return rows
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def segments_to_csv(segments) -> str:
|
| 50 |
+
"""Build CSV text from segment dicts.
|
| 51 |
+
|
| 52 |
+
Each segment is {"start": str|float, "end": str|float, "label": str}.
|
| 53 |
+
Columns: start_sec, start_mmss, end_sec, end_mmss, label.
|
| 54 |
+
"""
|
| 55 |
+
buf = io.StringIO()
|
| 56 |
+
writer = csv.writer(buf, lineterminator="\n")
|
| 57 |
+
writer.writerow(["start_sec", "start_mmss", "end_sec", "end_mmss", "label"])
|
| 58 |
+
for seg in segments:
|
| 59 |
+
start = float(seg["start"])
|
| 60 |
+
end = float(seg["end"])
|
| 61 |
+
writer.writerow(
|
| 62 |
+
[
|
| 63 |
+
f"{start:.2f}",
|
| 64 |
+
format_time(start),
|
| 65 |
+
f"{end:.2f}",
|
| 66 |
+
format_time(end),
|
| 67 |
+
seg["label"],
|
| 68 |
+
]
|
| 69 |
+
)
|
| 70 |
+
return buf.getvalue()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def segments_to_combined_csv(named) -> str:
|
| 74 |
+
"""Build a combined CSV across files.
|
| 75 |
+
|
| 76 |
+
`named` is a list of (filename, segments). Columns:
|
| 77 |
+
filename, start_sec, start_mmss, end_sec, end_mmss, label.
|
| 78 |
+
"""
|
| 79 |
+
buf = io.StringIO()
|
| 80 |
+
writer = csv.writer(buf, lineterminator="\n")
|
| 81 |
+
writer.writerow(
|
| 82 |
+
["filename", "start_sec", "start_mmss", "end_sec", "end_mmss", "label"]
|
| 83 |
+
)
|
| 84 |
+
for filename, segments in named:
|
| 85 |
+
for seg in segments:
|
| 86 |
+
start = float(seg["start"])
|
| 87 |
+
end = float(seg["end"])
|
| 88 |
+
writer.writerow(
|
| 89 |
+
[
|
| 90 |
+
filename,
|
| 91 |
+
f"{start:.2f}",
|
| 92 |
+
format_time(start),
|
| 93 |
+
f"{end:.2f}",
|
| 94 |
+
format_time(end),
|
| 95 |
+
seg["label"],
|
| 96 |
+
]
|
| 97 |
+
)
|
| 98 |
+
return buf.getvalue()
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def combined_json(named) -> str:
|
| 102 |
+
"""Build a combined JSON mapping {filename: segments} across files."""
|
| 103 |
+
return json.dumps(
|
| 104 |
+
{filename: segments for filename, segments in named},
|
| 105 |
+
indent=2,
|
| 106 |
+
ensure_ascii=False,
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def write_exports(audio_path, segments, json_str, msa_str, fig, out_dir, stem=None) -> dict:
|
| 111 |
+
"""Write json/msa/csv/png into out_dir; return {format: path}.
|
| 112 |
+
|
| 113 |
+
Reuses the already-built json_str/msa_str from app.py rather than
|
| 114 |
+
re-serializing. Saves the matplotlib figure as PNG. `stem` overrides the
|
| 115 |
+
filename stem (used by batch to keep de-duplicated folder and file names
|
| 116 |
+
consistent); defaults to the audio filename's stem.
|
| 117 |
+
"""
|
| 118 |
+
if stem is None:
|
| 119 |
+
stem = stem_of(audio_path)
|
| 120 |
+
paths = {
|
| 121 |
+
"json": os.path.join(out_dir, f"{stem}.json"),
|
| 122 |
+
"msa": os.path.join(out_dir, f"{stem}.msa.txt"),
|
| 123 |
+
"csv": os.path.join(out_dir, f"{stem}.csv"),
|
| 124 |
+
"png": os.path.join(out_dir, f"{stem}.png"),
|
| 125 |
+
}
|
| 126 |
+
with open(paths["json"], "w", encoding="utf-8") as f:
|
| 127 |
+
f.write(json_str)
|
| 128 |
+
with open(paths["msa"], "w", encoding="utf-8") as f:
|
| 129 |
+
f.write(msa_str)
|
| 130 |
+
with open(paths["csv"], "w", encoding="utf-8", newline="") as f:
|
| 131 |
+
f.write(segments_to_csv(segments))
|
| 132 |
+
fig.savefig(paths["png"], dpi=150, bbox_inches="tight")
|
| 133 |
+
return paths
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def make_zip(paths, zip_path) -> str:
|
| 137 |
+
"""Bundle the given files into zip_path using their basenames.
|
| 138 |
+
|
| 139 |
+
Returns zip_path.
|
| 140 |
+
"""
|
| 141 |
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
| 142 |
+
for p in paths:
|
| 143 |
+
zf.write(p, arcname=os.path.basename(p))
|
| 144 |
+
return zip_path
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
# File types that are already compressed: deflating them again wastes CPU
|
| 148 |
+
# (which matters because the batch ZIP is rebuilt incrementally per file).
|
| 149 |
+
_STORED_EXTENSIONS = {".png", ".jpg", ".jpeg", ".zip", ".mp3", ".flac", ".ogg"}
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def zip_dir(src_dir, zip_path) -> str:
|
| 153 |
+
"""Zip the contents of src_dir into zip_path.
|
| 154 |
+
|
| 155 |
+
Arcnames are relative to src_dir, preserving subfolders. Files that are
|
| 156 |
+
already compressed (see _STORED_EXTENSIONS) are stored uncompressed.
|
| 157 |
+
Returns zip_path.
|
| 158 |
+
"""
|
| 159 |
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
| 160 |
+
for root, _dirs, files in os.walk(src_dir):
|
| 161 |
+
for name in files:
|
| 162 |
+
full = os.path.join(root, name)
|
| 163 |
+
arcname = os.path.relpath(full, src_dir)
|
| 164 |
+
compress = (
|
| 165 |
+
zipfile.ZIP_STORED
|
| 166 |
+
if os.path.splitext(name)[1].lower() in _STORED_EXTENSIONS
|
| 167 |
+
else zipfile.ZIP_DEFLATED
|
| 168 |
+
)
|
| 169 |
+
zf.write(full, arcname=arcname, compress_type=compress)
|
| 170 |
+
return zip_path
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def cleanup_old_exports(parent_dir, max_age_seconds, now=None) -> list:
|
| 174 |
+
"""Remove run subdirectories of parent_dir older than max_age_seconds.
|
| 175 |
+
|
| 176 |
+
Only directories are swept (stray files are left alone). A missing
|
| 177 |
+
parent_dir is a no-op. Recent runs are preserved so their download files
|
| 178 |
+
remain servable. Returns the list of removed directory paths.
|
| 179 |
+
"""
|
| 180 |
+
if now is None:
|
| 181 |
+
now = time.time()
|
| 182 |
+
removed = []
|
| 183 |
+
if not os.path.isdir(parent_dir):
|
| 184 |
+
return removed
|
| 185 |
+
cutoff = now - max_age_seconds
|
| 186 |
+
for name in sorted(os.listdir(parent_dir)):
|
| 187 |
+
path = os.path.join(parent_dir, name)
|
| 188 |
+
if not os.path.isdir(path):
|
| 189 |
+
continue
|
| 190 |
+
if os.path.getmtime(path) < cutoff:
|
| 191 |
+
shutil.rmtree(path, ignore_errors=True)
|
| 192 |
+
removed.append(path)
|
| 193 |
+
return removed
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def new_run_dir(parent_dir=None, ttl_seconds=DEFAULT_EXPORT_TTL_SECONDS) -> str:
|
| 197 |
+
"""Create a fresh run directory for export files, sweeping stale runs.
|
| 198 |
+
|
| 199 |
+
Shared bootstrap for the single-file and batch handlers. parent_dir
|
| 200 |
+
defaults to <system tempdir>/songformer_exports.
|
| 201 |
+
"""
|
| 202 |
+
if parent_dir is None:
|
| 203 |
+
parent_dir = os.path.join(tempfile.gettempdir(), "songformer_exports")
|
| 204 |
+
os.makedirs(parent_dir, exist_ok=True)
|
| 205 |
+
cleanup_old_exports(parent_dir, ttl_seconds)
|
| 206 |
+
return tempfile.mkdtemp(prefix="run_", dir=parent_dir)
|
src/SongFormer/infer.sh
CHANGED
|
@@ -16,6 +16,8 @@ python infer/infer.py \
|
|
| 16 |
--checkpoint SongFormer.safetensors \
|
| 17 |
--config_path SongFormer.yaml \
|
| 18 |
-gn 1 \
|
| 19 |
-
-tn 1
|
|
|
|
|
|
|
| 20 |
# --debug
|
| 21 |
# --no_rule_post_processing
|
|
|
|
| 16 |
--checkpoint SongFormer.safetensors \
|
| 17 |
--config_path SongFormer.yaml \
|
| 18 |
-gn 1 \
|
| 19 |
+
-tn 1 \
|
| 20 |
+
--save_plots \
|
| 21 |
+
--device mps
|
| 22 |
# --debug
|
| 23 |
# --no_rule_post_processing
|
src/SongFormer/infer/infer.py
CHANGED
|
@@ -22,9 +22,33 @@ from muq import MuQ
|
|
| 22 |
from musicfm.model.musicfm_25hz import MusicFM25Hz
|
| 23 |
from omegaconf import OmegaConf
|
| 24 |
from tqdm import tqdm
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
mp.set_start_method("spawn", force=True)
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
MUSICFM_HOME_PATH = os.path.join("ckpts", "MusicFM")
|
| 29 |
|
| 30 |
BEFORE_DOWNSAMPLING_FRAME_RATES = 25
|
|
@@ -36,7 +60,7 @@ DATASET_IDS = [5]
|
|
| 36 |
TIME_DUR = 420
|
| 37 |
INPUT_SAMPLING_RATE = 24000
|
| 38 |
|
| 39 |
-
from dataset.label2id import DATASET_ID_ALLOWED_LABEL_IDS, DATASET_LABEL_TO_DATASET_ID
|
| 40 |
from postprocessing.functional import postprocess_functional_structure
|
| 41 |
|
| 42 |
|
|
@@ -60,6 +84,112 @@ def get_processing_ids(input_path, processed_ids_set):
|
|
| 60 |
return ret
|
| 61 |
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
def load_checkpoint(checkpoint_path, device=None):
|
| 64 |
"""Load checkpoint from path"""
|
| 65 |
if device is None:
|
|
@@ -115,7 +245,7 @@ def rule_post_processing(msa_list):
|
|
| 115 |
|
| 116 |
def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
| 117 |
"""Run inference on the input audio"""
|
| 118 |
-
device =
|
| 119 |
|
| 120 |
# MuQ model loading (this will automatically fetch the checkpoint from huggingface)
|
| 121 |
muq = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")
|
|
@@ -199,7 +329,7 @@ def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
|
| 199 |
muq_output = muq(audio_seg.unsqueeze(0), output_hidden_states=True)
|
| 200 |
muq_embd_420s = muq_output["hidden_states"][10]
|
| 201 |
del muq_output
|
| 202 |
-
|
| 203 |
|
| 204 |
# MusicFM embedding
|
| 205 |
_, musicfm_hidden_states = musicfm.get_predictions(
|
|
@@ -207,7 +337,7 @@ def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
|
| 207 |
)
|
| 208 |
musicfm_embd_420s = musicfm_hidden_states[10]
|
| 209 |
del musicfm_hidden_states
|
| 210 |
-
|
| 211 |
|
| 212 |
wraped_muq_embd_30s = []
|
| 213 |
wraped_musicfm_embd_30s = []
|
|
@@ -229,13 +359,13 @@ def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
|
| 229 |
output_hidden_states=True,
|
| 230 |
)["hidden_states"][10]
|
| 231 |
)
|
| 232 |
-
|
| 233 |
wraped_musicfm_embd_30s.append(
|
| 234 |
musicfm.get_predictions(
|
| 235 |
audio[start_idx_30s:end_idx_30s].unsqueeze(0)
|
| 236 |
)[1][10]
|
| 237 |
)
|
| 238 |
-
|
| 239 |
|
| 240 |
wraped_muq_embd_30s = torch.concatenate(wraped_muq_embd_30s, dim=1)
|
| 241 |
wraped_musicfm_embd_30s = torch.concatenate(
|
|
@@ -326,6 +456,11 @@ def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
|
| 326 |
ensure_ascii=False,
|
| 327 |
)
|
| 328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
queue_output.put(None)
|
| 330 |
|
| 331 |
except Exception as e:
|
|
@@ -368,6 +503,8 @@ def main(args):
|
|
| 368 |
checkpoint=args.checkpoint,
|
| 369 |
config_path=args.config_path,
|
| 370 |
no_rule_post_processing=args.no_rule_post_processing,
|
|
|
|
|
|
|
| 371 |
)
|
| 372 |
|
| 373 |
processes = []
|
|
@@ -433,6 +570,12 @@ if __name__ == "__main__":
|
|
| 433 |
help="Disable rule-based post-processing",
|
| 434 |
)
|
| 435 |
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
|
| 437 |
args = parser.parse_args()
|
| 438 |
|
|
|
|
| 22 |
from musicfm.model.musicfm_25hz import MusicFM25Hz
|
| 23 |
from omegaconf import OmegaConf
|
| 24 |
from tqdm import tqdm
|
| 25 |
+
import matplotlib
|
| 26 |
+
matplotlib.use("Agg")
|
| 27 |
+
import matplotlib.pyplot as plt
|
| 28 |
+
import matplotlib.ticker as ticker
|
| 29 |
|
| 30 |
mp.set_start_method("spawn", force=True)
|
| 31 |
|
| 32 |
+
|
| 33 |
+
def get_device(device_override=None, rank=0):
|
| 34 |
+
"""Select the best available device: MPS (Apple Silicon), CUDA, or CPU."""
|
| 35 |
+
if device_override:
|
| 36 |
+
return torch.device(device_override)
|
| 37 |
+
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
| 38 |
+
return torch.device("mps")
|
| 39 |
+
if torch.cuda.is_available():
|
| 40 |
+
return torch.device(f"cuda:{rank}")
|
| 41 |
+
return torch.device("cpu")
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def clear_device_cache(device):
|
| 45 |
+
"""Clear GPU memory cache for the given device type."""
|
| 46 |
+
if device.type == "cuda":
|
| 47 |
+
torch.cuda.empty_cache()
|
| 48 |
+
elif device.type == "mps":
|
| 49 |
+
torch.mps.empty_cache()
|
| 50 |
+
|
| 51 |
+
|
| 52 |
MUSICFM_HOME_PATH = os.path.join("ckpts", "MusicFM")
|
| 53 |
|
| 54 |
BEFORE_DOWNSAMPLING_FRAME_RATES = 25
|
|
|
|
| 60 |
TIME_DUR = 420
|
| 61 |
INPUT_SAMPLING_RATE = 24000
|
| 62 |
|
| 63 |
+
from dataset.label2id import DATASET_ID_ALLOWED_LABEL_IDS, DATASET_LABEL_TO_DATASET_ID, ID_TO_LABEL
|
| 64 |
from postprocessing.functional import postprocess_functional_structure
|
| 65 |
|
| 66 |
|
|
|
|
| 84 |
return ret
|
| 85 |
|
| 86 |
|
| 87 |
+
def save_visualizations(logits, msa_infer_output, data_id, output_dir, label_num=8):
|
| 88 |
+
"""Save activation visualizations (line plot PDF + heatmap PNG) and raw logits (.npy)."""
|
| 89 |
+
try:
|
| 90 |
+
function_vals = logits["function_logits"].squeeze().cpu().numpy() # [T, 128]
|
| 91 |
+
boundary_vals = logits["boundary_logits"].squeeze().cpu().numpy() # [T]
|
| 92 |
+
|
| 93 |
+
# --- Raw logits ---
|
| 94 |
+
logits_dir = os.path.join(output_dir, "logits")
|
| 95 |
+
os.makedirs(logits_dir, exist_ok=True)
|
| 96 |
+
np.save(os.path.join(logits_dir, f"{data_id}_function.npy"), function_vals)
|
| 97 |
+
np.save(os.path.join(logits_dir, f"{data_id}_boundary.npy"), boundary_vals)
|
| 98 |
+
|
| 99 |
+
# --- Plots ---
|
| 100 |
+
plots_dir = os.path.join(output_dir, "plots")
|
| 101 |
+
os.makedirs(plots_dir, exist_ok=True)
|
| 102 |
+
|
| 103 |
+
T = function_vals.shape[0]
|
| 104 |
+
time_axis = np.arange(T) / AFTER_DOWNSAMPLING_FRAME_RATES
|
| 105 |
+
top_classes = np.argsort(function_vals.mean(axis=0))[-label_num:]
|
| 106 |
+
|
| 107 |
+
# A. Line plot (PDF)
|
| 108 |
+
fig, ax = plt.subplots(2, 1, figsize=(15, 8), sharex=True)
|
| 109 |
+
|
| 110 |
+
ax[0].plot(time_axis, boundary_vals, label="Boundary logit", color="orange")
|
| 111 |
+
ax[0].set_title("Boundary logits")
|
| 112 |
+
ax[0].set_ylabel("Logit")
|
| 113 |
+
ax[0].legend()
|
| 114 |
+
ax[0].grid(True)
|
| 115 |
+
|
| 116 |
+
for cls in top_classes:
|
| 117 |
+
ax[1].plot(
|
| 118 |
+
time_axis,
|
| 119 |
+
function_vals[:, cls],
|
| 120 |
+
label=f"{ID_TO_LABEL.get(cls, f'Class_{cls}')}",
|
| 121 |
+
)
|
| 122 |
+
ax[1].set_title(f"Top {label_num} Function logits by mean activation")
|
| 123 |
+
ax[1].set_xlabel("Time (seconds)")
|
| 124 |
+
ax[1].set_ylabel("Logit")
|
| 125 |
+
ax[1].xaxis.set_major_locator(ticker.MultipleLocator(20))
|
| 126 |
+
ax[1].xaxis.set_minor_locator(ticker.MultipleLocator(5))
|
| 127 |
+
ax[1].xaxis.set_major_formatter(ticker.FormatStrFormatter("%.1f"))
|
| 128 |
+
ax[1].legend()
|
| 129 |
+
ax[1].grid(True)
|
| 130 |
+
|
| 131 |
+
for t_sec, label in msa_infer_output:
|
| 132 |
+
for a in ax:
|
| 133 |
+
a.axvline(x=t_sec, color="red", linestyle="--", linewidth=0.8)
|
| 134 |
+
if label != "end":
|
| 135 |
+
ax[1].text(
|
| 136 |
+
t_sec + 0.3,
|
| 137 |
+
ax[1].get_ylim()[1] * 0.85,
|
| 138 |
+
label,
|
| 139 |
+
rotation=90,
|
| 140 |
+
fontsize=8,
|
| 141 |
+
color="red",
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
plt.suptitle(f"{data_id} — MSA Logits Overview", fontsize=16)
|
| 145 |
+
plt.tight_layout()
|
| 146 |
+
plt.savefig(os.path.join(plots_dir, f"{data_id}.pdf"), bbox_inches="tight")
|
| 147 |
+
plt.close(fig)
|
| 148 |
+
|
| 149 |
+
# B. Heatmap (PNG)
|
| 150 |
+
fig, ax = plt.subplots(figsize=(15, 6))
|
| 151 |
+
class_labels = [ID_TO_LABEL.get(cls, f"Class_{cls}") for cls in top_classes]
|
| 152 |
+
heatmap_data = function_vals[:, top_classes] # [T, label_num]
|
| 153 |
+
|
| 154 |
+
im = ax.imshow(
|
| 155 |
+
heatmap_data.T,
|
| 156 |
+
aspect="auto",
|
| 157 |
+
origin="lower",
|
| 158 |
+
cmap="viridis",
|
| 159 |
+
extent=[time_axis[0], time_axis[-1], -0.5, label_num - 0.5],
|
| 160 |
+
)
|
| 161 |
+
ax.set_yticks(range(label_num))
|
| 162 |
+
ax.set_yticklabels(class_labels)
|
| 163 |
+
ax.set_xlabel("Time (seconds)")
|
| 164 |
+
ax.set_ylabel("Class")
|
| 165 |
+
ax.set_title(f"{data_id} — Function Logits Heatmap (Top {label_num})")
|
| 166 |
+
|
| 167 |
+
for t_sec, label in msa_infer_output:
|
| 168 |
+
ax.axvline(x=t_sec, color="white", linestyle="--", linewidth=0.8, alpha=0.7)
|
| 169 |
+
if label != "end":
|
| 170 |
+
ax.text(
|
| 171 |
+
t_sec + 0.3,
|
| 172 |
+
label_num - 0.7,
|
| 173 |
+
label,
|
| 174 |
+
rotation=90,
|
| 175 |
+
fontsize=7,
|
| 176 |
+
color="white",
|
| 177 |
+
alpha=0.9,
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
plt.colorbar(im, ax=ax, label="Logit value")
|
| 181 |
+
plt.tight_layout()
|
| 182 |
+
plt.savefig(
|
| 183 |
+
os.path.join(plots_dir, f"{data_id}_heatmap.png"),
|
| 184 |
+
dpi=150,
|
| 185 |
+
bbox_inches="tight",
|
| 186 |
+
)
|
| 187 |
+
plt.close(fig)
|
| 188 |
+
|
| 189 |
+
except Exception as e:
|
| 190 |
+
logger.error(f"Visualization failed for {data_id}: {e}")
|
| 191 |
+
|
| 192 |
+
|
| 193 |
def load_checkpoint(checkpoint_path, device=None):
|
| 194 |
"""Load checkpoint from path"""
|
| 195 |
if device is None:
|
|
|
|
| 245 |
|
| 246 |
def inference(rank, queue_input: mp.Queue, queue_output: mp.Queue, args):
|
| 247 |
"""Run inference on the input audio"""
|
| 248 |
+
device = get_device(getattr(args, 'device', None), rank)
|
| 249 |
|
| 250 |
# MuQ model loading (this will automatically fetch the checkpoint from huggingface)
|
| 251 |
muq = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")
|
|
|
|
| 329 |
muq_output = muq(audio_seg.unsqueeze(0), output_hidden_states=True)
|
| 330 |
muq_embd_420s = muq_output["hidden_states"][10]
|
| 331 |
del muq_output
|
| 332 |
+
clear_device_cache(device)
|
| 333 |
|
| 334 |
# MusicFM embedding
|
| 335 |
_, musicfm_hidden_states = musicfm.get_predictions(
|
|
|
|
| 337 |
)
|
| 338 |
musicfm_embd_420s = musicfm_hidden_states[10]
|
| 339 |
del musicfm_hidden_states
|
| 340 |
+
clear_device_cache(device)
|
| 341 |
|
| 342 |
wraped_muq_embd_30s = []
|
| 343 |
wraped_musicfm_embd_30s = []
|
|
|
|
| 359 |
output_hidden_states=True,
|
| 360 |
)["hidden_states"][10]
|
| 361 |
)
|
| 362 |
+
clear_device_cache(device)
|
| 363 |
wraped_musicfm_embd_30s.append(
|
| 364 |
musicfm.get_predictions(
|
| 365 |
audio[start_idx_30s:end_idx_30s].unsqueeze(0)
|
| 366 |
)[1][10]
|
| 367 |
)
|
| 368 |
+
clear_device_cache(device)
|
| 369 |
|
| 370 |
wraped_muq_embd_30s = torch.concatenate(wraped_muq_embd_30s, dim=1)
|
| 371 |
wraped_musicfm_embd_30s = torch.concatenate(
|
|
|
|
| 456 |
ensure_ascii=False,
|
| 457 |
)
|
| 458 |
|
| 459 |
+
if args.save_plots:
|
| 460 |
+
save_visualizations(
|
| 461 |
+
logits, msa_infer_output, Path(item).stem, args.output_dir
|
| 462 |
+
)
|
| 463 |
+
|
| 464 |
queue_output.put(None)
|
| 465 |
|
| 466 |
except Exception as e:
|
|
|
|
| 503 |
checkpoint=args.checkpoint,
|
| 504 |
config_path=args.config_path,
|
| 505 |
no_rule_post_processing=args.no_rule_post_processing,
|
| 506 |
+
device=getattr(args, 'device', None),
|
| 507 |
+
save_plots=args.save_plots,
|
| 508 |
)
|
| 509 |
|
| 510 |
processes = []
|
|
|
|
| 570 |
help="Disable rule-based post-processing",
|
| 571 |
)
|
| 572 |
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
| 573 |
+
parser.add_argument(
|
| 574 |
+
"--save_plots",
|
| 575 |
+
action="store_true",
|
| 576 |
+
help="Save activation visualizations (line plots + heatmaps) and raw logits (.npy)",
|
| 577 |
+
)
|
| 578 |
+
parser.add_argument("--device", type=str, default=None, help="Force device (mps, cuda, cpu). Auto-detected if not set.")
|
| 579 |
|
| 580 |
args = parser.parse_args()
|
| 581 |
|
src/third_party/MuQ/.gitattributes
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
# Auto detect text files and perform LF normalization
|
| 2 |
-
* text=auto
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/.gitignore
DELETED
|
@@ -1,46 +0,0 @@
|
|
| 1 |
-
# Byte-compiled / optimized / DLL files
|
| 2 |
-
__pycache__/
|
| 3 |
-
*.py[cod]
|
| 4 |
-
*$py.class
|
| 5 |
-
*.egg*/
|
| 6 |
-
*pyc
|
| 7 |
-
|
| 8 |
-
# Distribution / packaging
|
| 9 |
-
.Python
|
| 10 |
-
env/
|
| 11 |
-
build/
|
| 12 |
-
dist/
|
| 13 |
-
*.log
|
| 14 |
-
|
| 15 |
-
# pyenv
|
| 16 |
-
.python-version
|
| 17 |
-
|
| 18 |
-
# dotenv
|
| 19 |
-
.env
|
| 20 |
-
|
| 21 |
-
# virtualenv
|
| 22 |
-
.venv/
|
| 23 |
-
venv/
|
| 24 |
-
ENV/
|
| 25 |
-
|
| 26 |
-
# VSCode settings
|
| 27 |
-
.vscode
|
| 28 |
-
|
| 29 |
-
# IDEA files
|
| 30 |
-
.idea
|
| 31 |
-
|
| 32 |
-
# OSX dir files
|
| 33 |
-
.DS_Store
|
| 34 |
-
|
| 35 |
-
# Sublime Text settings
|
| 36 |
-
*.sublime-workspace
|
| 37 |
-
*.sublime-project
|
| 38 |
-
|
| 39 |
-
# custom
|
| 40 |
-
open/
|
| 41 |
-
src/recipes/pretrain/dataset/music4all/*.json
|
| 42 |
-
src/recipes/contrastive_learning/datasets/mtg-jamendo/*.json
|
| 43 |
-
runs/
|
| 44 |
-
output/
|
| 45 |
-
logs
|
| 46 |
-
outputs/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/.gitmodules
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
[submodule "src/recipes/pretrain/fairseq"]
|
| 2 |
-
path = src/recipes/pretrain/fairseq
|
| 3 |
-
url = https://github.com/facebookresearch/fairseq
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
| 1 |
-
MIT License
|
| 2 |
-
|
| 3 |
-
Copyright (c) Tencent.
|
| 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/LICENSE_weights
DELETED
|
@@ -1,399 +0,0 @@
|
|
| 1 |
-
Attribution-NonCommercial 4.0 International
|
| 2 |
-
|
| 3 |
-
=======================================================================
|
| 4 |
-
|
| 5 |
-
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
| 6 |
-
does not provide legal services or legal advice. Distribution of
|
| 7 |
-
Creative Commons public licenses does not create a lawyer-client or
|
| 8 |
-
other relationship. Creative Commons makes its licenses and related
|
| 9 |
-
information available on an "as-is" basis. Creative Commons gives no
|
| 10 |
-
warranties regarding its licenses, any material licensed under their
|
| 11 |
-
terms and conditions, or any related information. Creative Commons
|
| 12 |
-
disclaims all liability for damages resulting from their use to the
|
| 13 |
-
fullest extent possible.
|
| 14 |
-
|
| 15 |
-
Using Creative Commons Public Licenses
|
| 16 |
-
|
| 17 |
-
Creative Commons public licenses provide a standard set of terms and
|
| 18 |
-
conditions that creators and other rights holders may use to share
|
| 19 |
-
original works of authorship and other material subject to copyright
|
| 20 |
-
and certain other rights specified in the public license below. The
|
| 21 |
-
following considerations are for informational purposes only, are not
|
| 22 |
-
exhaustive, and do not form part of our licenses.
|
| 23 |
-
|
| 24 |
-
Considerations for licensors: Our public licenses are
|
| 25 |
-
intended for use by those authorized to give the public
|
| 26 |
-
permission to use material in ways otherwise restricted by
|
| 27 |
-
copyright and certain other rights. Our licenses are
|
| 28 |
-
irrevocable. Licensors should read and understand the terms
|
| 29 |
-
and conditions of the license they choose before applying it.
|
| 30 |
-
Licensors should also secure all rights necessary before
|
| 31 |
-
applying our licenses so that the public can reuse the
|
| 32 |
-
material as expected. Licensors should clearly mark any
|
| 33 |
-
material not subject to the license. This includes other CC-
|
| 34 |
-
licensed material, or material used under an exception or
|
| 35 |
-
limitation to copyright. More considerations for licensors:
|
| 36 |
-
wiki.creativecommons.org/Considerations_for_licensors
|
| 37 |
-
|
| 38 |
-
Considerations for the public: By using one of our public
|
| 39 |
-
licenses, a licensor grants the public permission to use the
|
| 40 |
-
licensed material under specified terms and conditions. If
|
| 41 |
-
the licensor's permission is not necessary for any reason--for
|
| 42 |
-
example, because of any applicable exception or limitation to
|
| 43 |
-
copyright--then that use is not regulated by the license. Our
|
| 44 |
-
licenses grant only permissions under copyright and certain
|
| 45 |
-
other rights that a licensor has authority to grant. Use of
|
| 46 |
-
the licensed material may still be restricted for other
|
| 47 |
-
reasons, including because others have copyright or other
|
| 48 |
-
rights in the material. A licensor may make special requests,
|
| 49 |
-
such as asking that all changes be marked or described.
|
| 50 |
-
Although not required by our licenses, you are encouraged to
|
| 51 |
-
respect those requests where reasonable. More_considerations
|
| 52 |
-
for the public:
|
| 53 |
-
wiki.creativecommons.org/Considerations_for_licensees
|
| 54 |
-
|
| 55 |
-
=======================================================================
|
| 56 |
-
|
| 57 |
-
Creative Commons Attribution-NonCommercial 4.0 International Public
|
| 58 |
-
License
|
| 59 |
-
|
| 60 |
-
By exercising the Licensed Rights (defined below), You accept and agree
|
| 61 |
-
to be bound by the terms and conditions of this Creative Commons
|
| 62 |
-
Attribution-NonCommercial 4.0 International Public License ("Public
|
| 63 |
-
License"). To the extent this Public License may be interpreted as a
|
| 64 |
-
contract, You are granted the Licensed Rights in consideration of Your
|
| 65 |
-
acceptance of these terms and conditions, and the Licensor grants You
|
| 66 |
-
such rights in consideration of benefits the Licensor receives from
|
| 67 |
-
making the Licensed Material available under these terms and
|
| 68 |
-
conditions.
|
| 69 |
-
|
| 70 |
-
Section 1 -- Definitions.
|
| 71 |
-
|
| 72 |
-
a. Adapted Material means material subject to Copyright and Similar
|
| 73 |
-
Rights that is derived from or based upon the Licensed Material
|
| 74 |
-
and in which the Licensed Material is translated, altered,
|
| 75 |
-
arranged, transformed, or otherwise modified in a manner requiring
|
| 76 |
-
permission under the Copyright and Similar Rights held by the
|
| 77 |
-
Licensor. For purposes of this Public License, where the Licensed
|
| 78 |
-
Material is a musical work, performance, or sound recording,
|
| 79 |
-
Adapted Material is always produced where the Licensed Material is
|
| 80 |
-
synched in timed relation with a moving image.
|
| 81 |
-
|
| 82 |
-
b. Adapter's License means the license You apply to Your Copyright
|
| 83 |
-
and Similar Rights in Your contributions to Adapted Material in
|
| 84 |
-
accordance with the terms and conditions of this Public License.
|
| 85 |
-
|
| 86 |
-
c. Copyright and Similar Rights means copyright and/or similar rights
|
| 87 |
-
closely related to copyright including, without limitation,
|
| 88 |
-
performance, broadcast, sound recording, and Sui Generis Database
|
| 89 |
-
Rights, without regard to how the rights are labeled or
|
| 90 |
-
categorized. For purposes of this Public License, the rights
|
| 91 |
-
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
| 92 |
-
Rights.
|
| 93 |
-
d. Effective Technological Measures means those measures that, in the
|
| 94 |
-
absence of proper authority, may not be circumvented under laws
|
| 95 |
-
fulfilling obligations under Article 11 of the WIPO Copyright
|
| 96 |
-
Treaty adopted on December 20, 1996, and/or similar international
|
| 97 |
-
agreements.
|
| 98 |
-
|
| 99 |
-
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
| 100 |
-
any other exception or limitation to Copyright and Similar Rights
|
| 101 |
-
that applies to Your use of the Licensed Material.
|
| 102 |
-
|
| 103 |
-
f. Licensed Material means the artistic or literary work, database,
|
| 104 |
-
or other material to which the Licensor applied this Public
|
| 105 |
-
License.
|
| 106 |
-
|
| 107 |
-
g. Licensed Rights means the rights granted to You subject to the
|
| 108 |
-
terms and conditions of this Public License, which are limited to
|
| 109 |
-
all Copyright and Similar Rights that apply to Your use of the
|
| 110 |
-
Licensed Material and that the Licensor has authority to license.
|
| 111 |
-
|
| 112 |
-
h. Licensor means the individual(s) or entity(ies) granting rights
|
| 113 |
-
under this Public License.
|
| 114 |
-
|
| 115 |
-
i. NonCommercial means not primarily intended for or directed towards
|
| 116 |
-
commercial advantage or monetary compensation. For purposes of
|
| 117 |
-
this Public License, the exchange of the Licensed Material for
|
| 118 |
-
other material subject to Copyright and Similar Rights by digital
|
| 119 |
-
file-sharing or similar means is NonCommercial provided there is
|
| 120 |
-
no payment of monetary compensation in connection with the
|
| 121 |
-
exchange.
|
| 122 |
-
|
| 123 |
-
j. Share means to provide material to the public by any means or
|
| 124 |
-
process that requires permission under the Licensed Rights, such
|
| 125 |
-
as reproduction, public display, public performance, distribution,
|
| 126 |
-
dissemination, communication, or importation, and to make material
|
| 127 |
-
available to the public including in ways that members of the
|
| 128 |
-
public may access the material from a place and at a time
|
| 129 |
-
individually chosen by them.
|
| 130 |
-
|
| 131 |
-
k. Sui Generis Database Rights means rights other than copyright
|
| 132 |
-
resulting from Directive 96/9/EC of the European Parliament and of
|
| 133 |
-
the Council of 11 March 1996 on the legal protection of databases,
|
| 134 |
-
as amended and/or succeeded, as well as other essentially
|
| 135 |
-
equivalent rights anywhere in the world.
|
| 136 |
-
|
| 137 |
-
l. You means the individual or entity exercising the Licensed Rights
|
| 138 |
-
under this Public License. Your has a corresponding meaning.
|
| 139 |
-
|
| 140 |
-
Section 2 -- Scope.
|
| 141 |
-
|
| 142 |
-
a. License grant.
|
| 143 |
-
|
| 144 |
-
1. Subject to the terms and conditions of this Public License,
|
| 145 |
-
the Licensor hereby grants You a worldwide, royalty-free,
|
| 146 |
-
non-sublicensable, non-exclusive, irrevocable license to
|
| 147 |
-
exercise the Licensed Rights in the Licensed Material to:
|
| 148 |
-
|
| 149 |
-
a. reproduce and Share the Licensed Material, in whole or
|
| 150 |
-
in part, for NonCommercial purposes only; and
|
| 151 |
-
|
| 152 |
-
b. produce, reproduce, and Share Adapted Material for
|
| 153 |
-
NonCommercial purposes only.
|
| 154 |
-
|
| 155 |
-
2. Exceptions and Limitations. For the avoidance of doubt, where
|
| 156 |
-
Exceptions and Limitations apply to Your use, this Public
|
| 157 |
-
License does not apply, and You do not need to comply with
|
| 158 |
-
its terms and conditions.
|
| 159 |
-
|
| 160 |
-
3. Term. The term of this Public License is specified in Section
|
| 161 |
-
6(a).
|
| 162 |
-
|
| 163 |
-
4. Media and formats; technical modifications allowed. The
|
| 164 |
-
Licensor authorizes You to exercise the Licensed Rights in
|
| 165 |
-
all media and formats whether now known or hereafter created,
|
| 166 |
-
and to make technical modifications necessary to do so. The
|
| 167 |
-
Licensor waives and/or agrees not to assert any right or
|
| 168 |
-
authority to forbid You from making technical modifications
|
| 169 |
-
necessary to exercise the Licensed Rights, including
|
| 170 |
-
technical modifications necessary to circumvent Effective
|
| 171 |
-
Technological Measures. For purposes of this Public License,
|
| 172 |
-
simply making modifications authorized by this Section 2(a)
|
| 173 |
-
(4) never produces Adapted Material.
|
| 174 |
-
|
| 175 |
-
5. Downstream recipients.
|
| 176 |
-
|
| 177 |
-
a. Offer from the Licensor -- Licensed Material. Every
|
| 178 |
-
recipient of the Licensed Material automatically
|
| 179 |
-
receives an offer from the Licensor to exercise the
|
| 180 |
-
Licensed Rights under the terms and conditions of this
|
| 181 |
-
Public License.
|
| 182 |
-
|
| 183 |
-
b. No downstream restrictions. You may not offer or impose
|
| 184 |
-
any additional or different terms or conditions on, or
|
| 185 |
-
apply any Effective Technological Measures to, the
|
| 186 |
-
Licensed Material if doing so restricts exercise of the
|
| 187 |
-
Licensed Rights by any recipient of the Licensed
|
| 188 |
-
Material.
|
| 189 |
-
|
| 190 |
-
6. No endorsement. Nothing in this Public License constitutes or
|
| 191 |
-
may be construed as permission to assert or imply that You
|
| 192 |
-
are, or that Your use of the Licensed Material is, connected
|
| 193 |
-
with, or sponsored, endorsed, or granted official status by,
|
| 194 |
-
the Licensor or others designated to receive attribution as
|
| 195 |
-
provided in Section 3(a)(1)(A)(i).
|
| 196 |
-
|
| 197 |
-
b. Other rights.
|
| 198 |
-
|
| 199 |
-
1. Moral rights, such as the right of integrity, are not
|
| 200 |
-
licensed under this Public License, nor are publicity,
|
| 201 |
-
privacy, and/or other similar personality rights; however, to
|
| 202 |
-
the extent possible, the Licensor waives and/or agrees not to
|
| 203 |
-
assert any such rights held by the Licensor to the limited
|
| 204 |
-
extent necessary to allow You to exercise the Licensed
|
| 205 |
-
Rights, but not otherwise.
|
| 206 |
-
|
| 207 |
-
2. Patent and trademark rights are not licensed under this
|
| 208 |
-
Public License.
|
| 209 |
-
|
| 210 |
-
3. To the extent possible, the Licensor waives any right to
|
| 211 |
-
collect royalties from You for the exercise of the Licensed
|
| 212 |
-
Rights, whether directly or through a collecting society
|
| 213 |
-
under any voluntary or waivable statutory or compulsory
|
| 214 |
-
licensing scheme. In all other cases the Licensor expressly
|
| 215 |
-
reserves any right to collect such royalties, including when
|
| 216 |
-
the Licensed Material is used other than for NonCommercial
|
| 217 |
-
purposes.
|
| 218 |
-
|
| 219 |
-
Section 3 -- License Conditions.
|
| 220 |
-
|
| 221 |
-
Your exercise of the Licensed Rights is expressly made subject to the
|
| 222 |
-
following conditions.
|
| 223 |
-
|
| 224 |
-
a. Attribution.
|
| 225 |
-
|
| 226 |
-
1. If You Share the Licensed Material (including in modified
|
| 227 |
-
form), You must:
|
| 228 |
-
|
| 229 |
-
a. retain the following if it is supplied by the Licensor
|
| 230 |
-
with the Licensed Material:
|
| 231 |
-
|
| 232 |
-
i. identification of the creator(s) of the Licensed
|
| 233 |
-
Material and any others designated to receive
|
| 234 |
-
attribution, in any reasonable manner requested by
|
| 235 |
-
the Licensor (including by pseudonym if
|
| 236 |
-
designated);
|
| 237 |
-
|
| 238 |
-
ii. a copyright notice;
|
| 239 |
-
|
| 240 |
-
iii. a notice that refers to this Public License;
|
| 241 |
-
|
| 242 |
-
iv. a notice that refers to the disclaimer of
|
| 243 |
-
warranties;
|
| 244 |
-
|
| 245 |
-
v. a URI or hyperlink to the Licensed Material to the
|
| 246 |
-
extent reasonably practicable;
|
| 247 |
-
|
| 248 |
-
b. indicate if You modified the Licensed Material and
|
| 249 |
-
retain an indication of any previous modifications; and
|
| 250 |
-
|
| 251 |
-
c. indicate the Licensed Material is licensed under this
|
| 252 |
-
Public License, and include the text of, or the URI or
|
| 253 |
-
hyperlink to, this Public License.
|
| 254 |
-
|
| 255 |
-
2. You may satisfy the conditions in Section 3(a)(1) in any
|
| 256 |
-
reasonable manner based on the medium, means, and context in
|
| 257 |
-
which You Share the Licensed Material. For example, it may be
|
| 258 |
-
reasonable to satisfy the conditions by providing a URI or
|
| 259 |
-
hyperlink to a resource that includes the required
|
| 260 |
-
information.
|
| 261 |
-
|
| 262 |
-
3. If requested by the Licensor, You must remove any of the
|
| 263 |
-
information required by Section 3(a)(1)(A) to the extent
|
| 264 |
-
reasonably practicable.
|
| 265 |
-
|
| 266 |
-
4. If You Share Adapted Material You produce, the Adapter's
|
| 267 |
-
License You apply must not prevent recipients of the Adapted
|
| 268 |
-
Material from complying with this Public License.
|
| 269 |
-
|
| 270 |
-
Section 4 -- Sui Generis Database Rights.
|
| 271 |
-
|
| 272 |
-
Where the Licensed Rights include Sui Generis Database Rights that
|
| 273 |
-
apply to Your use of the Licensed Material:
|
| 274 |
-
|
| 275 |
-
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
| 276 |
-
to extract, reuse, reproduce, and Share all or a substantial
|
| 277 |
-
portion of the contents of the database for NonCommercial purposes
|
| 278 |
-
only;
|
| 279 |
-
|
| 280 |
-
b. if You include all or a substantial portion of the database
|
| 281 |
-
contents in a database in which You have Sui Generis Database
|
| 282 |
-
Rights, then the database in which You have Sui Generis Database
|
| 283 |
-
Rights (but not its individual contents) is Adapted Material; and
|
| 284 |
-
|
| 285 |
-
c. You must comply with the conditions in Section 3(a) if You Share
|
| 286 |
-
all or a substantial portion of the contents of the database.
|
| 287 |
-
|
| 288 |
-
For the avoidance of doubt, this Section 4 supplements and does not
|
| 289 |
-
replace Your obligations under this Public License where the Licensed
|
| 290 |
-
Rights include other Copyright and Similar Rights.
|
| 291 |
-
|
| 292 |
-
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
| 293 |
-
|
| 294 |
-
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
| 295 |
-
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
| 296 |
-
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
| 297 |
-
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
| 298 |
-
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
| 299 |
-
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
| 300 |
-
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
| 301 |
-
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
| 302 |
-
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
| 303 |
-
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
| 304 |
-
|
| 305 |
-
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
| 306 |
-
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
| 307 |
-
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
| 308 |
-
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
| 309 |
-
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
| 310 |
-
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
| 311 |
-
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
| 312 |
-
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
| 313 |
-
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
| 314 |
-
|
| 315 |
-
c. The disclaimer of warranties and limitation of liability provided
|
| 316 |
-
above shall be interpreted in a manner that, to the extent
|
| 317 |
-
possible, most closely approximates an absolute disclaimer and
|
| 318 |
-
waiver of all liability.
|
| 319 |
-
|
| 320 |
-
Section 6 -- Term and Termination.
|
| 321 |
-
|
| 322 |
-
a. This Public License applies for the term of the Copyright and
|
| 323 |
-
Similar Rights licensed here. However, if You fail to comply with
|
| 324 |
-
this Public License, then Your rights under this Public License
|
| 325 |
-
terminate automatically.
|
| 326 |
-
|
| 327 |
-
b. Where Your right to use the Licensed Material has terminated under
|
| 328 |
-
Section 6(a), it reinstates:
|
| 329 |
-
|
| 330 |
-
1. automatically as of the date the violation is cured, provided
|
| 331 |
-
it is cured within 30 days of Your discovery of the
|
| 332 |
-
violation; or
|
| 333 |
-
|
| 334 |
-
2. upon express reinstatement by the Licensor.
|
| 335 |
-
|
| 336 |
-
For the avoidance of doubt, this Section 6(b) does not affect any
|
| 337 |
-
right the Licensor may have to seek remedies for Your violations
|
| 338 |
-
of this Public License.
|
| 339 |
-
|
| 340 |
-
c. For the avoidance of doubt, the Licensor may also offer the
|
| 341 |
-
Licensed Material under separate terms or conditions or stop
|
| 342 |
-
distributing the Licensed Material at any time; however, doing so
|
| 343 |
-
will not terminate this Public License.
|
| 344 |
-
|
| 345 |
-
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
| 346 |
-
License.
|
| 347 |
-
|
| 348 |
-
Section 7 -- Other Terms and Conditions.
|
| 349 |
-
|
| 350 |
-
a. The Licensor shall not be bound by any additional or different
|
| 351 |
-
terms or conditions communicated by You unless expressly agreed.
|
| 352 |
-
|
| 353 |
-
b. Any arrangements, understandings, or agreements regarding the
|
| 354 |
-
Licensed Material not stated herein are separate from and
|
| 355 |
-
independent of the terms and conditions of this Public License.
|
| 356 |
-
|
| 357 |
-
Section 8 -- Interpretation.
|
| 358 |
-
|
| 359 |
-
a. For the avoidance of doubt, this Public License does not, and
|
| 360 |
-
shall not be interpreted to, reduce, limit, restrict, or impose
|
| 361 |
-
conditions on any use of the Licensed Material that could lawfully
|
| 362 |
-
be made without permission under this Public License.
|
| 363 |
-
|
| 364 |
-
b. To the extent possible, if any provision of this Public License is
|
| 365 |
-
deemed unenforceable, it shall be automatically reformed to the
|
| 366 |
-
minimum extent necessary to make it enforceable. If the provision
|
| 367 |
-
cannot be reformed, it shall be severed from this Public License
|
| 368 |
-
without affecting the enforceability of the remaining terms and
|
| 369 |
-
conditions.
|
| 370 |
-
|
| 371 |
-
c. No term or condition of this Public License will be waived and no
|
| 372 |
-
failure to comply consented to unless expressly agreed to by the
|
| 373 |
-
Licensor.
|
| 374 |
-
|
| 375 |
-
d. Nothing in this Public License constitutes or may be interpreted
|
| 376 |
-
as a limitation upon, or waiver of, any privileges and immunities
|
| 377 |
-
that apply to the Licensor or You, including from the legal
|
| 378 |
-
processes of any jurisdiction or authority.
|
| 379 |
-
|
| 380 |
-
=======================================================================
|
| 381 |
-
|
| 382 |
-
Creative Commons is not a party to its public
|
| 383 |
-
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
| 384 |
-
its public licenses to material it publishes and in those instances
|
| 385 |
-
will be considered the “Licensor.” The text of the Creative Commons
|
| 386 |
-
public licenses is dedicated to the public domain under the CC0 Public
|
| 387 |
-
Domain Dedication. Except for the limited purpose of indicating that
|
| 388 |
-
material is shared under a Creative Commons public license or as
|
| 389 |
-
otherwise permitted by the Creative Commons policies published at
|
| 390 |
-
creativecommons.org/policies, Creative Commons does not authorize the
|
| 391 |
-
use of the trademark "Creative Commons" or any other trademark or logo
|
| 392 |
-
of Creative Commons without its prior written consent including,
|
| 393 |
-
without limitation, in connection with any unauthorized modifications
|
| 394 |
-
to any of its public licenses or any other arrangements,
|
| 395 |
-
understandings, or agreements concerning use of licensed material. For
|
| 396 |
-
the avoidance of doubt, this paragraph does not form part of the
|
| 397 |
-
public licenses.
|
| 398 |
-
|
| 399 |
-
Creative Commons may be contacted at creativecommons.org.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/README.md
DELETED
|
@@ -1,129 +0,0 @@
|
|
| 1 |
-
# <img src="images/muq-logo.jpeg" alt="" height="24px"> MuQ & MuQ-MuLan
|
| 2 |
-
|
| 3 |
-
<div>
|
| 4 |
-
<a href='#'><img alt="Static Badge" src="https://img.shields.io/badge/Python-3.8%2B-blue?logo=python&logoColor=white"></a>
|
| 5 |
-
<a href='https://arxiv.org/abs/2501.01108'><img alt="Static Badge" src="https://img.shields.io/badge/arXiv-2501.01108-%23b31b1b?logo=arxiv&link=https%3A%2F%2Farxiv.org%2F"></a>
|
| 6 |
-
<a href='https://huggingface.co/OpenMuQ'><img alt="Static Badge" src="https://img.shields.io/badge/huggingface-OpenMuQ-%23FFD21E?logo=huggingface&link=https%3A%2F%2Fhuggingface.co%2FOpenMuQ"></a>
|
| 7 |
-
<a href='https://pytorch.org/'><img alt="Static Badge" src="https://img.shields.io/badge/framework-PyTorch-%23EE4C2C?logo=pytorch"></a>
|
| 8 |
-
<a href='https://pypi.org/project/muq'><img alt="Static Badge" src="https://img.shields.io/badge/pip%20install-muq-green?logo=PyPI&logoColor=white&link=https%3A%2F%2Fpypi.org%2Fproject%2Fmuq"></a>
|
| 9 |
-
</div>
|
| 10 |
-
|
| 11 |
-
This is the official repository for the paper *"**MuQ**: Self-Supervised **Mu**sic Representation Learning
|
| 12 |
-
with Mel Residual Vector **Q**uantization"*.
|
| 13 |
-
|
| 14 |
-
In this repo, the following models are released:
|
| 15 |
-
|
| 16 |
-
- **MuQ**: A large music foundation model pre-trained via Self-Supervised Learning (SSL), achieving SOTA in various MIR tasks.
|
| 17 |
-
- **MuQ-MuLan**: A music-text joint embedding model trained via contrastive learning, supporting both English and Chinese texts.
|
| 18 |
-
|
| 19 |
-
## Overview
|
| 20 |
-
|
| 21 |
-
We develop the **MuQ** for music SSL. MuQ applys our proposed Mel-RVQ as quantitative targets and achieves SOTA performance on many music understanding (or MIR) tasks.
|
| 22 |
-
|
| 23 |
-
We also construct the **MuQ-MuLan**, a CLIP-like model trained by contrastive learning, which jointly represents music and text into embeddings.
|
| 24 |
-
|
| 25 |
-
For more details, please refer to our [paper](https://arxiv.org/abs/2501.01108).
|
| 26 |
-
|
| 27 |
-
<div>
|
| 28 |
-
<img src="images/radar.jpg" width="45%" alt="Evaluation on MARBLE Benchmark">
|
| 29 |
-
<img src="images/tagging.jpg" width="45%" alt="Evaluation on Zero-shot Music Tagging">
|
| 30 |
-
</div>
|
| 31 |
-
|
| 32 |
-
## Usage
|
| 33 |
-
|
| 34 |
-
To begin with, please use pip to install the official `muq` lib, and ensure that your `python>=3.8`:
|
| 35 |
-
```bash
|
| 36 |
-
pip3 install muq
|
| 37 |
-
```
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
To extract music audio features using **MuQ**, you can refer to the following code:
|
| 41 |
-
```python
|
| 42 |
-
import torch, librosa
|
| 43 |
-
from muq import MuQ
|
| 44 |
-
|
| 45 |
-
device = 'cuda'
|
| 46 |
-
wav, sr = librosa.load("path/to/music_audio.wav", sr = 24000)
|
| 47 |
-
wavs = torch.tensor(wav).unsqueeze(0).to(device)
|
| 48 |
-
|
| 49 |
-
# This will automatically fetch the checkpoint from huggingface
|
| 50 |
-
muq = MuQ.from_pretrained("OpenMuQ/MuQ-large-msd-iter")
|
| 51 |
-
muq = muq.to(device).eval()
|
| 52 |
-
|
| 53 |
-
with torch.no_grad():
|
| 54 |
-
output = muq(wavs, output_hidden_states=True)
|
| 55 |
-
|
| 56 |
-
print('Total number of layers: ', len(output.hidden_states))
|
| 57 |
-
print('Feature shape: ', output.last_hidden_state.shape)
|
| 58 |
-
|
| 59 |
-
```
|
| 60 |
-
|
| 61 |
-
Using **MuQ-MuLan** to extract the music and text embeddings and calculate the similarity:
|
| 62 |
-
```python
|
| 63 |
-
import torch, librosa
|
| 64 |
-
from muq import MuQMuLan
|
| 65 |
-
|
| 66 |
-
# This will automatically fetch checkpoints from huggingface
|
| 67 |
-
device = 'cuda'
|
| 68 |
-
mulan = MuQMuLan.from_pretrained("OpenMuQ/MuQ-MuLan-large")
|
| 69 |
-
mulan = mulan.to(device).eval()
|
| 70 |
-
|
| 71 |
-
# Extract music embeddings
|
| 72 |
-
wav, sr = librosa.load("path/to/music_audio.wav", sr = 24000)
|
| 73 |
-
wavs = torch.tensor(wav).unsqueeze(0).to(device)
|
| 74 |
-
with torch.no_grad():
|
| 75 |
-
audio_embeds = mulan(wavs = wavs)
|
| 76 |
-
|
| 77 |
-
# Extract text embeddings (texts can be in English or Chinese)
|
| 78 |
-
texts = ["classical genres, hopeful mood, piano.", "一首适合海边风景的小提琴曲,节奏欢快"]
|
| 79 |
-
with torch.no_grad():
|
| 80 |
-
text_embeds = mulan(texts = texts)
|
| 81 |
-
|
| 82 |
-
# Calculate dot product similarity
|
| 83 |
-
sim = mulan.calc_similarity(audio_embeds, text_embeds)
|
| 84 |
-
print(sim)
|
| 85 |
-
```
|
| 86 |
-
|
| 87 |
-
> Note that both MuQ and MuQ-MuLan strictly require **24 kHz** audio as input.
|
| 88 |
-
> We recommend using **fp32** during MuQ inference to avoid potential NaN issues.
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
## Performance
|
| 92 |
-
|
| 93 |
-
<img src="images/tab-marble.jpg" width="100%" style="max-width: 800px" alt="Table MARBLE Benchmark">
|
| 94 |
-
<img src="images/tab-mulan.png" width="50%" style="max-width: 400px; margin: 0 25%" alt="Table Mulan Results">
|
| 95 |
-
|
| 96 |
-
## Model Checkpoints
|
| 97 |
-
|
| 98 |
-
| Model Name | Parameters | Data | HuggingFace🤗 |
|
| 99 |
-
| ----------- | --- | --- | ----------- |
|
| 100 |
-
| MuQ | ~300M | MSD dataset | [OpenMuQ/MuQ-large-msd-iter](https://huggingface.co/OpenMuQ/MuQ-large-msd-iter) |
|
| 101 |
-
| MuQ-MuLan | ~700M | music-text pairs | [OpenMuQ/MuQ-MuLan-large](https://huggingface.co/OpenMuQ/MuQ-MuLan-large) |
|
| 102 |
-
|
| 103 |
-
**Note**: Please note that the open-sourced MuQ was trained on the Million Song Dataset. Due to differences in dataset size, the open-sourced model may not achieve the same level of performance as reported in the paper. The training recipes can be found [here](./src/recipes).
|
| 104 |
-
|
| 105 |
-
## License
|
| 106 |
-
|
| 107 |
-
The code in this repository is released under the MIT license as found in the [LICENSE](LICENSE) file.
|
| 108 |
-
|
| 109 |
-
The model weights (MuQ-large-msd-iter, MuQ-MuLan-large) in this repository are released under the CC-BY-NC 4.0 license, as detailed in the [LICENSE_weights](LICENSE_weights) file.
|
| 110 |
-
|
| 111 |
-
## Citation
|
| 112 |
-
|
| 113 |
-
```
|
| 114 |
-
@article{zhu2025muq,
|
| 115 |
-
title={MuQ: Self-Supervised Music Representation Learning with Mel Residual Vector Quantization},
|
| 116 |
-
author={Haina Zhu and Yizhi Zhou and Hangting Chen and Jianwei Yu and Ziyang Ma and Rongzhi Gu and Yi Luo and Wei Tan and Xie Chen},
|
| 117 |
-
journal={arXiv preprint arXiv:2501.01108},
|
| 118 |
-
year={2025}
|
| 119 |
-
}
|
| 120 |
-
```
|
| 121 |
-
|
| 122 |
-
## Acknowledgement
|
| 123 |
-
|
| 124 |
-
We borrow many codes from the following repositories:
|
| 125 |
-
- [lucidrains/musiclm-pytorch](https://github.com/lucidrains/musiclm-pytorch)
|
| 126 |
-
- [minzwon/musicfm](https://github.com/minzwon/musicfm)
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
Also, we are especially grateful to the awesome [MARBLE-Benchmark](https://github.com/a43992899/MARBLE-Benchmark).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/images/muq-logo.jpeg
DELETED
|
Binary file (39.3 kB)
|
|
|
src/third_party/MuQ/images/radar.jpg
DELETED
|
Binary file (43.1 kB)
|
|
|
src/third_party/MuQ/images/tab-marble.jpg
DELETED
Git LFS Details
|
src/third_party/MuQ/images/tab-mulan.png
DELETED
|
Binary file (83.6 kB)
|
|
|
src/third_party/MuQ/images/tagging.jpg
DELETED
|
Binary file (44.4 kB)
|
|
|
src/third_party/MuQ/requirements.txt
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
einops
|
| 2 |
-
librosa
|
| 3 |
-
nnAudio
|
| 4 |
-
numpy
|
| 5 |
-
soundfile
|
| 6 |
-
torch
|
| 7 |
-
torchaudio
|
| 8 |
-
tqdm
|
| 9 |
-
transformers
|
| 10 |
-
easydict
|
| 11 |
-
x_clip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/setup.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
| 1 |
-
from setuptools import setup, find_packages
|
| 2 |
-
|
| 3 |
-
setup(
|
| 4 |
-
name='muq', # Name of the package
|
| 5 |
-
version='0.1.0', # Version of the package
|
| 6 |
-
packages=find_packages(where='src'), # Automatically discover packages under the 'src' directory
|
| 7 |
-
package_dir={'': 'src'}, # Specify the root directory for packages as 'src'
|
| 8 |
-
include_package_data=True, # Include additional files, such as static files
|
| 9 |
-
install_requires=[ # List of dependencies
|
| 10 |
-
"einops",
|
| 11 |
-
"librosa",
|
| 12 |
-
"nnAudio",
|
| 13 |
-
"numpy",
|
| 14 |
-
"soundfile",
|
| 15 |
-
"torch",
|
| 16 |
-
"torchaudio",
|
| 17 |
-
"tqdm",
|
| 18 |
-
"transformers",
|
| 19 |
-
"easydict",
|
| 20 |
-
"x_clip",
|
| 21 |
-
],
|
| 22 |
-
author='Haina Zhu', # Author name
|
| 23 |
-
author_email='juhayna@qq.com', # Author email address
|
| 24 |
-
description='MuQ: A deep learning model for music and text', # Short description of the package
|
| 25 |
-
long_description=open('README.md', encoding='utf-8').read(), # Long description from the README file
|
| 26 |
-
long_description_content_type='text/markdown', # Format of the long description (Markdown)
|
| 27 |
-
url='https://github.com/tencent-ailab/MuQ', # Project URL
|
| 28 |
-
classifiers=[
|
| 29 |
-
'Programming Language :: Python :: 3', # Python 3 support
|
| 30 |
-
'License :: OSI Approved :: MIT License', # License type
|
| 31 |
-
'Operating System :: OS Independent', # Supports all operating systems
|
| 32 |
-
],
|
| 33 |
-
python_requires='>=3.8', # Supported Python version
|
| 34 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/__init__.py
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
from .muq import MuQ, MuQConfig
|
| 2 |
-
from .muq_mulan import MuQMuLan, MuQMuLanConfig
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
from .muq import MuQConfig, MuQ
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/models/__init__.py
DELETED
|
File without changes
|
src/third_party/MuQ/src/muq/muq/models/muq_model.py
DELETED
|
@@ -1,366 +0,0 @@
|
|
| 1 |
-
import json
|
| 2 |
-
import random
|
| 3 |
-
import torch
|
| 4 |
-
from torch import nn
|
| 5 |
-
from einops import rearrange
|
| 6 |
-
import os
|
| 7 |
-
from easydict import EasyDict
|
| 8 |
-
|
| 9 |
-
from ..modules.random_quantizer import RandomProjectionQuantizer
|
| 10 |
-
from ..modules.features import MelSTFT
|
| 11 |
-
from ..modules.conv import Conv2dSubsampling
|
| 12 |
-
|
| 13 |
-
class MuQModel(nn.Module):
|
| 14 |
-
|
| 15 |
-
def __init__(
|
| 16 |
-
self,
|
| 17 |
-
num_codebooks=1,
|
| 18 |
-
codebook_dim=16,
|
| 19 |
-
codebook_size=4096,
|
| 20 |
-
features=["melspec_2048"],
|
| 21 |
-
hop_length=240,
|
| 22 |
-
n_mels=128,
|
| 23 |
-
conv_dim=512,
|
| 24 |
-
encoder_dim=1024,
|
| 25 |
-
encoder_depth=12,
|
| 26 |
-
mask_hop=0.4,
|
| 27 |
-
mask_prob=0.6,
|
| 28 |
-
is_flash=False,
|
| 29 |
-
stat=dict(),
|
| 30 |
-
w2v2_config=dict(),
|
| 31 |
-
use_rvq_target=False,
|
| 32 |
-
use_vq_target=False,
|
| 33 |
-
use_encodec_target=False,
|
| 34 |
-
rvq_ckpt_path=None,
|
| 35 |
-
recon_loss_ratio=None,
|
| 36 |
-
label_rate=25,
|
| 37 |
-
rvq_n_codebooks=8,
|
| 38 |
-
rvq_multi_layer_num=1,
|
| 39 |
-
):
|
| 40 |
-
super().__init__()
|
| 41 |
-
|
| 42 |
-
# global variables
|
| 43 |
-
self.hop_length = hop_length
|
| 44 |
-
self.mask_hop = mask_hop
|
| 45 |
-
self.mask_prob = mask_prob
|
| 46 |
-
self.num_codebooks = num_codebooks
|
| 47 |
-
self.codebook_size = codebook_size
|
| 48 |
-
self.features = features
|
| 49 |
-
self.recon_loss_ratio = recon_loss_ratio
|
| 50 |
-
self.n_fold = int(100//label_rate)
|
| 51 |
-
self.label_rate = label_rate
|
| 52 |
-
|
| 53 |
-
# load feature mean / std stats
|
| 54 |
-
self.stat = stat
|
| 55 |
-
|
| 56 |
-
# feature extractor
|
| 57 |
-
self.preprocessor_melspec_2048 = MelSTFT(
|
| 58 |
-
n_fft=2048, hop_length=hop_length, is_db=True
|
| 59 |
-
)
|
| 60 |
-
|
| 61 |
-
# random quantizer
|
| 62 |
-
self.use_rvq_target = use_rvq_target
|
| 63 |
-
self.use_vq_target = use_vq_target
|
| 64 |
-
self.use_encodec_target = use_encodec_target
|
| 65 |
-
|
| 66 |
-
seed = 142
|
| 67 |
-
if self.use_rvq_like_target:
|
| 68 |
-
if use_rvq_target:
|
| 69 |
-
from ..modules.rvq import ResidualVectorQuantize
|
| 70 |
-
|
| 71 |
-
inp_dim = 128*self.n_fold
|
| 72 |
-
self.rvq = ResidualVectorQuantize(
|
| 73 |
-
input_dim = inp_dim,
|
| 74 |
-
n_codebooks = rvq_n_codebooks,
|
| 75 |
-
codebook_size = 1024,
|
| 76 |
-
codebook_dim = 16,
|
| 77 |
-
quantizer_dropout = 0.0,
|
| 78 |
-
use_multi_layer_num = rvq_multi_layer_num,
|
| 79 |
-
)
|
| 80 |
-
elif use_vq_target:
|
| 81 |
-
from ..modules.rvq import VectorQuantize
|
| 82 |
-
|
| 83 |
-
self.rvq = VectorQuantize(
|
| 84 |
-
input_dim = 128*self.n_fold,
|
| 85 |
-
codebook_size = 1024,
|
| 86 |
-
codebook_dim = 8,
|
| 87 |
-
stale_tolerance = 1000,
|
| 88 |
-
mfcc_clustering = False
|
| 89 |
-
)
|
| 90 |
-
elif use_encodec_target:
|
| 91 |
-
from encodec import EncodecModel
|
| 92 |
-
self.rvq = EncodecModel.encodec_model_24khz()
|
| 93 |
-
self.rvq.set_target_bandwidth(6.0)
|
| 94 |
-
for param in self.rvq.parameters():
|
| 95 |
-
param.requires_grad = False
|
| 96 |
-
|
| 97 |
-
if rvq_ckpt_path is not None and os.path.exists(rvq_ckpt_path):
|
| 98 |
-
state_dict = torch.load(rvq_ckpt_path, map_location="cpu")
|
| 99 |
-
self.rvq.load_state_dict(state_dict)
|
| 100 |
-
else:
|
| 101 |
-
pass
|
| 102 |
-
# print(f'Checkpoint for rvq `{rvq_ckpt_path}` not found. Using random initialization.')
|
| 103 |
-
else:
|
| 104 |
-
for feature in self.features:
|
| 105 |
-
for i in range(num_codebooks):
|
| 106 |
-
setattr(
|
| 107 |
-
self,
|
| 108 |
-
f"quantizer_{feature}", # _{i}
|
| 109 |
-
RandomProjectionQuantizer(
|
| 110 |
-
n_mels * self.n_fold, codebook_dim, codebook_size, seed=seed + i
|
| 111 |
-
),
|
| 112 |
-
)
|
| 113 |
-
|
| 114 |
-
# two residual convolution layers + one projection layer
|
| 115 |
-
strides_factory = {
|
| 116 |
-
4: [2, 2],
|
| 117 |
-
2: [2, 1]
|
| 118 |
-
}
|
| 119 |
-
self.conv = Conv2dSubsampling(
|
| 120 |
-
1, conv_dim, encoder_dim, strides=strides_factory.get(self.n_fold), n_bands=n_mels
|
| 121 |
-
)
|
| 122 |
-
|
| 123 |
-
# Conformer
|
| 124 |
-
if is_flash:
|
| 125 |
-
from modules.flash_conformer import (
|
| 126 |
-
Wav2Vec2ConformerEncoder,
|
| 127 |
-
Wav2Vec2ConformerConfig,
|
| 128 |
-
)
|
| 129 |
-
else:
|
| 130 |
-
from transformers.models.wav2vec2_conformer.modeling_wav2vec2_conformer import (
|
| 131 |
-
Wav2Vec2ConformerEncoder,
|
| 132 |
-
Wav2Vec2ConformerConfig,
|
| 133 |
-
)
|
| 134 |
-
config = EasyDict(w2v2_config)
|
| 135 |
-
config.num_hidden_layers = encoder_depth
|
| 136 |
-
config.hidden_size = encoder_dim
|
| 137 |
-
|
| 138 |
-
self.conformer = Wav2Vec2ConformerEncoder(config)
|
| 139 |
-
|
| 140 |
-
self.linear = nn.Linear(encoder_dim, codebook_size) # projection layer
|
| 141 |
-
|
| 142 |
-
# reconstruct melspec
|
| 143 |
-
if self.recon_loss_ratio is not None and self.recon_loss_ratio > 0:
|
| 144 |
-
self.recon_proj = nn.Linear(encoder_dim, n_mels * self.n_fold)
|
| 145 |
-
self.recon_loss = nn.MSELoss()
|
| 146 |
-
|
| 147 |
-
# loss function
|
| 148 |
-
self.loss = nn.CrossEntropyLoss()
|
| 149 |
-
|
| 150 |
-
# cls token (used for sequence classification)
|
| 151 |
-
random.seed(seed)
|
| 152 |
-
self.cls_token = nn.Parameter(torch.randn(encoder_dim))
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
@property
|
| 156 |
-
def use_rvq_like_target(self):
|
| 157 |
-
return self.use_rvq_target or self.use_vq_target or self.use_encodec_target
|
| 158 |
-
|
| 159 |
-
def masking(self, x, attention_mask=None):
|
| 160 |
-
"""random masking of 400ms with given probability"""
|
| 161 |
-
mx = x.clone()
|
| 162 |
-
b, t = mx.shape
|
| 163 |
-
len_masking_raw = int(24000 * self.mask_hop)
|
| 164 |
-
len_masking_token = int(24000 / self.hop_length / 2 / 2 * self.mask_hop)
|
| 165 |
-
|
| 166 |
-
# get random mask indices
|
| 167 |
-
start_indices = torch.rand(b, t // len_masking_raw) < self.mask_prob
|
| 168 |
-
time_domain_masked_indices = torch.nonzero(
|
| 169 |
-
start_indices.repeat_interleave(len_masking_raw, dim=1)
|
| 170 |
-
)
|
| 171 |
-
token_domain_masked_indices = torch.nonzero(
|
| 172 |
-
start_indices.repeat_interleave(len_masking_token, dim=1)
|
| 173 |
-
)
|
| 174 |
-
|
| 175 |
-
# mask with random values
|
| 176 |
-
masking_noise = (
|
| 177 |
-
torch.randn(time_domain_masked_indices.shape[0], dtype=x.dtype) * 0.1
|
| 178 |
-
) # 0 mean 0.1 std
|
| 179 |
-
mx[tuple(time_domain_masked_indices.t())] = masking_noise.to(x.device)
|
| 180 |
-
|
| 181 |
-
return mx, token_domain_masked_indices
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
@torch.no_grad()
|
| 185 |
-
def preprocessing(self, x, features):
|
| 186 |
-
"""extract classic audio features"""
|
| 187 |
-
# check precision
|
| 188 |
-
if x.dtype == torch.float16 or x.dtype == torch.bfloat16:
|
| 189 |
-
precision = 16
|
| 190 |
-
else:
|
| 191 |
-
precision = 32
|
| 192 |
-
|
| 193 |
-
out = {}
|
| 194 |
-
for key in features:
|
| 195 |
-
layer = getattr(self, "preprocessor_%s" % key)
|
| 196 |
-
layer.to(x.device)
|
| 197 |
-
dtype = x.dtype
|
| 198 |
-
out[key] = layer(x.float())[..., :-1]
|
| 199 |
-
if precision == 16:
|
| 200 |
-
out[key] = out[key].half()
|
| 201 |
-
if out[key].dtype != dtype:
|
| 202 |
-
out[key].to(dtype=dtype)
|
| 203 |
-
return out
|
| 204 |
-
|
| 205 |
-
def encoder(self, x, *, attention_mask=None, is_features_only=False):
|
| 206 |
-
"""2-layer conv + w2v-conformer"""
|
| 207 |
-
x = self.conv(x)
|
| 208 |
-
mask_indices = None
|
| 209 |
-
if attention_mask is None:
|
| 210 |
-
out = self.conformer(x, output_hidden_states=True)
|
| 211 |
-
else:
|
| 212 |
-
attention_mask = attention_mask.bool()
|
| 213 |
-
skip_n = int(attention_mask.size(-1) / x.size(1))
|
| 214 |
-
attention_mask = attention_mask[:, ::skip_n]
|
| 215 |
-
attention_mask = attention_mask[:, :x.size(1)]
|
| 216 |
-
out = self.conformer(x, attention_mask=attention_mask, output_hidden_states=True)
|
| 217 |
-
hidden_emb = out["hidden_states"]
|
| 218 |
-
last_emb = out["last_hidden_state"]
|
| 219 |
-
logits = self.linear(last_emb)
|
| 220 |
-
interval = self.codebook_size
|
| 221 |
-
logits = {
|
| 222 |
-
key: logits[:, :, i * interval : (i + 1) * interval]
|
| 223 |
-
for i, key in enumerate(self.features)
|
| 224 |
-
}
|
| 225 |
-
return logits, hidden_emb, mask_indices
|
| 226 |
-
|
| 227 |
-
@torch.no_grad()
|
| 228 |
-
def normalize(self, x):
|
| 229 |
-
"""normalize the input audio to have zero mean unit variance"""
|
| 230 |
-
for key in x.keys():
|
| 231 |
-
x[key] = (x[key] - self.stat["%s_mean" % key]) / self.stat["%s_std" % key]
|
| 232 |
-
return x
|
| 233 |
-
|
| 234 |
-
@torch.no_grad()
|
| 235 |
-
def rearrange(self, x):
|
| 236 |
-
"""rearrange the batch to flatten every 4 steps"""
|
| 237 |
-
for key in x.keys():
|
| 238 |
-
if key == "chromagram":
|
| 239 |
-
x[key] = rearrange(x[key], "b f t -> b t f")
|
| 240 |
-
else:
|
| 241 |
-
x[key] = rearrange(x[key], "b f (t s) -> b t (s f)", s=self.n_fold)
|
| 242 |
-
return x
|
| 243 |
-
|
| 244 |
-
def get_rvq_codes(self, inp, raw_wav):
|
| 245 |
-
if self.use_rvq_target:
|
| 246 |
-
quantized_prompt_embeds, codes, _, commitment_loss, codebook_loss, rvq_usage = self.rvq(inp)
|
| 247 |
-
return codes
|
| 248 |
-
if self.use_vq_target:
|
| 249 |
-
quantized_prompt_embeds, commitment_loss, codebook_loss, codes, _ = self.rvq(inp)
|
| 250 |
-
return codes.unsqueeze(1)
|
| 251 |
-
if self.use_encodec_target:
|
| 252 |
-
encoded_frames = self.rvq.encode(raw_wav.unsqueeze(1)) #list, B,[ 8,T ]
|
| 253 |
-
codes = torch.cat([encoded[0].detach() for encoded in encoded_frames], dim=-1)
|
| 254 |
-
if self.label_rate == 25:
|
| 255 |
-
codes = codes[:, :, ::3]
|
| 256 |
-
return codes
|
| 257 |
-
|
| 258 |
-
@torch.no_grad()
|
| 259 |
-
def tokenize(self, x, raw_wav):
|
| 260 |
-
out = {}
|
| 261 |
-
for key in x.keys():
|
| 262 |
-
if self.use_rvq_like_target:
|
| 263 |
-
self.rvq.eval()
|
| 264 |
-
inp = x[key].permute((0, 2, 1))
|
| 265 |
-
codes = self.get_rvq_codes(inp, raw_wav)
|
| 266 |
-
out[key] = torch.cat([codes[:, idx, ...] for idx in range(int(self.codebook_size//1024))], dim=-1)
|
| 267 |
-
else:
|
| 268 |
-
layer = getattr(self, "quantizer_%s" % key)
|
| 269 |
-
out[key] = layer(x[key])
|
| 270 |
-
return out
|
| 271 |
-
|
| 272 |
-
def get_targets(self, x, label=None):
|
| 273 |
-
if self.use_encodec_target:
|
| 274 |
-
raw_x = x.clone()
|
| 275 |
-
else:
|
| 276 |
-
raw_x = None
|
| 277 |
-
x = self.preprocessing(x, features=self.features)
|
| 278 |
-
x = self.normalize(x)
|
| 279 |
-
x = self.rearrange(x)
|
| 280 |
-
melspec = x['melspec_2048']
|
| 281 |
-
if label is None:
|
| 282 |
-
# Use labels from Mel-RVQ
|
| 283 |
-
target_tokens = self.tokenize(x, raw_x)
|
| 284 |
-
else:
|
| 285 |
-
# Use labels pre-extracted for iteration training
|
| 286 |
-
target_tokens = {'melspec_2048': rearrange(label, "b n s -> b (n s)").long()}
|
| 287 |
-
return target_tokens, melspec
|
| 288 |
-
|
| 289 |
-
def get_predictions(self, x, *, mask=None, attention_mask=None, return_new_mask=False, is_features_only=False):
|
| 290 |
-
# preprocessing
|
| 291 |
-
x = self.preprocessing(x, features=["melspec_2048"])
|
| 292 |
-
x = self.normalize(x)
|
| 293 |
-
|
| 294 |
-
# encoding
|
| 295 |
-
logits, hidden_emb, new_mask = self.encoder(x["melspec_2048"], attention_mask=attention_mask, is_features_only=is_features_only)
|
| 296 |
-
|
| 297 |
-
if return_new_mask:
|
| 298 |
-
return logits, hidden_emb, mask if new_mask is None else new_mask
|
| 299 |
-
else:
|
| 300 |
-
return logits, hidden_emb
|
| 301 |
-
|
| 302 |
-
def get_latent(self, x, layer_ix=12):
|
| 303 |
-
_, hidden_states = self.get_predictions(x)
|
| 304 |
-
emb = hidden_states[layer_ix]
|
| 305 |
-
return emb
|
| 306 |
-
|
| 307 |
-
def compute_nce(self, x, pos, negs):
|
| 308 |
-
neg_is_pos = (pos == negs).all(-1)
|
| 309 |
-
pos = pos.unsqueeze(0)
|
| 310 |
-
targets = torch.cat([pos, negs], dim=0)
|
| 311 |
-
|
| 312 |
-
logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1).type_as(x)
|
| 313 |
-
logits /= 0.1
|
| 314 |
-
if neg_is_pos.any():
|
| 315 |
-
logits[1:][neg_is_pos] = float("-inf")
|
| 316 |
-
logits = logits.transpose(0, 1)
|
| 317 |
-
return logits
|
| 318 |
-
|
| 319 |
-
def get_loss(self, logits, target_tokens, masked_indices):
|
| 320 |
-
losses = {}
|
| 321 |
-
accuracies = {}
|
| 322 |
-
for key in logits.keys():
|
| 323 |
-
if not self.use_rvq_like_target:
|
| 324 |
-
masked_logits = logits[key][tuple(masked_indices.t())]
|
| 325 |
-
masked_tokens = target_tokens[key][tuple(masked_indices.t())]
|
| 326 |
-
else:
|
| 327 |
-
Batch, SeqLen, N_Codebook_x_CodebookSize = logits[key].shape
|
| 328 |
-
Batch, N_Codebook_x_SeqLen = target_tokens[key].shape
|
| 329 |
-
N_Codebook = int(N_Codebook_x_SeqLen // SeqLen)
|
| 330 |
-
target_tokens[key] = rearrange(target_tokens[key], "b (n s) -> b s n", n=N_Codebook) # Batch, SeqLen=750, N_Codebook=4
|
| 331 |
-
masked_logits = logits[key][tuple(masked_indices.t())]
|
| 332 |
-
masked_tokens = target_tokens[key][tuple(masked_indices.t())]
|
| 333 |
-
masked_logits = rearrange(masked_logits, "b (n c) -> (b n) c", n=N_Codebook)
|
| 334 |
-
masked_tokens = rearrange(masked_tokens, "b n -> (b n)", n=N_Codebook)
|
| 335 |
-
|
| 336 |
-
losses[key] = self.loss(masked_logits, masked_tokens)
|
| 337 |
-
accuracies[key] = (
|
| 338 |
-
torch.sum(masked_logits.argmax(-1) == masked_tokens)
|
| 339 |
-
/ masked_tokens.numel()
|
| 340 |
-
)
|
| 341 |
-
return losses, accuracies
|
| 342 |
-
|
| 343 |
-
def get_recon_loss(self, last_hidden_emb, melspec, masked_indices):
|
| 344 |
-
pred_melspec = self.recon_proj(last_hidden_emb[tuple(masked_indices.t())])
|
| 345 |
-
target_melspec = melspec[tuple(masked_indices.t())]
|
| 346 |
-
recon_loss = self.recon_loss(pred_melspec, target_melspec)
|
| 347 |
-
return recon_loss
|
| 348 |
-
|
| 349 |
-
def forward(self, x, attention_mask=None, label=None):
|
| 350 |
-
dtype = x.dtype
|
| 351 |
-
# get target feature tokens
|
| 352 |
-
target_tokens, melspec = self.get_targets(x, label=label)
|
| 353 |
-
|
| 354 |
-
# masking
|
| 355 |
-
x, masked_indices = self.masking(x, attention_mask=attention_mask)
|
| 356 |
-
|
| 357 |
-
# forward
|
| 358 |
-
logits, hidden_emb, masked_indices = self.get_predictions(x, mask=masked_indices, attention_mask=attention_mask, return_new_mask=True)
|
| 359 |
-
|
| 360 |
-
# get loss
|
| 361 |
-
losses, accuracies = self.get_loss(logits, target_tokens, masked_indices)
|
| 362 |
-
|
| 363 |
-
if self.recon_loss_ratio:
|
| 364 |
-
losses["recon_loss"] = self.get_recon_loss(hidden_emb[-1], melspec, masked_indices) * self.recon_loss_ratio
|
| 365 |
-
|
| 366 |
-
return logits, hidden_emb, losses, accuracies
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/__init__.py
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
|
| 2 |
-
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/conv.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
| 1 |
-
from torch import nn
|
| 2 |
-
from einops import rearrange
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class Res2dModule(nn.Module):
|
| 6 |
-
def __init__(self, idim, odim, stride=(2, 2)):
|
| 7 |
-
super(Res2dModule, self).__init__()
|
| 8 |
-
self.conv1 = nn.Conv2d(idim, odim, 3, padding=1, stride=stride)
|
| 9 |
-
self.bn1 = nn.BatchNorm2d(odim)
|
| 10 |
-
self.conv2 = nn.Conv2d(odim, odim, 3, padding=1)
|
| 11 |
-
self.bn2 = nn.BatchNorm2d(odim)
|
| 12 |
-
self.relu = nn.ReLU()
|
| 13 |
-
|
| 14 |
-
# residual
|
| 15 |
-
self.diff = False
|
| 16 |
-
if (idim != odim) or (stride[0] > 1):
|
| 17 |
-
self.conv3 = nn.Conv2d(idim, odim, 3, padding=1, stride=stride)
|
| 18 |
-
self.bn3 = nn.BatchNorm2d(odim)
|
| 19 |
-
self.diff = True
|
| 20 |
-
|
| 21 |
-
def forward(self, x):
|
| 22 |
-
out = self.bn2(self.conv2(self.relu(self.bn1(self.conv1(x)))))
|
| 23 |
-
if self.diff:
|
| 24 |
-
x = self.bn3(self.conv3(x))
|
| 25 |
-
out = x + out
|
| 26 |
-
out = self.relu(out)
|
| 27 |
-
return out
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
class Conv2dSubsampling(nn.Module):
|
| 31 |
-
"""Convolutional 2D subsampling (to 1/4 length).
|
| 32 |
-
|
| 33 |
-
Args:
|
| 34 |
-
idim (int): Input dimension.
|
| 35 |
-
hdim (int): Hidden dimension.
|
| 36 |
-
odim (int): Output dimension.
|
| 37 |
-
strides (list): Sizes of strides.
|
| 38 |
-
n_bands (int): Number of frequency bands.
|
| 39 |
-
"""
|
| 40 |
-
|
| 41 |
-
def __init__(self, idim, hdim, odim, strides=[2, 2], n_bands=64):
|
| 42 |
-
"""Construct an Conv2dSubsampling object."""
|
| 43 |
-
super(Conv2dSubsampling, self).__init__()
|
| 44 |
-
|
| 45 |
-
self.conv = nn.Sequential(
|
| 46 |
-
Res2dModule(idim, hdim, (2, strides[0])),
|
| 47 |
-
Res2dModule(hdim, hdim, (2, strides[1])),
|
| 48 |
-
)
|
| 49 |
-
self.linear = nn.Linear(hdim * n_bands // 2 // 2, odim)
|
| 50 |
-
|
| 51 |
-
def forward(self, x):
|
| 52 |
-
"""Subsample x.
|
| 53 |
-
|
| 54 |
-
Args:
|
| 55 |
-
x (torch.Tensor): Input tensor (#batch, idim, time).
|
| 56 |
-
|
| 57 |
-
Returns:
|
| 58 |
-
torch.Tensor: Subsampled tensor (#batch, time', odim),
|
| 59 |
-
where time' = time // 4.
|
| 60 |
-
"""
|
| 61 |
-
|
| 62 |
-
if x.dim() == 3:
|
| 63 |
-
x = x.unsqueeze(1) # (b, c, f, t)
|
| 64 |
-
x = self.conv(x)
|
| 65 |
-
x = rearrange(x, "b c f t -> b t (c f)")
|
| 66 |
-
x = self.linear(x)
|
| 67 |
-
return x
|
| 68 |
-
|
| 69 |
-
if __name__ == '__main__':
|
| 70 |
-
import torch
|
| 71 |
-
conv_dim, encoder_dim = 512, 1024
|
| 72 |
-
conv = Conv2dSubsampling(
|
| 73 |
-
1, conv_dim, encoder_dim, strides=[2, 1], n_bands=128
|
| 74 |
-
)
|
| 75 |
-
inp = torch.randn((1, 128, 3000))
|
| 76 |
-
out = conv(inp)
|
| 77 |
-
print(out.shape)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/features.py
DELETED
|
@@ -1,37 +0,0 @@
|
|
| 1 |
-
import torchaudio
|
| 2 |
-
from torch import nn
|
| 3 |
-
import torch
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class MelSTFT:
|
| 7 |
-
def __init__(
|
| 8 |
-
self,
|
| 9 |
-
sample_rate=24000,
|
| 10 |
-
n_fft=2048,
|
| 11 |
-
hop_length=240,
|
| 12 |
-
n_mels=128,
|
| 13 |
-
is_db=False,
|
| 14 |
-
):
|
| 15 |
-
super(MelSTFT, self).__init__()
|
| 16 |
-
|
| 17 |
-
# spectrogram
|
| 18 |
-
self.mel_stft = torchaudio.transforms.MelSpectrogram(
|
| 19 |
-
sample_rate=sample_rate, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels
|
| 20 |
-
)
|
| 21 |
-
|
| 22 |
-
# amplitude to decibel
|
| 23 |
-
self.is_db = is_db
|
| 24 |
-
if is_db:
|
| 25 |
-
self.amplitude_to_db = torchaudio.transforms.AmplitudeToDB()
|
| 26 |
-
|
| 27 |
-
def __call__(self, waveform):
|
| 28 |
-
if self.is_db:
|
| 29 |
-
return self.amplitude_to_db(self.mel_stft(waveform))
|
| 30 |
-
else:
|
| 31 |
-
return self.mel_stft(waveform)
|
| 32 |
-
|
| 33 |
-
def to(self, device):
|
| 34 |
-
self.mel_stft = self.mel_stft.to(device)
|
| 35 |
-
if self.is_db:
|
| 36 |
-
self.amplitude_to_db = self.amplitude_to_db.to(device)
|
| 37 |
-
return self
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/flash_conformer.py
DELETED
|
@@ -1,2114 +0,0 @@
|
|
| 1 |
-
# coding=utf-8
|
| 2 |
-
# Copyright 2022 The Fairseq Authors and the HuggingFace Inc. team. 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 |
-
""" PyTorch Wav2Vec2-Conformer model."""
|
| 16 |
-
|
| 17 |
-
import math
|
| 18 |
-
from dataclasses import dataclass
|
| 19 |
-
from typing import Optional, Tuple, Union
|
| 20 |
-
|
| 21 |
-
import numpy as np
|
| 22 |
-
import torch
|
| 23 |
-
import torch.utils.checkpoint
|
| 24 |
-
from torch import nn
|
| 25 |
-
from torch.nn import CrossEntropyLoss
|
| 26 |
-
from torch.nn import functional as F
|
| 27 |
-
|
| 28 |
-
from transformers.activations import ACT2FN
|
| 29 |
-
from transformers.deepspeed import is_deepspeed_zero3_enabled
|
| 30 |
-
from transformers.modeling_outputs import (
|
| 31 |
-
BaseModelOutput,
|
| 32 |
-
CausalLMOutput,
|
| 33 |
-
SequenceClassifierOutput,
|
| 34 |
-
TokenClassifierOutput,
|
| 35 |
-
Wav2Vec2BaseModelOutput,
|
| 36 |
-
XVectorOutput,
|
| 37 |
-
)
|
| 38 |
-
from transformers.modeling_utils import PreTrainedModel
|
| 39 |
-
from transformers.utils import (
|
| 40 |
-
ModelOutput,
|
| 41 |
-
add_code_sample_docstrings,
|
| 42 |
-
add_start_docstrings,
|
| 43 |
-
add_start_docstrings_to_model_forward,
|
| 44 |
-
logging,
|
| 45 |
-
replace_return_docstrings,
|
| 46 |
-
)
|
| 47 |
-
from transformers.models.wav2vec2_conformer.configuration_wav2vec2_conformer import Wav2Vec2ConformerConfig
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
logger = logging.get_logger(__name__)
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
_HIDDEN_STATES_START_POSITION = 2
|
| 54 |
-
|
| 55 |
-
# General docstring
|
| 56 |
-
_CONFIG_FOR_DOC = "Wav2Vec2ConformerConfig"
|
| 57 |
-
|
| 58 |
-
# Base docstring
|
| 59 |
-
_CHECKPOINT_FOR_DOC = "facebook/wav2vec2-conformer-rope-large-960h-ft"
|
| 60 |
-
_EXPECTED_OUTPUT_SHAPE = [1, 292, 1024]
|
| 61 |
-
|
| 62 |
-
# CTC docstring
|
| 63 |
-
_CTC_EXPECTED_OUTPUT = "'MISTER QUILTER IS THE APOSTLE OF THE MIDDLE CLASSES AND WE ARE GLAD TO WELCOME HIS GOSPEL'"
|
| 64 |
-
_CTC_EXPECTED_LOSS = 64.21
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
WAV2VEC2_CONFORMER_PRETRAINED_MODEL_ARCHIVE_LIST = [
|
| 68 |
-
"facebook/wav2vec2-conformer-rel-pos-large",
|
| 69 |
-
# See all Wav2Vec2Conformer models at https://huggingface.co/models?filter=wav2vec2-conformer
|
| 70 |
-
]
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
@dataclass
|
| 74 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTrainingOutput with Wav2Vec2->Wav2Vec2Conformer
|
| 75 |
-
class Wav2Vec2ConformerForPreTrainingOutput(ModelOutput):
|
| 76 |
-
"""
|
| 77 |
-
Output type of [`Wav2Vec2ConformerForPreTraining`], with potential hidden states and attentions.
|
| 78 |
-
|
| 79 |
-
Args:
|
| 80 |
-
loss (*optional*, returned when `sample_negative_indices` are passed, `torch.FloatTensor` of shape `(1,)`):
|
| 81 |
-
Total loss as the sum of the contrastive loss (L_m) and the diversity loss (L_d) as stated in the [official
|
| 82 |
-
paper](https://arxiv.org/pdf/2006.11477.pdf) . (classification) loss.
|
| 83 |
-
projected_states (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.proj_codevector_dim)`):
|
| 84 |
-
Hidden-states of the model projected to *config.proj_codevector_dim* that can be used to predict the masked
|
| 85 |
-
projected quantized states.
|
| 86 |
-
projected_quantized_states (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.proj_codevector_dim)`):
|
| 87 |
-
Quantized extracted feature vectors projected to *config.proj_codevector_dim* representing the positive
|
| 88 |
-
target vectors for contrastive loss.
|
| 89 |
-
hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
|
| 90 |
-
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of
|
| 91 |
-
shape `(batch_size, sequence_length, hidden_size)`.
|
| 92 |
-
|
| 93 |
-
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
| 94 |
-
attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` is passed or when `config.output_attentions=True`):
|
| 95 |
-
Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
|
| 96 |
-
sequence_length)`.
|
| 97 |
-
|
| 98 |
-
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
| 99 |
-
heads.
|
| 100 |
-
contrastive_loss (*optional*, returned when `sample_negative_indices` are passed, `torch.FloatTensor` of shape `(1,)`):
|
| 101 |
-
The contrastive loss (L_m) as stated in the [official paper](https://arxiv.org/pdf/2006.11477.pdf) .
|
| 102 |
-
diversity_loss (*optional*, returned when `sample_negative_indices` are passed, `torch.FloatTensor` of shape `(1,)`):
|
| 103 |
-
The diversity loss (L_d) as stated in the [official paper](https://arxiv.org/pdf/2006.11477.pdf) .
|
| 104 |
-
"""
|
| 105 |
-
|
| 106 |
-
loss: Optional[torch.FloatTensor] = None
|
| 107 |
-
projected_states: torch.FloatTensor = None
|
| 108 |
-
projected_quantized_states: torch.FloatTensor = None
|
| 109 |
-
codevector_perplexity: torch.FloatTensor = None
|
| 110 |
-
hidden_states: Optional[Tuple[torch.FloatTensor]] = None
|
| 111 |
-
attentions: Optional[Tuple[torch.FloatTensor]] = None
|
| 112 |
-
contrastive_loss: Optional[torch.FloatTensor] = None
|
| 113 |
-
diversity_loss: Optional[torch.FloatTensor] = None
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2._compute_mask_indices
|
| 117 |
-
def _compute_mask_indices(
|
| 118 |
-
shape: Tuple[int, int],
|
| 119 |
-
mask_prob: float,
|
| 120 |
-
mask_length: int,
|
| 121 |
-
attention_mask: Optional[torch.LongTensor] = None,
|
| 122 |
-
min_masks: int = 0,
|
| 123 |
-
) -> np.ndarray:
|
| 124 |
-
"""
|
| 125 |
-
Computes random mask spans for a given shape. Used to implement [SpecAugment: A Simple Data Augmentation Method for
|
| 126 |
-
ASR](https://arxiv.org/abs/1904.08779). Note that this method is not optimized to run on TPU and should be run on
|
| 127 |
-
CPU as part of the preprocessing during training.
|
| 128 |
-
|
| 129 |
-
Args:
|
| 130 |
-
shape: The shape for which to compute masks. This should be of a tuple of size 2 where
|
| 131 |
-
the first element is the batch size and the second element is the length of the axis to span.
|
| 132 |
-
mask_prob: The percentage of the whole axis (between 0 and 1) which will be masked. The number of
|
| 133 |
-
independently generated mask spans of length `mask_length` is computed by
|
| 134 |
-
`mask_prob*shape[1]/mask_length`. Note that due to overlaps, `mask_prob` is an upper bound and the
|
| 135 |
-
actual percentage will be smaller.
|
| 136 |
-
mask_length: size of the mask
|
| 137 |
-
min_masks: minimum number of masked spans
|
| 138 |
-
attention_mask: A (right-padded) attention mask which independently shortens the feature axis of
|
| 139 |
-
each batch dimension.
|
| 140 |
-
"""
|
| 141 |
-
batch_size, sequence_length = shape
|
| 142 |
-
|
| 143 |
-
if mask_length < 1:
|
| 144 |
-
raise ValueError("`mask_length` has to be bigger than 0.")
|
| 145 |
-
|
| 146 |
-
if mask_length > sequence_length:
|
| 147 |
-
raise ValueError(
|
| 148 |
-
f"`mask_length` has to be smaller than `sequence_length`, but got `mask_length`: {mask_length}"
|
| 149 |
-
f" and `sequence_length`: {sequence_length}`"
|
| 150 |
-
)
|
| 151 |
-
|
| 152 |
-
# epsilon is used for probabilistic rounding
|
| 153 |
-
epsilon = np.random.rand(1).item()
|
| 154 |
-
|
| 155 |
-
def compute_num_masked_span(input_length):
|
| 156 |
-
"""Given input length, compute how many spans should be masked"""
|
| 157 |
-
num_masked_span = int(mask_prob * input_length / mask_length + epsilon)
|
| 158 |
-
num_masked_span = max(num_masked_span, min_masks)
|
| 159 |
-
|
| 160 |
-
# make sure num masked span <= sequence_length
|
| 161 |
-
if num_masked_span * mask_length > sequence_length:
|
| 162 |
-
num_masked_span = sequence_length // mask_length
|
| 163 |
-
|
| 164 |
-
# make sure num_masked span is also <= input_length - (mask_length - 1)
|
| 165 |
-
if input_length - (mask_length - 1) < num_masked_span:
|
| 166 |
-
num_masked_span = max(input_length - (mask_length - 1), 0)
|
| 167 |
-
|
| 168 |
-
return num_masked_span
|
| 169 |
-
|
| 170 |
-
# compute number of masked spans in batch
|
| 171 |
-
input_lengths = (
|
| 172 |
-
attention_mask.sum(-1).detach().tolist()
|
| 173 |
-
if attention_mask is not None
|
| 174 |
-
else [sequence_length for _ in range(batch_size)]
|
| 175 |
-
)
|
| 176 |
-
|
| 177 |
-
# SpecAugment mask to fill
|
| 178 |
-
spec_aug_mask = np.zeros((batch_size, sequence_length), dtype=bool)
|
| 179 |
-
spec_aug_mask_idxs = []
|
| 180 |
-
|
| 181 |
-
max_num_masked_span = compute_num_masked_span(sequence_length)
|
| 182 |
-
|
| 183 |
-
if max_num_masked_span == 0:
|
| 184 |
-
return spec_aug_mask
|
| 185 |
-
|
| 186 |
-
for input_length in input_lengths:
|
| 187 |
-
# compute num of masked spans for this input
|
| 188 |
-
num_masked_span = compute_num_masked_span(input_length)
|
| 189 |
-
|
| 190 |
-
# get random indices to mask
|
| 191 |
-
spec_aug_mask_idx = np.random.choice(
|
| 192 |
-
np.arange(input_length - (mask_length - 1)), num_masked_span, replace=False
|
| 193 |
-
)
|
| 194 |
-
|
| 195 |
-
# pick first sampled index that will serve as a dummy index to pad vector
|
| 196 |
-
# to ensure same dimension for all batches due to probabilistic rounding
|
| 197 |
-
# Picking first sample just pads those vectors twice.
|
| 198 |
-
if len(spec_aug_mask_idx) == 0:
|
| 199 |
-
# this case can only happen if `input_length` is strictly smaller then
|
| 200 |
-
# `sequence_length` in which case the last token has to be a padding
|
| 201 |
-
# token which we can use as a dummy mask id
|
| 202 |
-
dummy_mask_idx = sequence_length - 1
|
| 203 |
-
else:
|
| 204 |
-
dummy_mask_idx = spec_aug_mask_idx[0]
|
| 205 |
-
|
| 206 |
-
spec_aug_mask_idx = np.concatenate(
|
| 207 |
-
[spec_aug_mask_idx, np.ones(max_num_masked_span - num_masked_span, dtype=np.int32) * dummy_mask_idx]
|
| 208 |
-
)
|
| 209 |
-
spec_aug_mask_idxs.append(spec_aug_mask_idx)
|
| 210 |
-
|
| 211 |
-
spec_aug_mask_idxs = np.array(spec_aug_mask_idxs)
|
| 212 |
-
|
| 213 |
-
# expand masked indices to masked spans
|
| 214 |
-
spec_aug_mask_idxs = np.broadcast_to(
|
| 215 |
-
spec_aug_mask_idxs[:, :, None], (batch_size, max_num_masked_span, mask_length)
|
| 216 |
-
)
|
| 217 |
-
spec_aug_mask_idxs = spec_aug_mask_idxs.reshape(batch_size, max_num_masked_span * mask_length)
|
| 218 |
-
|
| 219 |
-
# add offset to the starting indexes so that indexes now create a span
|
| 220 |
-
offsets = np.arange(mask_length)[None, None, :]
|
| 221 |
-
offsets = np.broadcast_to(offsets, (batch_size, max_num_masked_span, mask_length)).reshape(
|
| 222 |
-
batch_size, max_num_masked_span * mask_length
|
| 223 |
-
)
|
| 224 |
-
spec_aug_mask_idxs = spec_aug_mask_idxs + offsets
|
| 225 |
-
|
| 226 |
-
# ensure that we cannot have indices larger than sequence_length
|
| 227 |
-
if spec_aug_mask_idxs.max() > sequence_length - 1:
|
| 228 |
-
spec_aug_mask_idxs[spec_aug_mask_idxs > sequence_length - 1] = sequence_length - 1
|
| 229 |
-
|
| 230 |
-
# scatter indices to mask
|
| 231 |
-
np.put_along_axis(spec_aug_mask, spec_aug_mask_idxs, 1, -1)
|
| 232 |
-
|
| 233 |
-
return spec_aug_mask
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2._sample_negative_indices
|
| 237 |
-
def _sample_negative_indices(
|
| 238 |
-
features_shape: Tuple, num_negatives: int, mask_time_indices: Optional[np.ndarray] = None
|
| 239 |
-
):
|
| 240 |
-
"""
|
| 241 |
-
Sample `num_negatives` vectors from feature vectors.
|
| 242 |
-
"""
|
| 243 |
-
batch_size, sequence_length = features_shape
|
| 244 |
-
|
| 245 |
-
# generate indices of the positive vectors themselves, repeat them `num_negatives` times
|
| 246 |
-
sequence_length_range = np.arange(sequence_length)
|
| 247 |
-
|
| 248 |
-
# get `num_negatives` random vector indices from the same utterance
|
| 249 |
-
sampled_negative_indices = np.zeros(shape=(batch_size, sequence_length, num_negatives), dtype=np.int32)
|
| 250 |
-
|
| 251 |
-
mask_time_indices = (
|
| 252 |
-
mask_time_indices.astype(bool) if mask_time_indices is not None else np.ones(features_shape, dtype=bool)
|
| 253 |
-
)
|
| 254 |
-
|
| 255 |
-
for batch_idx in range(batch_size):
|
| 256 |
-
high = mask_time_indices[batch_idx].sum() - 1
|
| 257 |
-
mapped_masked_indices = sequence_length_range[mask_time_indices[batch_idx]]
|
| 258 |
-
|
| 259 |
-
feature_indices = np.broadcast_to(np.arange(high + 1)[:, None], (high + 1, num_negatives))
|
| 260 |
-
sampled_indices = np.random.randint(0, high, size=(high + 1, num_negatives))
|
| 261 |
-
# avoid sampling the same positive vector, but keep the distribution uniform
|
| 262 |
-
sampled_indices[sampled_indices >= feature_indices] += 1
|
| 263 |
-
|
| 264 |
-
# remap to actual indices
|
| 265 |
-
sampled_negative_indices[batch_idx][mask_time_indices[batch_idx]] = mapped_masked_indices[sampled_indices]
|
| 266 |
-
|
| 267 |
-
# correct for batch size
|
| 268 |
-
sampled_negative_indices[batch_idx] += batch_idx * sequence_length
|
| 269 |
-
|
| 270 |
-
return sampled_negative_indices
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2NoLayerNormConvLayer with Wav2Vec2->Wav2Vec2Conformer
|
| 274 |
-
class Wav2Vec2ConformerNoLayerNormConvLayer(nn.Module):
|
| 275 |
-
def __init__(self, config, layer_id=0):
|
| 276 |
-
super().__init__()
|
| 277 |
-
self.in_conv_dim = config.conv_dim[layer_id - 1] if layer_id > 0 else 1
|
| 278 |
-
self.out_conv_dim = config.conv_dim[layer_id]
|
| 279 |
-
|
| 280 |
-
self.conv = nn.Conv1d(
|
| 281 |
-
self.in_conv_dim,
|
| 282 |
-
self.out_conv_dim,
|
| 283 |
-
kernel_size=config.conv_kernel[layer_id],
|
| 284 |
-
stride=config.conv_stride[layer_id],
|
| 285 |
-
bias=config.conv_bias,
|
| 286 |
-
)
|
| 287 |
-
self.activation = ACT2FN[config.feat_extract_activation]
|
| 288 |
-
|
| 289 |
-
def forward(self, hidden_states):
|
| 290 |
-
hidden_states = self.conv(hidden_states)
|
| 291 |
-
hidden_states = self.activation(hidden_states)
|
| 292 |
-
return hidden_states
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2LayerNormConvLayer with Wav2Vec2->Wav2Vec2Conformer
|
| 296 |
-
class Wav2Vec2ConformerLayerNormConvLayer(nn.Module):
|
| 297 |
-
def __init__(self, config, layer_id=0):
|
| 298 |
-
super().__init__()
|
| 299 |
-
self.in_conv_dim = config.conv_dim[layer_id - 1] if layer_id > 0 else 1
|
| 300 |
-
self.out_conv_dim = config.conv_dim[layer_id]
|
| 301 |
-
|
| 302 |
-
self.conv = nn.Conv1d(
|
| 303 |
-
self.in_conv_dim,
|
| 304 |
-
self.out_conv_dim,
|
| 305 |
-
kernel_size=config.conv_kernel[layer_id],
|
| 306 |
-
stride=config.conv_stride[layer_id],
|
| 307 |
-
bias=config.conv_bias,
|
| 308 |
-
)
|
| 309 |
-
self.layer_norm = nn.LayerNorm(self.out_conv_dim, elementwise_affine=True)
|
| 310 |
-
self.activation = ACT2FN[config.feat_extract_activation]
|
| 311 |
-
|
| 312 |
-
def forward(self, hidden_states):
|
| 313 |
-
hidden_states = self.conv(hidden_states)
|
| 314 |
-
|
| 315 |
-
hidden_states = hidden_states.transpose(-2, -1)
|
| 316 |
-
hidden_states = self.layer_norm(hidden_states)
|
| 317 |
-
hidden_states = hidden_states.transpose(-2, -1)
|
| 318 |
-
|
| 319 |
-
hidden_states = self.activation(hidden_states)
|
| 320 |
-
return hidden_states
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2GroupNormConvLayer with Wav2Vec2->Wav2Vec2Conformer
|
| 324 |
-
class Wav2Vec2ConformerGroupNormConvLayer(nn.Module):
|
| 325 |
-
def __init__(self, config, layer_id=0):
|
| 326 |
-
super().__init__()
|
| 327 |
-
self.in_conv_dim = config.conv_dim[layer_id - 1] if layer_id > 0 else 1
|
| 328 |
-
self.out_conv_dim = config.conv_dim[layer_id]
|
| 329 |
-
|
| 330 |
-
self.conv = nn.Conv1d(
|
| 331 |
-
self.in_conv_dim,
|
| 332 |
-
self.out_conv_dim,
|
| 333 |
-
kernel_size=config.conv_kernel[layer_id],
|
| 334 |
-
stride=config.conv_stride[layer_id],
|
| 335 |
-
bias=config.conv_bias,
|
| 336 |
-
)
|
| 337 |
-
self.activation = ACT2FN[config.feat_extract_activation]
|
| 338 |
-
|
| 339 |
-
self.layer_norm = nn.GroupNorm(num_groups=self.out_conv_dim, num_channels=self.out_conv_dim, affine=True)
|
| 340 |
-
|
| 341 |
-
def forward(self, hidden_states):
|
| 342 |
-
hidden_states = self.conv(hidden_states)
|
| 343 |
-
hidden_states = self.layer_norm(hidden_states)
|
| 344 |
-
hidden_states = self.activation(hidden_states)
|
| 345 |
-
return hidden_states
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2PositionalConvEmbedding with Wav2Vec2->Wav2Vec2Conformer
|
| 349 |
-
class Wav2Vec2ConformerPositionalConvEmbedding(nn.Module):
|
| 350 |
-
def __init__(self, config):
|
| 351 |
-
super().__init__()
|
| 352 |
-
self.conv = nn.Conv1d(
|
| 353 |
-
config.hidden_size,
|
| 354 |
-
config.hidden_size,
|
| 355 |
-
kernel_size=config.num_conv_pos_embeddings,
|
| 356 |
-
padding=config.num_conv_pos_embeddings // 2,
|
| 357 |
-
groups=config.num_conv_pos_embedding_groups,
|
| 358 |
-
)
|
| 359 |
-
|
| 360 |
-
if is_deepspeed_zero3_enabled():
|
| 361 |
-
import deepspeed
|
| 362 |
-
|
| 363 |
-
with deepspeed.zero.GatheredParameters(self.conv.weight, modifier_rank=0):
|
| 364 |
-
self.conv = nn.utils.weight_norm(self.conv, name="weight", dim=2)
|
| 365 |
-
deepspeed.zero.register_external_parameter(self, self.conv.weight_v)
|
| 366 |
-
deepspeed.zero.register_external_parameter(self, self.conv.weight_g)
|
| 367 |
-
else:
|
| 368 |
-
self.conv = nn.utils.weight_norm(self.conv, name="weight", dim=2)
|
| 369 |
-
|
| 370 |
-
self.padding = Wav2Vec2ConformerSamePadLayer(config.num_conv_pos_embeddings)
|
| 371 |
-
self.activation = ACT2FN[config.feat_extract_activation]
|
| 372 |
-
|
| 373 |
-
def forward(self, hidden_states):
|
| 374 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 375 |
-
|
| 376 |
-
hidden_states = self.conv(hidden_states)
|
| 377 |
-
hidden_states = self.padding(hidden_states)
|
| 378 |
-
hidden_states = self.activation(hidden_states)
|
| 379 |
-
|
| 380 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 381 |
-
return hidden_states
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
class Wav2Vec2ConformerRotaryPositionalEmbedding(nn.Module):
|
| 385 |
-
"""Rotary positional embedding
|
| 386 |
-
Reference : https://blog.eleuther.ai/rotary-embeddings/ Paper: https://arxiv.org/pdf/2104.09864.pdf
|
| 387 |
-
"""
|
| 388 |
-
|
| 389 |
-
def __init__(self, config):
|
| 390 |
-
super().__init__()
|
| 391 |
-
dim = config.hidden_size // config.num_attention_heads
|
| 392 |
-
base = config.rotary_embedding_base
|
| 393 |
-
|
| 394 |
-
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
|
| 395 |
-
self.register_buffer("inv_freq", inv_freq)
|
| 396 |
-
self.cached_sequence_length = None
|
| 397 |
-
self.cached_rotary_positional_embedding = None
|
| 398 |
-
|
| 399 |
-
def forward(self, hidden_states):
|
| 400 |
-
sequence_length = hidden_states.shape[1]
|
| 401 |
-
|
| 402 |
-
if sequence_length == self.cached_sequence_length and self.cached_rotary_positional_embedding is not None:
|
| 403 |
-
return self.cached_rotary_positional_embedding
|
| 404 |
-
|
| 405 |
-
self.cached_sequence_length = sequence_length
|
| 406 |
-
time_stamps = torch.arange(sequence_length).type_as(self.inv_freq)
|
| 407 |
-
freqs = torch.einsum("i,j->ij", time_stamps, self.inv_freq)
|
| 408 |
-
embeddings = torch.cat((freqs, freqs), dim=-1)
|
| 409 |
-
|
| 410 |
-
cos_embeddings = embeddings.cos()[:, None, None, :]
|
| 411 |
-
sin_embeddings = embeddings.sin()[:, None, None, :]
|
| 412 |
-
self.cached_rotary_positional_embedding = torch.stack([cos_embeddings, sin_embeddings])
|
| 413 |
-
return self.cached_rotary_positional_embedding
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
class Wav2Vec2ConformerRelPositionalEmbedding(nn.Module):
|
| 417 |
-
"""Relative positional encoding module."""
|
| 418 |
-
|
| 419 |
-
def __init__(self, config):
|
| 420 |
-
super().__init__()
|
| 421 |
-
self.max_len = config.max_source_positions
|
| 422 |
-
self.d_model = config.hidden_size
|
| 423 |
-
self.pe = None
|
| 424 |
-
self.extend_pe(torch.tensor(0.0).expand(1, self.max_len))
|
| 425 |
-
|
| 426 |
-
def extend_pe(self, x):
|
| 427 |
-
# Reset the positional encodings
|
| 428 |
-
if self.pe is not None:
|
| 429 |
-
# self.pe contains both positive and negative parts
|
| 430 |
-
# the length of self.pe is 2 * input_len - 1
|
| 431 |
-
if self.pe.size(1) >= x.size(1) * 2 - 1:
|
| 432 |
-
if self.pe.dtype != x.dtype or self.pe.device != x.device:
|
| 433 |
-
self.pe = self.pe.to(dtype=x.dtype, device=x.device)
|
| 434 |
-
return
|
| 435 |
-
# Suppose `i` is the position of query vector and `j` is the
|
| 436 |
-
# position of key vector. We use positive relative positions when keys
|
| 437 |
-
# are to the left (i>j) and negative relative positions otherwise (i<j).
|
| 438 |
-
pe_positive = torch.zeros(x.size(1), self.d_model)
|
| 439 |
-
pe_negative = torch.zeros(x.size(1), self.d_model)
|
| 440 |
-
position = torch.arange(0, x.size(1), dtype=torch.float32).unsqueeze(1)
|
| 441 |
-
div_term = torch.exp(
|
| 442 |
-
torch.arange(0, self.d_model, 2, dtype=torch.float32) * -(math.log(10000.0) / self.d_model)
|
| 443 |
-
)
|
| 444 |
-
pe_positive[:, 0::2] = torch.sin(position * div_term)
|
| 445 |
-
pe_positive[:, 1::2] = torch.cos(position * div_term)
|
| 446 |
-
pe_negative[:, 0::2] = torch.sin(-1 * position * div_term)
|
| 447 |
-
pe_negative[:, 1::2] = torch.cos(-1 * position * div_term)
|
| 448 |
-
|
| 449 |
-
# Reverse the order of positive indices and concat both positive and
|
| 450 |
-
# negative indices. This is used to support the shifting trick
|
| 451 |
-
# as in https://arxiv.org/abs/1901.02860
|
| 452 |
-
pe_positive = torch.flip(pe_positive, [0]).unsqueeze(0)
|
| 453 |
-
pe_negative = pe_negative[1:].unsqueeze(0)
|
| 454 |
-
pe = torch.cat([pe_positive, pe_negative], dim=1)
|
| 455 |
-
self.pe = pe.to(device=x.device, dtype=x.dtype)
|
| 456 |
-
|
| 457 |
-
def forward(self, hidden_states: torch.Tensor):
|
| 458 |
-
self.extend_pe(hidden_states)
|
| 459 |
-
start_idx = self.pe.size(1) // 2 - hidden_states.size(1) + 1
|
| 460 |
-
end_idx = self.pe.size(1) // 2 + hidden_states.size(1)
|
| 461 |
-
relative_position_embeddings = self.pe[:, start_idx:end_idx]
|
| 462 |
-
|
| 463 |
-
return relative_position_embeddings
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2SamePadLayer with Wav2Vec2->Wav2Vec2Conformer
|
| 467 |
-
class Wav2Vec2ConformerSamePadLayer(nn.Module):
|
| 468 |
-
def __init__(self, num_conv_pos_embeddings):
|
| 469 |
-
super().__init__()
|
| 470 |
-
self.num_pad_remove = 1 if num_conv_pos_embeddings % 2 == 0 else 0
|
| 471 |
-
|
| 472 |
-
def forward(self, hidden_states):
|
| 473 |
-
if self.num_pad_remove > 0:
|
| 474 |
-
hidden_states = hidden_states[:, :, : -self.num_pad_remove]
|
| 475 |
-
return hidden_states
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2FeatureEncoder with Wav2Vec2->Wav2Vec2Conformer
|
| 479 |
-
class Wav2Vec2ConformerFeatureEncoder(nn.Module):
|
| 480 |
-
"""Construct the features from raw audio waveform"""
|
| 481 |
-
|
| 482 |
-
def __init__(self, config):
|
| 483 |
-
super().__init__()
|
| 484 |
-
|
| 485 |
-
if config.feat_extract_norm == "group":
|
| 486 |
-
conv_layers = [Wav2Vec2ConformerGroupNormConvLayer(config, layer_id=0)] + [
|
| 487 |
-
Wav2Vec2ConformerNoLayerNormConvLayer(config, layer_id=i + 1)
|
| 488 |
-
for i in range(config.num_feat_extract_layers - 1)
|
| 489 |
-
]
|
| 490 |
-
elif config.feat_extract_norm == "layer":
|
| 491 |
-
conv_layers = [
|
| 492 |
-
Wav2Vec2ConformerLayerNormConvLayer(config, layer_id=i) for i in range(config.num_feat_extract_layers)
|
| 493 |
-
]
|
| 494 |
-
else:
|
| 495 |
-
raise ValueError(
|
| 496 |
-
f"`config.feat_extract_norm` is {config.feat_extract_norm}, but has to be one of ['group', 'layer']"
|
| 497 |
-
)
|
| 498 |
-
self.conv_layers = nn.ModuleList(conv_layers)
|
| 499 |
-
self.gradient_checkpointing = False
|
| 500 |
-
self._requires_grad = True
|
| 501 |
-
|
| 502 |
-
def _freeze_parameters(self):
|
| 503 |
-
for param in self.parameters():
|
| 504 |
-
param.requires_grad = False
|
| 505 |
-
self._requires_grad = False
|
| 506 |
-
|
| 507 |
-
def forward(self, input_values):
|
| 508 |
-
hidden_states = input_values[:, None]
|
| 509 |
-
|
| 510 |
-
# make sure hidden_states require grad for gradient_checkpointing
|
| 511 |
-
if self._requires_grad and self.training:
|
| 512 |
-
hidden_states.requires_grad = True
|
| 513 |
-
|
| 514 |
-
for conv_layer in self.conv_layers:
|
| 515 |
-
if self._requires_grad and self.gradient_checkpointing and self.training:
|
| 516 |
-
|
| 517 |
-
def create_custom_forward(module):
|
| 518 |
-
def custom_forward(*inputs):
|
| 519 |
-
return module(*inputs)
|
| 520 |
-
|
| 521 |
-
return custom_forward
|
| 522 |
-
|
| 523 |
-
hidden_states = torch.utils.checkpoint.checkpoint(
|
| 524 |
-
create_custom_forward(conv_layer),
|
| 525 |
-
hidden_states,
|
| 526 |
-
)
|
| 527 |
-
else:
|
| 528 |
-
hidden_states = conv_layer(hidden_states)
|
| 529 |
-
|
| 530 |
-
return hidden_states
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2FeatureProjection with Wav2Vec2->Wav2Vec2Conformer
|
| 534 |
-
class Wav2Vec2ConformerFeatureProjection(nn.Module):
|
| 535 |
-
def __init__(self, config):
|
| 536 |
-
super().__init__()
|
| 537 |
-
self.layer_norm = nn.LayerNorm(config.conv_dim[-1], eps=config.layer_norm_eps)
|
| 538 |
-
self.projection = nn.Linear(config.conv_dim[-1], config.hidden_size)
|
| 539 |
-
self.dropout = nn.Dropout(config.feat_proj_dropout)
|
| 540 |
-
|
| 541 |
-
def forward(self, hidden_states):
|
| 542 |
-
# non-projected hidden states are needed for quantization
|
| 543 |
-
norm_hidden_states = self.layer_norm(hidden_states)
|
| 544 |
-
hidden_states = self.projection(norm_hidden_states)
|
| 545 |
-
hidden_states = self.dropout(hidden_states)
|
| 546 |
-
return hidden_states, norm_hidden_states
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2FeedForward with Wav2Vec2->Wav2Vec2Conformer
|
| 550 |
-
class Wav2Vec2ConformerFeedForward(nn.Module):
|
| 551 |
-
def __init__(self, config):
|
| 552 |
-
super().__init__()
|
| 553 |
-
self.intermediate_dropout = nn.Dropout(config.activation_dropout)
|
| 554 |
-
|
| 555 |
-
self.intermediate_dense = nn.Linear(config.hidden_size, config.intermediate_size)
|
| 556 |
-
if isinstance(config.hidden_act, str):
|
| 557 |
-
self.intermediate_act_fn = ACT2FN[config.hidden_act]
|
| 558 |
-
else:
|
| 559 |
-
self.intermediate_act_fn = config.hidden_act
|
| 560 |
-
|
| 561 |
-
self.output_dense = nn.Linear(config.intermediate_size, config.hidden_size)
|
| 562 |
-
self.output_dropout = nn.Dropout(config.hidden_dropout)
|
| 563 |
-
|
| 564 |
-
def forward(self, hidden_states):
|
| 565 |
-
hidden_states = self.intermediate_dense(hidden_states)
|
| 566 |
-
hidden_states = self.intermediate_act_fn(hidden_states)
|
| 567 |
-
hidden_states = self.intermediate_dropout(hidden_states)
|
| 568 |
-
|
| 569 |
-
hidden_states = self.output_dense(hidden_states)
|
| 570 |
-
hidden_states = self.output_dropout(hidden_states)
|
| 571 |
-
return hidden_states
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
class Wav2Vec2ConformerConvolutionModule(nn.Module):
|
| 575 |
-
"""Convolution block used in the conformer block"""
|
| 576 |
-
|
| 577 |
-
def __init__(self, config):
|
| 578 |
-
super().__init__()
|
| 579 |
-
if (config.conv_depthwise_kernel_size - 1) % 2 == 1:
|
| 580 |
-
raise ValueError("`config.conv_depthwise_kernel_size` should be a odd number for 'SAME' padding")
|
| 581 |
-
self.layer_norm = nn.LayerNorm(config.hidden_size)
|
| 582 |
-
self.pointwise_conv1 = torch.nn.Conv1d(
|
| 583 |
-
config.hidden_size,
|
| 584 |
-
2 * config.hidden_size,
|
| 585 |
-
kernel_size=1,
|
| 586 |
-
stride=1,
|
| 587 |
-
padding=0,
|
| 588 |
-
bias=False,
|
| 589 |
-
)
|
| 590 |
-
self.glu = torch.nn.GLU(dim=1)
|
| 591 |
-
self.depthwise_conv = torch.nn.Conv1d(
|
| 592 |
-
config.hidden_size,
|
| 593 |
-
config.hidden_size,
|
| 594 |
-
config.conv_depthwise_kernel_size,
|
| 595 |
-
stride=1,
|
| 596 |
-
padding=(config.conv_depthwise_kernel_size - 1) // 2,
|
| 597 |
-
groups=config.hidden_size,
|
| 598 |
-
bias=False,
|
| 599 |
-
)
|
| 600 |
-
self.batch_norm = torch.nn.BatchNorm1d(config.hidden_size)
|
| 601 |
-
self.activation = ACT2FN[config.hidden_act]
|
| 602 |
-
self.pointwise_conv2 = torch.nn.Conv1d(
|
| 603 |
-
config.hidden_size,
|
| 604 |
-
config.hidden_size,
|
| 605 |
-
kernel_size=1,
|
| 606 |
-
stride=1,
|
| 607 |
-
padding=0,
|
| 608 |
-
bias=False,
|
| 609 |
-
)
|
| 610 |
-
self.dropout = torch.nn.Dropout(config.conformer_conv_dropout)
|
| 611 |
-
|
| 612 |
-
def forward(self, hidden_states):
|
| 613 |
-
hidden_states = self.layer_norm(hidden_states)
|
| 614 |
-
# exchange the temporal dimension and the feature dimension
|
| 615 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 616 |
-
|
| 617 |
-
# GLU mechanism
|
| 618 |
-
# => (batch, 2*channel, dim)
|
| 619 |
-
hidden_states = self.pointwise_conv1(hidden_states)
|
| 620 |
-
# => (batch, channel, dim)
|
| 621 |
-
hidden_states = self.glu(hidden_states)
|
| 622 |
-
|
| 623 |
-
# 1D Depthwise Conv
|
| 624 |
-
hidden_states = self.depthwise_conv(hidden_states)
|
| 625 |
-
hidden_states = self.batch_norm(hidden_states)
|
| 626 |
-
hidden_states = self.activation(hidden_states)
|
| 627 |
-
|
| 628 |
-
hidden_states = self.pointwise_conv2(hidden_states)
|
| 629 |
-
hidden_states = self.dropout(hidden_states)
|
| 630 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 631 |
-
return hidden_states
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
class Wav2Vec2ConformerSelfAttention(nn.Module):
|
| 635 |
-
"""Construct an Wav2Vec2ConformerSelfAttention object.
|
| 636 |
-
Can be enhanced with rotary or relative position embeddings.
|
| 637 |
-
"""
|
| 638 |
-
|
| 639 |
-
def __init__(self, config):
|
| 640 |
-
super().__init__()
|
| 641 |
-
|
| 642 |
-
self.head_size = config.hidden_size // config.num_attention_heads
|
| 643 |
-
self.num_heads = config.num_attention_heads
|
| 644 |
-
self.position_embeddings_type = config.position_embeddings_type
|
| 645 |
-
|
| 646 |
-
self.linear_q = nn.Linear(config.hidden_size, config.hidden_size)
|
| 647 |
-
self.linear_k = nn.Linear(config.hidden_size, config.hidden_size)
|
| 648 |
-
self.linear_v = nn.Linear(config.hidden_size, config.hidden_size)
|
| 649 |
-
self.linear_out = nn.Linear(config.hidden_size, config.hidden_size)
|
| 650 |
-
|
| 651 |
-
self.dropout = nn.Dropout(p=config.attention_dropout)
|
| 652 |
-
self.dropout_p = config.attention_dropout
|
| 653 |
-
|
| 654 |
-
self.is_causal = config.is_causal
|
| 655 |
-
|
| 656 |
-
if self.position_embeddings_type == "relative":
|
| 657 |
-
# linear transformation for positional encoding
|
| 658 |
-
self.linear_pos = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 659 |
-
# these two learnable bias are used in matrix c and matrix d
|
| 660 |
-
# as described in https://arxiv.org/abs/1901.02860 Section 3.3
|
| 661 |
-
self.pos_bias_u = nn.Parameter(torch.zeros(self.num_heads, self.head_size))
|
| 662 |
-
self.pos_bias_v = nn.Parameter(torch.zeros(self.num_heads, self.head_size))
|
| 663 |
-
|
| 664 |
-
def forward(
|
| 665 |
-
self,
|
| 666 |
-
hidden_states: torch.Tensor,
|
| 667 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 668 |
-
relative_position_embeddings: Optional[torch.Tensor] = None,
|
| 669 |
-
output_attentions: bool = False,
|
| 670 |
-
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 671 |
-
# self-attention mechanism
|
| 672 |
-
batch_size, sequence_length, hidden_size = hidden_states.size()
|
| 673 |
-
|
| 674 |
-
# make sure query/key states can be != value states
|
| 675 |
-
query_key_states = hidden_states
|
| 676 |
-
value_states = hidden_states
|
| 677 |
-
|
| 678 |
-
if self.position_embeddings_type == "rotary":
|
| 679 |
-
if relative_position_embeddings is None:
|
| 680 |
-
raise ValueError(
|
| 681 |
-
"`relative_position_embeddings` has to be defined when `self.position_embeddings_type == 'rotary'"
|
| 682 |
-
)
|
| 683 |
-
query_key_states = self._apply_rotary_embedding(query_key_states, relative_position_embeddings)
|
| 684 |
-
|
| 685 |
-
# project query_key_states and value_states
|
| 686 |
-
query = self.linear_q(query_key_states).view(batch_size, -1, self.num_heads, self.head_size)
|
| 687 |
-
key = self.linear_k(query_key_states).view(batch_size, -1, self.num_heads, self.head_size)
|
| 688 |
-
value = self.linear_v(value_states).view(batch_size, -1, self.num_heads, self.head_size)
|
| 689 |
-
|
| 690 |
-
# => (batch, head, time1, d_k)
|
| 691 |
-
query = query.transpose(1, 2)
|
| 692 |
-
key = key.transpose(1, 2)
|
| 693 |
-
value = value.transpose(1, 2)
|
| 694 |
-
|
| 695 |
-
with torch.backends.cuda.sdp_kernel(enable_math=False, enable_flash=True, enable_mem_efficient=False):
|
| 696 |
-
hidden_states = F.scaled_dot_product_attention(query, key, value, attn_mask=attention_mask, dropout_p=self.dropout_p, is_causal=self.is_causal)
|
| 697 |
-
probs = None
|
| 698 |
-
|
| 699 |
-
# # apply attention_mask if necessary
|
| 700 |
-
# if attention_mask is not None:
|
| 701 |
-
# scores = scores + attention_mask
|
| 702 |
-
|
| 703 |
-
# # => (batch, head, time1, time2)
|
| 704 |
-
# probs = torch.softmax(scores, dim=-1)
|
| 705 |
-
# probs = self.dropout(probs)
|
| 706 |
-
|
| 707 |
-
# # => (batch, head, time1, d_k)
|
| 708 |
-
# hidden_states = torch.matmul(probs, value)
|
| 709 |
-
|
| 710 |
-
# => (batch, time1, hidden_size)
|
| 711 |
-
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, self.num_heads * self.head_size)
|
| 712 |
-
hidden_states = self.linear_out(hidden_states)
|
| 713 |
-
|
| 714 |
-
return hidden_states, probs
|
| 715 |
-
|
| 716 |
-
def _apply_rotary_embedding(self, hidden_states, relative_position_embeddings):
|
| 717 |
-
batch_size, sequence_length, hidden_size = hidden_states.size()
|
| 718 |
-
hidden_states = hidden_states.view(batch_size, sequence_length, self.num_heads, self.head_size)
|
| 719 |
-
|
| 720 |
-
cos = relative_position_embeddings[0, :sequence_length, ...]
|
| 721 |
-
sin = relative_position_embeddings[1, :sequence_length, ...]
|
| 722 |
-
|
| 723 |
-
# rotate hidden_states with rotary embeddings
|
| 724 |
-
hidden_states = hidden_states.transpose(0, 1)
|
| 725 |
-
rotated_states_begin = hidden_states[..., : self.head_size // 2]
|
| 726 |
-
rotated_states_end = hidden_states[..., self.head_size // 2 :]
|
| 727 |
-
rotated_states = torch.cat((-rotated_states_end, rotated_states_begin), dim=rotated_states_begin.ndim - 1)
|
| 728 |
-
hidden_states = (hidden_states * cos) + (rotated_states * sin)
|
| 729 |
-
hidden_states = hidden_states.transpose(0, 1)
|
| 730 |
-
|
| 731 |
-
hidden_states = hidden_states.view(batch_size, sequence_length, self.num_heads * self.head_size)
|
| 732 |
-
|
| 733 |
-
return hidden_states
|
| 734 |
-
|
| 735 |
-
def _apply_relative_embeddings(self, query, key, relative_position_embeddings):
|
| 736 |
-
# 1. project positional embeddings
|
| 737 |
-
# => (batch, head, 2*time1-1, d_k)
|
| 738 |
-
proj_relative_position_embeddings = self.linear_pos(relative_position_embeddings)
|
| 739 |
-
proj_relative_position_embeddings = proj_relative_position_embeddings.view(
|
| 740 |
-
relative_position_embeddings.size(0), -1, self.num_heads, self.head_size
|
| 741 |
-
)
|
| 742 |
-
proj_relative_position_embeddings = proj_relative_position_embeddings.transpose(1, 2)
|
| 743 |
-
proj_relative_position_embeddings = proj_relative_position_embeddings.transpose(2, 3)
|
| 744 |
-
|
| 745 |
-
# 2. Add bias to query
|
| 746 |
-
# => (batch, head, time1, d_k)
|
| 747 |
-
query = query.transpose(1, 2)
|
| 748 |
-
q_with_bias_u = (query + self.pos_bias_u).transpose(1, 2)
|
| 749 |
-
q_with_bias_v = (query + self.pos_bias_v).transpose(1, 2)
|
| 750 |
-
|
| 751 |
-
# 3. attention score: first compute matrix a and matrix c
|
| 752 |
-
# as described in https://arxiv.org/abs/1901.02860 Section 3.3
|
| 753 |
-
# => (batch, head, time1, time2)
|
| 754 |
-
scores_ac = torch.matmul(q_with_bias_u, key.transpose(-2, -1))
|
| 755 |
-
|
| 756 |
-
# 4. then compute matrix b and matrix d
|
| 757 |
-
# => (batch, head, time1, 2*time1-1)
|
| 758 |
-
scores_bd = torch.matmul(q_with_bias_v, proj_relative_position_embeddings)
|
| 759 |
-
|
| 760 |
-
# 5. shift matrix b and matrix d
|
| 761 |
-
zero_pad = torch.zeros((*scores_bd.size()[:3], 1), device=scores_bd.device, dtype=scores_bd.dtype)
|
| 762 |
-
scores_bd_padded = torch.cat([zero_pad, scores_bd], dim=-1)
|
| 763 |
-
scores_bd_padded_shape = scores_bd.size()[:2] + (scores_bd.shape[3] + 1, scores_bd.shape[2])
|
| 764 |
-
scores_bd_padded = scores_bd_padded.view(*scores_bd_padded_shape)
|
| 765 |
-
scores_bd = scores_bd_padded[:, :, 1:].view_as(scores_bd)
|
| 766 |
-
scores_bd = scores_bd[:, :, :, : scores_bd.size(-1) // 2 + 1]
|
| 767 |
-
|
| 768 |
-
# 6. sum matrices
|
| 769 |
-
# => (batch, head, time1, time2)
|
| 770 |
-
scores = (scores_ac + scores_bd) / math.sqrt(self.head_size)
|
| 771 |
-
|
| 772 |
-
return scores
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
class Wav2Vec2ConformerEncoderLayer(nn.Module):
|
| 776 |
-
"""Conformer block based on https://arxiv.org/abs/2005.08100."""
|
| 777 |
-
|
| 778 |
-
def __init__(self, config):
|
| 779 |
-
super().__init__()
|
| 780 |
-
embed_dim = config.hidden_size
|
| 781 |
-
dropout = config.attention_dropout
|
| 782 |
-
|
| 783 |
-
# Feed-forward 1
|
| 784 |
-
self.ffn1_layer_norm = nn.LayerNorm(embed_dim)
|
| 785 |
-
self.ffn1 = Wav2Vec2ConformerFeedForward(config)
|
| 786 |
-
|
| 787 |
-
# Self-Attention
|
| 788 |
-
self.self_attn_layer_norm = nn.LayerNorm(embed_dim)
|
| 789 |
-
self.self_attn_dropout = torch.nn.Dropout(dropout)
|
| 790 |
-
self.self_attn = Wav2Vec2ConformerSelfAttention(config)
|
| 791 |
-
|
| 792 |
-
# Conformer Convolution
|
| 793 |
-
self.conv_module = Wav2Vec2ConformerConvolutionModule(config)
|
| 794 |
-
|
| 795 |
-
# Feed-forward 2
|
| 796 |
-
self.ffn2_layer_norm = nn.LayerNorm(embed_dim)
|
| 797 |
-
self.ffn2 = Wav2Vec2ConformerFeedForward(config)
|
| 798 |
-
self.final_layer_norm = nn.LayerNorm(embed_dim)
|
| 799 |
-
|
| 800 |
-
def forward(
|
| 801 |
-
self,
|
| 802 |
-
hidden_states,
|
| 803 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 804 |
-
relative_position_embeddings: Optional[torch.Tensor] = None,
|
| 805 |
-
output_attentions: bool = False,
|
| 806 |
-
):
|
| 807 |
-
hidden_states = hidden_states
|
| 808 |
-
|
| 809 |
-
# 1. Feed-Forward 1 layer
|
| 810 |
-
residual = hidden_states
|
| 811 |
-
hidden_states = self.ffn1_layer_norm(hidden_states)
|
| 812 |
-
hidden_states = self.ffn1(hidden_states)
|
| 813 |
-
hidden_states = hidden_states * 0.5 + residual
|
| 814 |
-
residual = hidden_states
|
| 815 |
-
|
| 816 |
-
# 2. Self-Attention layer
|
| 817 |
-
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 818 |
-
hidden_states, attn_weigts = self.self_attn(
|
| 819 |
-
hidden_states=hidden_states,
|
| 820 |
-
attention_mask=attention_mask,
|
| 821 |
-
relative_position_embeddings=relative_position_embeddings,
|
| 822 |
-
output_attentions=output_attentions,
|
| 823 |
-
)
|
| 824 |
-
hidden_states = self.self_attn_dropout(hidden_states)
|
| 825 |
-
hidden_states = hidden_states + residual
|
| 826 |
-
|
| 827 |
-
# 3. Convolutional Layer
|
| 828 |
-
residual = hidden_states
|
| 829 |
-
hidden_states = self.conv_module(hidden_states)
|
| 830 |
-
hidden_states = residual + hidden_states
|
| 831 |
-
|
| 832 |
-
# 4. Feed-Forward 2 Layer
|
| 833 |
-
residual = hidden_states
|
| 834 |
-
hidden_states = self.ffn2_layer_norm(hidden_states)
|
| 835 |
-
hidden_states = self.ffn2(hidden_states)
|
| 836 |
-
hidden_states = hidden_states * 0.5 + residual
|
| 837 |
-
hidden_states = self.final_layer_norm(hidden_states)
|
| 838 |
-
|
| 839 |
-
return hidden_states, attn_weigts
|
| 840 |
-
|
| 841 |
-
|
| 842 |
-
class Wav2Vec2ConformerEncoder(nn.Module):
|
| 843 |
-
def __init__(self, config, is_causal=False):
|
| 844 |
-
super().__init__()
|
| 845 |
-
config.is_causal = is_causal
|
| 846 |
-
self.config = config
|
| 847 |
-
|
| 848 |
-
if config.position_embeddings_type == "relative":
|
| 849 |
-
self.embed_positions = Wav2Vec2ConformerRelPositionalEmbedding(config)
|
| 850 |
-
elif config.position_embeddings_type == "rotary":
|
| 851 |
-
self.embed_positions = Wav2Vec2ConformerRotaryPositionalEmbedding(config)
|
| 852 |
-
else:
|
| 853 |
-
self.embed_positions = None
|
| 854 |
-
|
| 855 |
-
self.pos_conv_embed = Wav2Vec2ConformerPositionalConvEmbedding(config)
|
| 856 |
-
self.layer_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 857 |
-
self.dropout = nn.Dropout(config.hidden_dropout)
|
| 858 |
-
self.layers = nn.ModuleList([Wav2Vec2ConformerEncoderLayer(config) for _ in range(config.num_hidden_layers)])
|
| 859 |
-
self.gradient_checkpointing = False
|
| 860 |
-
|
| 861 |
-
def forward(
|
| 862 |
-
self,
|
| 863 |
-
hidden_states,
|
| 864 |
-
attention_mask=None,
|
| 865 |
-
output_attentions=False,
|
| 866 |
-
output_hidden_states=False,
|
| 867 |
-
return_dict=True,
|
| 868 |
-
):
|
| 869 |
-
all_hidden_states = () if output_hidden_states else None
|
| 870 |
-
all_self_attentions = () if output_attentions else None
|
| 871 |
-
|
| 872 |
-
if attention_mask is not None:
|
| 873 |
-
# make sure padded tokens output 0
|
| 874 |
-
hidden_states[~attention_mask] = 0.0
|
| 875 |
-
|
| 876 |
-
# extend attention_mask
|
| 877 |
-
attention_mask = 1.0 - attention_mask[:, None, None, :].to(dtype=hidden_states.dtype)
|
| 878 |
-
attention_mask = attention_mask * torch.finfo(hidden_states.dtype).min
|
| 879 |
-
attention_mask = attention_mask.expand(
|
| 880 |
-
attention_mask.shape[0], 1, attention_mask.shape[-1], attention_mask.shape[-1]
|
| 881 |
-
)
|
| 882 |
-
|
| 883 |
-
hidden_states = self.dropout(hidden_states)
|
| 884 |
-
|
| 885 |
-
if self.embed_positions is not None:
|
| 886 |
-
relative_position_embeddings = self.embed_positions(hidden_states)
|
| 887 |
-
else:
|
| 888 |
-
relative_position_embeddings = None
|
| 889 |
-
|
| 890 |
-
deepspeed_zero3_is_enabled = is_deepspeed_zero3_enabled()
|
| 891 |
-
|
| 892 |
-
for i, layer in enumerate(self.layers):
|
| 893 |
-
if output_hidden_states:
|
| 894 |
-
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 895 |
-
|
| 896 |
-
# add LayerDrop (see https://arxiv.org/abs/1909.11556 for description)
|
| 897 |
-
dropout_probability = np.random.uniform(0, 1)
|
| 898 |
-
|
| 899 |
-
skip_the_layer = True if self.training and (dropout_probability < self.config.layerdrop) else False
|
| 900 |
-
if not skip_the_layer or deepspeed_zero3_is_enabled:
|
| 901 |
-
# under deepspeed zero3 all gpus must run in sync
|
| 902 |
-
if self.gradient_checkpointing and self.training:
|
| 903 |
-
# create gradient checkpointing function
|
| 904 |
-
def create_custom_forward(module):
|
| 905 |
-
def custom_forward(*inputs):
|
| 906 |
-
return module(*inputs, output_attentions)
|
| 907 |
-
|
| 908 |
-
return custom_forward
|
| 909 |
-
|
| 910 |
-
layer_outputs = torch.utils.checkpoint.checkpoint(
|
| 911 |
-
create_custom_forward(layer),
|
| 912 |
-
hidden_states,
|
| 913 |
-
attention_mask,
|
| 914 |
-
relative_position_embeddings,
|
| 915 |
-
)
|
| 916 |
-
else:
|
| 917 |
-
layer_outputs = layer(
|
| 918 |
-
hidden_states,
|
| 919 |
-
attention_mask=attention_mask,
|
| 920 |
-
relative_position_embeddings=relative_position_embeddings,
|
| 921 |
-
output_attentions=output_attentions,
|
| 922 |
-
)
|
| 923 |
-
hidden_states = layer_outputs[0]
|
| 924 |
-
|
| 925 |
-
if skip_the_layer:
|
| 926 |
-
layer_outputs = (None, None)
|
| 927 |
-
|
| 928 |
-
if output_attentions:
|
| 929 |
-
all_self_attentions = all_self_attentions + (layer_outputs[1],)
|
| 930 |
-
|
| 931 |
-
hidden_states = self.layer_norm(hidden_states)
|
| 932 |
-
if output_hidden_states:
|
| 933 |
-
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 934 |
-
|
| 935 |
-
if not return_dict:
|
| 936 |
-
return tuple(v for v in [hidden_states, all_hidden_states, all_self_attentions] if v is not None)
|
| 937 |
-
return BaseModelOutput(
|
| 938 |
-
last_hidden_state=hidden_states,
|
| 939 |
-
hidden_states=all_hidden_states,
|
| 940 |
-
attentions=all_self_attentions,
|
| 941 |
-
)
|
| 942 |
-
|
| 943 |
-
|
| 944 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2GumbelVectorQuantizer with Wav2Vec2->Wav2Vec2Conformer
|
| 945 |
-
class Wav2Vec2ConformerGumbelVectorQuantizer(nn.Module):
|
| 946 |
-
"""
|
| 947 |
-
Vector quantization using gumbel softmax. See `[CATEGORICAL REPARAMETERIZATION WITH
|
| 948 |
-
GUMBEL-SOFTMAX](https://arxiv.org/pdf/1611.01144.pdf) for more information.
|
| 949 |
-
"""
|
| 950 |
-
|
| 951 |
-
def __init__(self, config):
|
| 952 |
-
super().__init__()
|
| 953 |
-
self.num_groups = config.num_codevector_groups
|
| 954 |
-
self.num_vars = config.num_codevectors_per_group
|
| 955 |
-
|
| 956 |
-
if config.codevector_dim % self.num_groups != 0:
|
| 957 |
-
raise ValueError(
|
| 958 |
-
f"`config.codevector_dim {config.codevector_dim} must be divisible "
|
| 959 |
-
f"by `config.num_codevector_groups` {self.num_groups} for concatenation"
|
| 960 |
-
)
|
| 961 |
-
|
| 962 |
-
# storage for codebook variables (codewords)
|
| 963 |
-
self.codevectors = nn.Parameter(
|
| 964 |
-
torch.FloatTensor(1, self.num_groups * self.num_vars, config.codevector_dim // self.num_groups)
|
| 965 |
-
)
|
| 966 |
-
self.weight_proj = nn.Linear(config.conv_dim[-1], self.num_groups * self.num_vars)
|
| 967 |
-
|
| 968 |
-
# can be decayed for training
|
| 969 |
-
self.temperature = 2
|
| 970 |
-
|
| 971 |
-
@staticmethod
|
| 972 |
-
def _compute_perplexity(probs, mask=None):
|
| 973 |
-
if mask is not None:
|
| 974 |
-
mask_extended = mask.flatten()[:, None, None].expand(probs.shape)
|
| 975 |
-
probs = torch.where(mask_extended, probs, torch.zeros_like(probs))
|
| 976 |
-
marginal_probs = probs.sum(dim=0) / mask.sum()
|
| 977 |
-
else:
|
| 978 |
-
marginal_probs = probs.mean(dim=0)
|
| 979 |
-
|
| 980 |
-
perplexity = torch.exp(-torch.sum(marginal_probs * torch.log(marginal_probs + 1e-7), dim=-1)).sum()
|
| 981 |
-
return perplexity
|
| 982 |
-
|
| 983 |
-
def forward(self, hidden_states, mask_time_indices=None):
|
| 984 |
-
batch_size, sequence_length, hidden_size = hidden_states.shape
|
| 985 |
-
|
| 986 |
-
# project to codevector dim
|
| 987 |
-
hidden_states = self.weight_proj(hidden_states)
|
| 988 |
-
hidden_states = hidden_states.view(batch_size * sequence_length * self.num_groups, -1)
|
| 989 |
-
|
| 990 |
-
if self.training:
|
| 991 |
-
# sample code vector probs via gumbel in differentiateable way
|
| 992 |
-
codevector_probs = nn.functional.gumbel_softmax(
|
| 993 |
-
hidden_states.float(), tau=self.temperature, hard=True
|
| 994 |
-
).type_as(hidden_states)
|
| 995 |
-
|
| 996 |
-
# compute perplexity
|
| 997 |
-
codevector_soft_dist = torch.softmax(
|
| 998 |
-
hidden_states.view(batch_size * sequence_length, self.num_groups, -1).float(), dim=-1
|
| 999 |
-
)
|
| 1000 |
-
perplexity = self._compute_perplexity(codevector_soft_dist, mask_time_indices)
|
| 1001 |
-
else:
|
| 1002 |
-
# take argmax in non-differentiable way
|
| 1003 |
-
# comptute hard codevector distribution (one hot)
|
| 1004 |
-
codevector_idx = hidden_states.argmax(dim=-1)
|
| 1005 |
-
codevector_probs = hidden_states.new_zeros(hidden_states.shape).scatter_(
|
| 1006 |
-
-1, codevector_idx.view(-1, 1), 1.0
|
| 1007 |
-
)
|
| 1008 |
-
codevector_probs = codevector_probs.view(batch_size * sequence_length, self.num_groups, -1)
|
| 1009 |
-
|
| 1010 |
-
perplexity = self._compute_perplexity(codevector_probs, mask_time_indices)
|
| 1011 |
-
|
| 1012 |
-
codevector_probs = codevector_probs.view(batch_size * sequence_length, -1)
|
| 1013 |
-
# use probs to retrieve codevectors
|
| 1014 |
-
codevectors_per_group = codevector_probs.unsqueeze(-1) * self.codevectors
|
| 1015 |
-
codevectors = codevectors_per_group.view(batch_size * sequence_length, self.num_groups, self.num_vars, -1)
|
| 1016 |
-
codevectors = codevectors.sum(-2).view(batch_size, sequence_length, -1)
|
| 1017 |
-
|
| 1018 |
-
return codevectors, perplexity
|
| 1019 |
-
|
| 1020 |
-
|
| 1021 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2Adapter with Wav2Vec2->Wav2Vec2Conformer
|
| 1022 |
-
class Wav2Vec2ConformerAdapter(nn.Module):
|
| 1023 |
-
def __init__(self, config):
|
| 1024 |
-
super().__init__()
|
| 1025 |
-
|
| 1026 |
-
# feature dim might need to be down-projected
|
| 1027 |
-
if config.output_hidden_size != config.hidden_size:
|
| 1028 |
-
self.proj = nn.Linear(config.hidden_size, config.output_hidden_size)
|
| 1029 |
-
self.proj_layer_norm = nn.LayerNorm(config.output_hidden_size)
|
| 1030 |
-
else:
|
| 1031 |
-
self.proj = self.proj_layer_norm = None
|
| 1032 |
-
|
| 1033 |
-
self.layers = nn.ModuleList(Wav2Vec2ConformerAdapterLayer(config) for _ in range(config.num_adapter_layers))
|
| 1034 |
-
self.layerdrop = config.layerdrop
|
| 1035 |
-
|
| 1036 |
-
def forward(self, hidden_states):
|
| 1037 |
-
# down project hidden_states if necessary
|
| 1038 |
-
if self.proj is not None and self.proj_layer_norm is not None:
|
| 1039 |
-
hidden_states = self.proj(hidden_states)
|
| 1040 |
-
hidden_states = self.proj_layer_norm(hidden_states)
|
| 1041 |
-
|
| 1042 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 1043 |
-
|
| 1044 |
-
for layer in self.layers:
|
| 1045 |
-
layerdrop_prob = np.random.random()
|
| 1046 |
-
if not self.training or (layerdrop_prob > self.layerdrop):
|
| 1047 |
-
hidden_states = layer(hidden_states)
|
| 1048 |
-
|
| 1049 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 1050 |
-
return hidden_states
|
| 1051 |
-
|
| 1052 |
-
|
| 1053 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2AdapterLayer with Wav2Vec2->Wav2Vec2Conformer
|
| 1054 |
-
class Wav2Vec2ConformerAdapterLayer(nn.Module):
|
| 1055 |
-
def __init__(self, config):
|
| 1056 |
-
super().__init__()
|
| 1057 |
-
self.conv = nn.Conv1d(
|
| 1058 |
-
config.output_hidden_size,
|
| 1059 |
-
2 * config.output_hidden_size,
|
| 1060 |
-
config.adapter_kernel_size,
|
| 1061 |
-
stride=config.adapter_stride,
|
| 1062 |
-
padding=1,
|
| 1063 |
-
)
|
| 1064 |
-
|
| 1065 |
-
def forward(self, hidden_states):
|
| 1066 |
-
hidden_states = self.conv(hidden_states)
|
| 1067 |
-
hidden_states = nn.functional.glu(hidden_states, dim=1)
|
| 1068 |
-
|
| 1069 |
-
return hidden_states
|
| 1070 |
-
|
| 1071 |
-
|
| 1072 |
-
class Wav2Vec2ConformerPreTrainedModel(PreTrainedModel):
|
| 1073 |
-
"""
|
| 1074 |
-
An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
|
| 1075 |
-
models.
|
| 1076 |
-
"""
|
| 1077 |
-
|
| 1078 |
-
config_class = Wav2Vec2ConformerConfig
|
| 1079 |
-
base_model_prefix = "wav2vec2_conformer"
|
| 1080 |
-
main_input_name = "input_values"
|
| 1081 |
-
_keys_to_ignore_on_load_missing = [r"position_ids"]
|
| 1082 |
-
supports_gradient_checkpointing = True
|
| 1083 |
-
|
| 1084 |
-
def _init_weights(self, module):
|
| 1085 |
-
"""Initialize the weights"""
|
| 1086 |
-
# Wav2Vec2ForPreTraining last 2 linear layers need standard Linear init.
|
| 1087 |
-
if isinstance(module, Wav2Vec2ConformerForPreTraining):
|
| 1088 |
-
module.project_hid.reset_parameters()
|
| 1089 |
-
module.project_q.reset_parameters()
|
| 1090 |
-
module.project_hid._is_hf_initialized = True
|
| 1091 |
-
module.project_q._is_hf_initialized = True
|
| 1092 |
-
# gumbel softmax requires special init
|
| 1093 |
-
elif isinstance(module, Wav2Vec2ConformerGumbelVectorQuantizer):
|
| 1094 |
-
module.weight_proj.weight.data.normal_(mean=0.0, std=1)
|
| 1095 |
-
module.weight_proj.bias.data.zero_()
|
| 1096 |
-
nn.init.uniform_(module.codevectors)
|
| 1097 |
-
elif isinstance(module, Wav2Vec2ConformerSelfAttention):
|
| 1098 |
-
if hasattr(module, "pos_bias_u"):
|
| 1099 |
-
nn.init.xavier_uniform_(module.pos_bias_u)
|
| 1100 |
-
if hasattr(module, "pos_bias_v"):
|
| 1101 |
-
nn.init.xavier_uniform_(module.pos_bias_v)
|
| 1102 |
-
elif isinstance(module, Wav2Vec2ConformerPositionalConvEmbedding):
|
| 1103 |
-
nn.init.normal_(
|
| 1104 |
-
module.conv.weight,
|
| 1105 |
-
mean=0,
|
| 1106 |
-
std=2 * math.sqrt(1 / (module.conv.kernel_size[0] * module.conv.in_channels)),
|
| 1107 |
-
)
|
| 1108 |
-
nn.init.constant_(module.conv.bias, 0)
|
| 1109 |
-
elif isinstance(module, Wav2Vec2ConformerFeatureProjection):
|
| 1110 |
-
k = math.sqrt(1 / module.projection.in_features)
|
| 1111 |
-
nn.init.uniform_(module.projection.weight, a=-k, b=k)
|
| 1112 |
-
nn.init.uniform_(module.projection.bias, a=-k, b=k)
|
| 1113 |
-
elif isinstance(module, nn.Linear):
|
| 1114 |
-
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
|
| 1115 |
-
|
| 1116 |
-
if module.bias is not None:
|
| 1117 |
-
module.bias.data.zero_()
|
| 1118 |
-
elif isinstance(module, (nn.LayerNorm, nn.GroupNorm)):
|
| 1119 |
-
module.bias.data.zero_()
|
| 1120 |
-
module.weight.data.fill_(1.0)
|
| 1121 |
-
elif isinstance(module, nn.Conv1d):
|
| 1122 |
-
nn.init.kaiming_normal_(module.weight)
|
| 1123 |
-
|
| 1124 |
-
if module.bias is not None:
|
| 1125 |
-
k = math.sqrt(module.groups / (module.in_channels * module.kernel_size[0]))
|
| 1126 |
-
nn.init.uniform_(module.bias, a=-k, b=k)
|
| 1127 |
-
|
| 1128 |
-
def _get_feat_extract_output_lengths(
|
| 1129 |
-
self, input_lengths: Union[torch.LongTensor, int], add_adapter: Optional[bool] = None
|
| 1130 |
-
):
|
| 1131 |
-
"""
|
| 1132 |
-
Computes the output length of the convolutional layers
|
| 1133 |
-
"""
|
| 1134 |
-
|
| 1135 |
-
add_adapter = self.config.add_adapter if add_adapter is None else add_adapter
|
| 1136 |
-
|
| 1137 |
-
def _conv_out_length(input_length, kernel_size, stride):
|
| 1138 |
-
# 1D convolutional layer output length formula taken
|
| 1139 |
-
# from https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html
|
| 1140 |
-
return torch.div(input_length - kernel_size, stride, rounding_mode="floor") + 1
|
| 1141 |
-
|
| 1142 |
-
for kernel_size, stride in zip(self.config.conv_kernel, self.config.conv_stride):
|
| 1143 |
-
input_lengths = _conv_out_length(input_lengths, kernel_size, stride)
|
| 1144 |
-
|
| 1145 |
-
if add_adapter:
|
| 1146 |
-
for _ in range(self.config.num_adapter_layers):
|
| 1147 |
-
input_lengths = _conv_out_length(input_lengths, 1, self.config.adapter_stride)
|
| 1148 |
-
|
| 1149 |
-
return input_lengths
|
| 1150 |
-
|
| 1151 |
-
def _get_feature_vector_attention_mask(
|
| 1152 |
-
self, feature_vector_length: int, attention_mask: torch.LongTensor, add_adapter=None
|
| 1153 |
-
):
|
| 1154 |
-
# Effectively attention_mask.sum(-1), but not inplace to be able to run
|
| 1155 |
-
# on inference mode.
|
| 1156 |
-
non_padded_lengths = attention_mask.cumsum(dim=-1)[:, -1]
|
| 1157 |
-
|
| 1158 |
-
output_lengths = self._get_feat_extract_output_lengths(non_padded_lengths, add_adapter=add_adapter)
|
| 1159 |
-
output_lengths = output_lengths.to(torch.long)
|
| 1160 |
-
|
| 1161 |
-
batch_size = attention_mask.shape[0]
|
| 1162 |
-
|
| 1163 |
-
attention_mask = torch.zeros(
|
| 1164 |
-
(batch_size, feature_vector_length), dtype=attention_mask.dtype, device=attention_mask.device
|
| 1165 |
-
)
|
| 1166 |
-
# these two operations makes sure that all values before the output lengths idxs are attended to
|
| 1167 |
-
attention_mask[(torch.arange(attention_mask.shape[0], device=attention_mask.device), output_lengths - 1)] = 1
|
| 1168 |
-
attention_mask = attention_mask.flip([-1]).cumsum(-1).flip([-1]).bool()
|
| 1169 |
-
return attention_mask
|
| 1170 |
-
|
| 1171 |
-
def _set_gradient_checkpointing(self, module, value=False):
|
| 1172 |
-
if isinstance(module, (Wav2Vec2ConformerEncoder, Wav2Vec2ConformerFeatureEncoder)):
|
| 1173 |
-
module.gradient_checkpointing = value
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING = r"""
|
| 1177 |
-
Wav2Vec2Conformer was proposed in [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech
|
| 1178 |
-
Representations](https://arxiv.org/abs/2006.11477) by Alexei Baevski, Henry Zhou, Abdelrahman Mohamed, Michael
|
| 1179 |
-
Auli.
|
| 1180 |
-
|
| 1181 |
-
This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the
|
| 1182 |
-
library implements for all its model (such as downloading or saving etc.).
|
| 1183 |
-
|
| 1184 |
-
This model is a PyTorch [nn.Module](https://pytorch.org/docs/stable/nn.html#nn.Module) sub-class. Use it as a
|
| 1185 |
-
regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and behavior.
|
| 1186 |
-
|
| 1187 |
-
Parameters:
|
| 1188 |
-
config ([`Wav2Vec2ConformerConfig`]): Model configuration class with all the parameters of the model.
|
| 1189 |
-
Initializing with a config file does not load the weights associated with the model, only the
|
| 1190 |
-
configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights.
|
| 1191 |
-
"""
|
| 1192 |
-
|
| 1193 |
-
|
| 1194 |
-
WAV2VEC2_CONFORMER_INPUTS_DOCSTRING = r"""
|
| 1195 |
-
Args:
|
| 1196 |
-
input_values (`torch.FloatTensor` of shape `(batch_size, sequence_length)`):
|
| 1197 |
-
Float values of input raw speech waveform. Values can be obtained by loading a `.flac` or `.wav` audio file
|
| 1198 |
-
into an array of type `List[float]` or a `numpy.ndarray`, *e.g.* via the soundfile library (`pip install
|
| 1199 |
-
soundfile`). To prepare the array into `input_values`, the [`AutoProcessor`] should be used for padding and
|
| 1200 |
-
conversion into a tensor of type `torch.FloatTensor`. See [`Wav2Vec2Processor.__call__`] for details.
|
| 1201 |
-
attention_mask (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1202 |
-
Mask to avoid performing convolution and attention on padding token indices. Mask values selected in `[0,
|
| 1203 |
-
1]`:
|
| 1204 |
-
|
| 1205 |
-
- 1 for tokens that are **not masked**,
|
| 1206 |
-
- 0 for tokens that are **masked**.
|
| 1207 |
-
|
| 1208 |
-
[What are attention masks?](../glossary#attention-mask)
|
| 1209 |
-
|
| 1210 |
-
<Tip warning={true}>
|
| 1211 |
-
|
| 1212 |
-
`attention_mask` should only be passed if the corresponding processor has `config.return_attention_mask ==
|
| 1213 |
-
True`. For all models whose processor has `config.return_attention_mask == False`, such as
|
| 1214 |
-
[wav2vec2-conformer-rel-pos-large](https://huggingface.co/facebook/wav2vec2-conformer-rel-pos-large),
|
| 1215 |
-
`attention_mask` should **not** be passed to avoid degraded performance when doing batched inference. For
|
| 1216 |
-
such models `input_values` should simply be padded with 0 and passed without `attention_mask`. Be aware
|
| 1217 |
-
that these models also yield slightly different results depending on whether `input_values` is padded or
|
| 1218 |
-
not.
|
| 1219 |
-
|
| 1220 |
-
</Tip>
|
| 1221 |
-
|
| 1222 |
-
output_attentions (`bool`, *optional*):
|
| 1223 |
-
Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned
|
| 1224 |
-
tensors for more detail.
|
| 1225 |
-
output_hidden_states (`bool`, *optional*):
|
| 1226 |
-
Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
|
| 1227 |
-
more detail.
|
| 1228 |
-
return_dict (`bool`, *optional*):
|
| 1229 |
-
Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
|
| 1230 |
-
"""
|
| 1231 |
-
|
| 1232 |
-
|
| 1233 |
-
@add_start_docstrings(
|
| 1234 |
-
"The bare Wav2Vec2Conformer Model transformer outputting raw hidden-states without any specific head on top.",
|
| 1235 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING,
|
| 1236 |
-
)
|
| 1237 |
-
class Wav2Vec2ConformerModel(Wav2Vec2ConformerPreTrainedModel):
|
| 1238 |
-
def __init__(self, config: Wav2Vec2ConformerConfig):
|
| 1239 |
-
super().__init__(config)
|
| 1240 |
-
self.config = config
|
| 1241 |
-
self.feature_extractor = Wav2Vec2ConformerFeatureEncoder(config)
|
| 1242 |
-
self.feature_projection = Wav2Vec2ConformerFeatureProjection(config)
|
| 1243 |
-
|
| 1244 |
-
# model only needs masking vector if mask prob is > 0.0
|
| 1245 |
-
if config.mask_time_prob > 0.0 or config.mask_feature_prob > 0.0:
|
| 1246 |
-
self.masked_spec_embed = nn.Parameter(torch.FloatTensor(config.hidden_size).uniform_())
|
| 1247 |
-
|
| 1248 |
-
self.encoder = Wav2Vec2ConformerEncoder(config)
|
| 1249 |
-
|
| 1250 |
-
self.adapter = Wav2Vec2ConformerAdapter(config) if config.add_adapter else None
|
| 1251 |
-
|
| 1252 |
-
# Initialize weights and apply final processing
|
| 1253 |
-
self.post_init()
|
| 1254 |
-
|
| 1255 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2Model.freeze_feature_encoder
|
| 1256 |
-
def freeze_feature_encoder(self):
|
| 1257 |
-
"""
|
| 1258 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 1259 |
-
not be updated during training.
|
| 1260 |
-
"""
|
| 1261 |
-
self.feature_extractor._freeze_parameters()
|
| 1262 |
-
|
| 1263 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2Model._mask_hidden_states
|
| 1264 |
-
def _mask_hidden_states(
|
| 1265 |
-
self,
|
| 1266 |
-
hidden_states: torch.FloatTensor,
|
| 1267 |
-
mask_time_indices: Optional[torch.FloatTensor] = None,
|
| 1268 |
-
attention_mask: Optional[torch.LongTensor] = None,
|
| 1269 |
-
):
|
| 1270 |
-
"""
|
| 1271 |
-
Masks extracted features along time axis and/or along feature axis according to
|
| 1272 |
-
[SpecAugment](https://arxiv.org/abs/1904.08779).
|
| 1273 |
-
"""
|
| 1274 |
-
|
| 1275 |
-
# `config.apply_spec_augment` can set masking to False
|
| 1276 |
-
if not getattr(self.config, "apply_spec_augment", True):
|
| 1277 |
-
return hidden_states
|
| 1278 |
-
|
| 1279 |
-
# generate indices & apply SpecAugment along time axis
|
| 1280 |
-
batch_size, sequence_length, hidden_size = hidden_states.size()
|
| 1281 |
-
|
| 1282 |
-
if mask_time_indices is not None:
|
| 1283 |
-
# apply SpecAugment along time axis with given mask_time_indices
|
| 1284 |
-
hidden_states[mask_time_indices] = self.masked_spec_embed.to(hidden_states.dtype)
|
| 1285 |
-
elif self.config.mask_time_prob > 0 and self.training:
|
| 1286 |
-
mask_time_indices = _compute_mask_indices(
|
| 1287 |
-
(batch_size, sequence_length),
|
| 1288 |
-
mask_prob=self.config.mask_time_prob,
|
| 1289 |
-
mask_length=self.config.mask_time_length,
|
| 1290 |
-
attention_mask=attention_mask,
|
| 1291 |
-
min_masks=self.config.mask_time_min_masks,
|
| 1292 |
-
)
|
| 1293 |
-
mask_time_indices = torch.tensor(mask_time_indices, device=hidden_states.device, dtype=torch.bool)
|
| 1294 |
-
hidden_states[mask_time_indices] = self.masked_spec_embed.to(hidden_states.dtype)
|
| 1295 |
-
|
| 1296 |
-
if self.config.mask_feature_prob > 0 and self.training:
|
| 1297 |
-
# generate indices & apply SpecAugment along feature axis
|
| 1298 |
-
mask_feature_indices = _compute_mask_indices(
|
| 1299 |
-
(batch_size, hidden_size),
|
| 1300 |
-
mask_prob=self.config.mask_feature_prob,
|
| 1301 |
-
mask_length=self.config.mask_feature_length,
|
| 1302 |
-
min_masks=self.config.mask_feature_min_masks,
|
| 1303 |
-
)
|
| 1304 |
-
mask_feature_indices = torch.tensor(mask_feature_indices, device=hidden_states.device, dtype=torch.bool)
|
| 1305 |
-
mask_feature_indices = mask_feature_indices[:, None].expand(-1, sequence_length, -1)
|
| 1306 |
-
hidden_states[mask_feature_indices] = 0
|
| 1307 |
-
|
| 1308 |
-
return hidden_states
|
| 1309 |
-
|
| 1310 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 1311 |
-
@add_code_sample_docstrings(
|
| 1312 |
-
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 1313 |
-
output_type=Wav2Vec2BaseModelOutput,
|
| 1314 |
-
config_class=_CONFIG_FOR_DOC,
|
| 1315 |
-
modality="audio",
|
| 1316 |
-
expected_output=_EXPECTED_OUTPUT_SHAPE,
|
| 1317 |
-
)
|
| 1318 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2Model.forward with wav2vec2->wav2vec2_conformer
|
| 1319 |
-
def forward(
|
| 1320 |
-
self,
|
| 1321 |
-
input_values: Optional[torch.Tensor],
|
| 1322 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 1323 |
-
mask_time_indices: Optional[torch.FloatTensor] = None,
|
| 1324 |
-
output_attentions: Optional[bool] = None,
|
| 1325 |
-
output_hidden_states: Optional[bool] = None,
|
| 1326 |
-
return_dict: Optional[bool] = None,
|
| 1327 |
-
) -> Union[Tuple, Wav2Vec2BaseModelOutput]:
|
| 1328 |
-
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 1329 |
-
output_hidden_states = (
|
| 1330 |
-
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 1331 |
-
)
|
| 1332 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1333 |
-
|
| 1334 |
-
extract_features = self.feature_extractor(input_values)
|
| 1335 |
-
extract_features = extract_features.transpose(1, 2)
|
| 1336 |
-
|
| 1337 |
-
if attention_mask is not None:
|
| 1338 |
-
# compute reduced attention_mask corresponding to feature vectors
|
| 1339 |
-
attention_mask = self._get_feature_vector_attention_mask(
|
| 1340 |
-
extract_features.shape[1], attention_mask, add_adapter=False
|
| 1341 |
-
)
|
| 1342 |
-
|
| 1343 |
-
hidden_states, extract_features = self.feature_projection(extract_features)
|
| 1344 |
-
hidden_states = self._mask_hidden_states(
|
| 1345 |
-
hidden_states, mask_time_indices=mask_time_indices, attention_mask=attention_mask
|
| 1346 |
-
)
|
| 1347 |
-
|
| 1348 |
-
encoder_outputs = self.encoder(
|
| 1349 |
-
hidden_states,
|
| 1350 |
-
attention_mask=attention_mask,
|
| 1351 |
-
output_attentions=output_attentions,
|
| 1352 |
-
output_hidden_states=output_hidden_states,
|
| 1353 |
-
return_dict=return_dict,
|
| 1354 |
-
)
|
| 1355 |
-
|
| 1356 |
-
hidden_states = encoder_outputs[0]
|
| 1357 |
-
|
| 1358 |
-
if self.adapter is not None:
|
| 1359 |
-
hidden_states = self.adapter(hidden_states)
|
| 1360 |
-
|
| 1361 |
-
if not return_dict:
|
| 1362 |
-
return (hidden_states, extract_features) + encoder_outputs[1:]
|
| 1363 |
-
|
| 1364 |
-
return Wav2Vec2BaseModelOutput(
|
| 1365 |
-
last_hidden_state=hidden_states,
|
| 1366 |
-
extract_features=extract_features,
|
| 1367 |
-
hidden_states=encoder_outputs.hidden_states,
|
| 1368 |
-
attentions=encoder_outputs.attentions,
|
| 1369 |
-
)
|
| 1370 |
-
|
| 1371 |
-
|
| 1372 |
-
@add_start_docstrings(
|
| 1373 |
-
"""Wav2Vec2Conformer Model with a quantizer and `VQ` head on top.""", WAV2VEC2_CONFORMER_START_DOCSTRING
|
| 1374 |
-
)
|
| 1375 |
-
class Wav2Vec2ConformerForPreTraining(Wav2Vec2ConformerPreTrainedModel):
|
| 1376 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTraining.__init__ with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer
|
| 1377 |
-
def __init__(self, config: Wav2Vec2ConformerConfig):
|
| 1378 |
-
super().__init__(config)
|
| 1379 |
-
self.wav2vec2_conformer = Wav2Vec2ConformerModel(config)
|
| 1380 |
-
self.dropout_features = nn.Dropout(config.feat_quantizer_dropout)
|
| 1381 |
-
|
| 1382 |
-
self.quantizer = Wav2Vec2ConformerGumbelVectorQuantizer(config)
|
| 1383 |
-
|
| 1384 |
-
self.project_hid = nn.Linear(config.hidden_size, config.proj_codevector_dim)
|
| 1385 |
-
self.project_q = nn.Linear(config.codevector_dim, config.proj_codevector_dim)
|
| 1386 |
-
|
| 1387 |
-
# Initialize weights and apply final processing
|
| 1388 |
-
self.post_init()
|
| 1389 |
-
|
| 1390 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTraining.set_gumbel_temperature
|
| 1391 |
-
def set_gumbel_temperature(self, temperature: int):
|
| 1392 |
-
"""
|
| 1393 |
-
Set the Gumbel softmax temperature to a given value. Only necessary for training
|
| 1394 |
-
"""
|
| 1395 |
-
self.quantizer.temperature = temperature
|
| 1396 |
-
|
| 1397 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTraining.freeze_feature_encoder with wav2vec2->wav2vec2_conformer
|
| 1398 |
-
def freeze_feature_encoder(self):
|
| 1399 |
-
"""
|
| 1400 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 1401 |
-
not be updated during training.
|
| 1402 |
-
"""
|
| 1403 |
-
self.wav2vec2_conformer.feature_extractor._freeze_parameters()
|
| 1404 |
-
|
| 1405 |
-
@staticmethod
|
| 1406 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTraining.compute_contrastive_logits
|
| 1407 |
-
def compute_contrastive_logits(
|
| 1408 |
-
target_features: torch.FloatTensor,
|
| 1409 |
-
negative_features: torch.FloatTensor,
|
| 1410 |
-
predicted_features: torch.FloatTensor,
|
| 1411 |
-
temperature: int = 0.1,
|
| 1412 |
-
):
|
| 1413 |
-
"""
|
| 1414 |
-
Compute logits for contrastive loss based using cosine similarity as the distance measure between
|
| 1415 |
-
`[positive_feature, negative_features]` and `[predicted_features]`. Additionally, temperature can be applied.
|
| 1416 |
-
"""
|
| 1417 |
-
target_features = torch.cat([target_features, negative_features], dim=0)
|
| 1418 |
-
|
| 1419 |
-
logits = torch.cosine_similarity(predicted_features.float(), target_features.float(), dim=-1).type_as(
|
| 1420 |
-
target_features
|
| 1421 |
-
)
|
| 1422 |
-
|
| 1423 |
-
# apply temperature
|
| 1424 |
-
logits = logits / temperature
|
| 1425 |
-
return logits
|
| 1426 |
-
|
| 1427 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 1428 |
-
@replace_return_docstrings(output_type=Wav2Vec2ConformerForPreTrainingOutput, config_class=_CONFIG_FOR_DOC)
|
| 1429 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForPreTraining.forward with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer,wav2vec2_conformer-base->wav2vec2-conformer-rel-pos-large
|
| 1430 |
-
def forward(
|
| 1431 |
-
self,
|
| 1432 |
-
input_values: Optional[torch.Tensor],
|
| 1433 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 1434 |
-
mask_time_indices: Optional[torch.BoolTensor] = None,
|
| 1435 |
-
sampled_negative_indices: Optional[torch.BoolTensor] = None,
|
| 1436 |
-
output_attentions: Optional[bool] = None,
|
| 1437 |
-
output_hidden_states: Optional[bool] = None,
|
| 1438 |
-
return_dict: Optional[bool] = None,
|
| 1439 |
-
) -> Union[Tuple, Wav2Vec2ConformerForPreTrainingOutput]:
|
| 1440 |
-
r"""
|
| 1441 |
-
mask_time_indices (`torch.BoolTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1442 |
-
Indices to mask extracted features for contrastive loss. When in training mode, model learns to predict
|
| 1443 |
-
masked extracted features in *config.proj_codevector_dim* space.
|
| 1444 |
-
sampled_negative_indices (`torch.BoolTensor` of shape `(batch_size, sequence_length, num_negatives)`, *optional*):
|
| 1445 |
-
Indices indicating which quantized target vectors are used as negative sampled vectors in contrastive loss.
|
| 1446 |
-
Required input for pre-training.
|
| 1447 |
-
|
| 1448 |
-
Returns:
|
| 1449 |
-
|
| 1450 |
-
Example:
|
| 1451 |
-
|
| 1452 |
-
```python
|
| 1453 |
-
>>> import torch
|
| 1454 |
-
>>> from transformers import AutoFeatureExtractor, Wav2Vec2ConformerForPreTraining
|
| 1455 |
-
>>> from transformers.models.wav2vec2_conformer.modeling_wav2vec2_conformer import (
|
| 1456 |
-
... _compute_mask_indices,
|
| 1457 |
-
... _sample_negative_indices,
|
| 1458 |
-
... )
|
| 1459 |
-
>>> from datasets import load_dataset
|
| 1460 |
-
|
| 1461 |
-
>>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-conformer-rel-pos-large")
|
| 1462 |
-
>>> model = Wav2Vec2ConformerForPreTraining.from_pretrained("facebook/wav2vec2-conformer-rel-pos-large")
|
| 1463 |
-
|
| 1464 |
-
>>> ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation")
|
| 1465 |
-
>>> input_values = feature_extractor(ds[0]["audio"]["array"], return_tensors="pt").input_values # Batch size 1
|
| 1466 |
-
|
| 1467 |
-
>>> # compute masked indices
|
| 1468 |
-
>>> batch_size, raw_sequence_length = input_values.shape
|
| 1469 |
-
>>> sequence_length = model._get_feat_extract_output_lengths(raw_sequence_length).item()
|
| 1470 |
-
>>> mask_time_indices = _compute_mask_indices(
|
| 1471 |
-
... shape=(batch_size, sequence_length), mask_prob=0.2, mask_length=2
|
| 1472 |
-
... )
|
| 1473 |
-
>>> sampled_negative_indices = _sample_negative_indices(
|
| 1474 |
-
... features_shape=(batch_size, sequence_length),
|
| 1475 |
-
... num_negatives=model.config.num_negatives,
|
| 1476 |
-
... mask_time_indices=mask_time_indices,
|
| 1477 |
-
... )
|
| 1478 |
-
>>> mask_time_indices = torch.tensor(data=mask_time_indices, device=input_values.device, dtype=torch.long)
|
| 1479 |
-
>>> sampled_negative_indices = torch.tensor(
|
| 1480 |
-
... data=sampled_negative_indices, device=input_values.device, dtype=torch.long
|
| 1481 |
-
... )
|
| 1482 |
-
|
| 1483 |
-
>>> with torch.no_grad():
|
| 1484 |
-
... outputs = model(input_values, mask_time_indices=mask_time_indices)
|
| 1485 |
-
|
| 1486 |
-
>>> # compute cosine similarity between predicted (=projected_states) and target (=projected_quantized_states)
|
| 1487 |
-
>>> cosine_sim = torch.cosine_similarity(outputs.projected_states, outputs.projected_quantized_states, dim=-1)
|
| 1488 |
-
|
| 1489 |
-
>>> # show that cosine similarity is much higher than random
|
| 1490 |
-
>>> cosine_sim[mask_time_indices.to(torch.bool)].mean() > 0.5
|
| 1491 |
-
tensor(True)
|
| 1492 |
-
|
| 1493 |
-
>>> # for contrastive loss training model should be put into train mode
|
| 1494 |
-
>>> model = model.train()
|
| 1495 |
-
>>> loss = model(
|
| 1496 |
-
... input_values, mask_time_indices=mask_time_indices, sampled_negative_indices=sampled_negative_indices
|
| 1497 |
-
... ).loss
|
| 1498 |
-
```"""
|
| 1499 |
-
|
| 1500 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1501 |
-
|
| 1502 |
-
if mask_time_indices is not None:
|
| 1503 |
-
mask_time_indices = mask_time_indices.to(torch.bool)
|
| 1504 |
-
|
| 1505 |
-
outputs = self.wav2vec2_conformer(
|
| 1506 |
-
input_values,
|
| 1507 |
-
attention_mask=attention_mask,
|
| 1508 |
-
output_attentions=output_attentions,
|
| 1509 |
-
output_hidden_states=output_hidden_states,
|
| 1510 |
-
mask_time_indices=mask_time_indices,
|
| 1511 |
-
return_dict=return_dict,
|
| 1512 |
-
)
|
| 1513 |
-
|
| 1514 |
-
# 1. project all transformed features (including masked) to final vq dim
|
| 1515 |
-
transformer_features = self.project_hid(outputs[0])
|
| 1516 |
-
|
| 1517 |
-
# 2. quantize all (unmasked) extracted features and project to final vq dim
|
| 1518 |
-
extract_features = self.dropout_features(outputs[1])
|
| 1519 |
-
|
| 1520 |
-
if attention_mask is not None:
|
| 1521 |
-
# compute reduced attention_mask correponding to feature vectors
|
| 1522 |
-
attention_mask = self._get_feature_vector_attention_mask(
|
| 1523 |
-
extract_features.shape[1], attention_mask, add_adapter=False
|
| 1524 |
-
)
|
| 1525 |
-
|
| 1526 |
-
quantized_features, codevector_perplexity = self.quantizer(
|
| 1527 |
-
extract_features, mask_time_indices=mask_time_indices
|
| 1528 |
-
)
|
| 1529 |
-
quantized_features = self.project_q(quantized_features)
|
| 1530 |
-
|
| 1531 |
-
loss = contrastive_loss = diversity_loss = None
|
| 1532 |
-
if sampled_negative_indices is not None:
|
| 1533 |
-
batch_size, sequence_length, hidden_size = quantized_features.shape
|
| 1534 |
-
|
| 1535 |
-
# for training, we sample negatives
|
| 1536 |
-
# 3. sample K negatives (distractors) quantized states for contrastive loss
|
| 1537 |
-
# if attention_mask is passed, make sure that padded feature vectors cannot be sampled
|
| 1538 |
-
# sample negative quantized vectors BTC => (BxT)C
|
| 1539 |
-
negative_quantized_features = quantized_features.view(-1, hidden_size)[
|
| 1540 |
-
sampled_negative_indices.long().view(-1)
|
| 1541 |
-
]
|
| 1542 |
-
negative_quantized_features = negative_quantized_features.view(
|
| 1543 |
-
batch_size, sequence_length, -1, hidden_size
|
| 1544 |
-
).permute(2, 0, 1, 3)
|
| 1545 |
-
|
| 1546 |
-
# 4. compute logits, corresponding to `logs = sim(c_t, [q_t, \sim{q}_t]) / \kappa`
|
| 1547 |
-
# of equation (3) in https://arxiv.org/pdf/2006.11477.pdf
|
| 1548 |
-
logits = self.compute_contrastive_logits(
|
| 1549 |
-
quantized_features[None, :],
|
| 1550 |
-
negative_quantized_features,
|
| 1551 |
-
transformer_features,
|
| 1552 |
-
self.config.contrastive_logits_temperature,
|
| 1553 |
-
)
|
| 1554 |
-
|
| 1555 |
-
# 5. if a negative vector is identical to the positive (i.e. when codebook utilization is low),
|
| 1556 |
-
# its cosine similarity will be masked
|
| 1557 |
-
neg_is_pos = (quantized_features == negative_quantized_features).all(-1)
|
| 1558 |
-
|
| 1559 |
-
if neg_is_pos.any():
|
| 1560 |
-
logits[1:][neg_is_pos] = float("-inf")
|
| 1561 |
-
|
| 1562 |
-
# 6. compute contrastive loss \mathbf{L}_m = cross_entropy(logs) =
|
| 1563 |
-
# -log(exp(sim(c_t, q_t)/\kappa) / \sum_{\sim{q}} exp(sim(c_t, \sim{q})/\kappa))
|
| 1564 |
-
logits = logits.transpose(0, 2).reshape(-1, logits.size(0))
|
| 1565 |
-
target = ((1 - mask_time_indices.long()) * -100).transpose(0, 1).flatten()
|
| 1566 |
-
|
| 1567 |
-
contrastive_loss = nn.functional.cross_entropy(logits.float(), target, reduction="sum")
|
| 1568 |
-
# 7. compute diversity loss: \mathbf{L}_d
|
| 1569 |
-
num_codevectors = self.config.num_codevectors_per_group * self.config.num_codevector_groups
|
| 1570 |
-
diversity_loss = ((num_codevectors - codevector_perplexity) / num_codevectors) * mask_time_indices.sum()
|
| 1571 |
-
|
| 1572 |
-
# 8. \mathbf{L} = \mathbf{L}_m + \alpha * \mathbf{L}_d
|
| 1573 |
-
loss = contrastive_loss + self.config.diversity_loss_weight * diversity_loss
|
| 1574 |
-
|
| 1575 |
-
if not return_dict:
|
| 1576 |
-
if loss is not None:
|
| 1577 |
-
return (loss, transformer_features, quantized_features, codevector_perplexity) + outputs[2:]
|
| 1578 |
-
return (transformer_features, quantized_features, codevector_perplexity) + outputs[2:]
|
| 1579 |
-
|
| 1580 |
-
return Wav2Vec2ConformerForPreTrainingOutput(
|
| 1581 |
-
loss=loss,
|
| 1582 |
-
projected_states=transformer_features,
|
| 1583 |
-
projected_quantized_states=quantized_features,
|
| 1584 |
-
codevector_perplexity=codevector_perplexity,
|
| 1585 |
-
hidden_states=outputs.hidden_states,
|
| 1586 |
-
attentions=outputs.attentions,
|
| 1587 |
-
contrastive_loss=contrastive_loss,
|
| 1588 |
-
diversity_loss=diversity_loss,
|
| 1589 |
-
)
|
| 1590 |
-
|
| 1591 |
-
|
| 1592 |
-
@add_start_docstrings(
|
| 1593 |
-
"""Wav2Vec2Conformer Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).""",
|
| 1594 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING,
|
| 1595 |
-
)
|
| 1596 |
-
class Wav2Vec2ConformerForCTC(Wav2Vec2ConformerPreTrainedModel):
|
| 1597 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForCTC.__init__ with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer
|
| 1598 |
-
def __init__(self, config):
|
| 1599 |
-
super().__init__(config)
|
| 1600 |
-
|
| 1601 |
-
self.wav2vec2_conformer = Wav2Vec2ConformerModel(config)
|
| 1602 |
-
self.dropout = nn.Dropout(config.final_dropout)
|
| 1603 |
-
|
| 1604 |
-
if config.vocab_size is None:
|
| 1605 |
-
raise ValueError(
|
| 1606 |
-
f"You are trying to instantiate {self.__class__} with a configuration that "
|
| 1607 |
-
"does not define the vocabulary size of the language model head. Please "
|
| 1608 |
-
"instantiate the model as follows: `Wav2Vec2ConformerForCTC.from_pretrained(..., vocab_size=vocab_size)`. "
|
| 1609 |
-
"or define `vocab_size` of your model's configuration."
|
| 1610 |
-
)
|
| 1611 |
-
output_hidden_size = (
|
| 1612 |
-
config.output_hidden_size if hasattr(config, "add_adapter") and config.add_adapter else config.hidden_size
|
| 1613 |
-
)
|
| 1614 |
-
self.lm_head = nn.Linear(output_hidden_size, config.vocab_size)
|
| 1615 |
-
|
| 1616 |
-
# Initialize weights and apply final processing
|
| 1617 |
-
self.post_init()
|
| 1618 |
-
|
| 1619 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForCTC.freeze_feature_encoder with wav2vec2->wav2vec2_conformer
|
| 1620 |
-
def freeze_feature_encoder(self):
|
| 1621 |
-
"""
|
| 1622 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 1623 |
-
not be updated during training.
|
| 1624 |
-
"""
|
| 1625 |
-
self.wav2vec2_conformer.feature_extractor._freeze_parameters()
|
| 1626 |
-
|
| 1627 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 1628 |
-
@add_code_sample_docstrings(
|
| 1629 |
-
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 1630 |
-
output_type=CausalLMOutput,
|
| 1631 |
-
config_class=_CONFIG_FOR_DOC,
|
| 1632 |
-
expected_output=_CTC_EXPECTED_OUTPUT,
|
| 1633 |
-
expected_loss=_CTC_EXPECTED_LOSS,
|
| 1634 |
-
)
|
| 1635 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForCTC.forward with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer
|
| 1636 |
-
def forward(
|
| 1637 |
-
self,
|
| 1638 |
-
input_values: Optional[torch.Tensor],
|
| 1639 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 1640 |
-
output_attentions: Optional[bool] = None,
|
| 1641 |
-
output_hidden_states: Optional[bool] = None,
|
| 1642 |
-
return_dict: Optional[bool] = None,
|
| 1643 |
-
labels: Optional[torch.Tensor] = None,
|
| 1644 |
-
) -> Union[Tuple, CausalLMOutput]:
|
| 1645 |
-
r"""
|
| 1646 |
-
labels (`torch.LongTensor` of shape `(batch_size, target_length)`, *optional*):
|
| 1647 |
-
Labels for connectionist temporal classification. Note that `target_length` has to be smaller or equal to
|
| 1648 |
-
the sequence length of the output logits. Indices are selected in `[-100, 0, ..., config.vocab_size - 1]`.
|
| 1649 |
-
All labels set to `-100` are ignored (masked), the loss is only computed for labels in `[0, ...,
|
| 1650 |
-
config.vocab_size - 1]`.
|
| 1651 |
-
"""
|
| 1652 |
-
|
| 1653 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1654 |
-
|
| 1655 |
-
outputs = self.wav2vec2_conformer(
|
| 1656 |
-
input_values,
|
| 1657 |
-
attention_mask=attention_mask,
|
| 1658 |
-
output_attentions=output_attentions,
|
| 1659 |
-
output_hidden_states=output_hidden_states,
|
| 1660 |
-
return_dict=return_dict,
|
| 1661 |
-
)
|
| 1662 |
-
|
| 1663 |
-
hidden_states = outputs[0]
|
| 1664 |
-
hidden_states = self.dropout(hidden_states)
|
| 1665 |
-
|
| 1666 |
-
logits = self.lm_head(hidden_states)
|
| 1667 |
-
|
| 1668 |
-
loss = None
|
| 1669 |
-
if labels is not None:
|
| 1670 |
-
if labels.max() >= self.config.vocab_size:
|
| 1671 |
-
raise ValueError(f"Label values must be <= vocab_size: {self.config.vocab_size}")
|
| 1672 |
-
|
| 1673 |
-
# retrieve loss input_lengths from attention_mask
|
| 1674 |
-
attention_mask = (
|
| 1675 |
-
attention_mask if attention_mask is not None else torch.ones_like(input_values, dtype=torch.long)
|
| 1676 |
-
)
|
| 1677 |
-
input_lengths = self._get_feat_extract_output_lengths(attention_mask.sum(-1)).to(torch.long)
|
| 1678 |
-
|
| 1679 |
-
# assuming that padded tokens are filled with -100
|
| 1680 |
-
# when not being attended to
|
| 1681 |
-
labels_mask = labels >= 0
|
| 1682 |
-
target_lengths = labels_mask.sum(-1)
|
| 1683 |
-
flattened_targets = labels.masked_select(labels_mask)
|
| 1684 |
-
|
| 1685 |
-
# ctc_loss doesn't support fp16
|
| 1686 |
-
log_probs = nn.functional.log_softmax(logits, dim=-1, dtype=torch.float32).transpose(0, 1)
|
| 1687 |
-
|
| 1688 |
-
with torch.backends.cudnn.flags(enabled=False):
|
| 1689 |
-
loss = nn.functional.ctc_loss(
|
| 1690 |
-
log_probs,
|
| 1691 |
-
flattened_targets,
|
| 1692 |
-
input_lengths,
|
| 1693 |
-
target_lengths,
|
| 1694 |
-
blank=self.config.pad_token_id,
|
| 1695 |
-
reduction=self.config.ctc_loss_reduction,
|
| 1696 |
-
zero_infinity=self.config.ctc_zero_infinity,
|
| 1697 |
-
)
|
| 1698 |
-
|
| 1699 |
-
if not return_dict:
|
| 1700 |
-
output = (logits,) + outputs[_HIDDEN_STATES_START_POSITION:]
|
| 1701 |
-
return ((loss,) + output) if loss is not None else output
|
| 1702 |
-
|
| 1703 |
-
return CausalLMOutput(
|
| 1704 |
-
loss=loss, logits=logits, hidden_states=outputs.hidden_states, attentions=outputs.attentions
|
| 1705 |
-
)
|
| 1706 |
-
|
| 1707 |
-
|
| 1708 |
-
@add_start_docstrings(
|
| 1709 |
-
"""
|
| 1710 |
-
Wav2Vec2Conformer Model with a sequence classification head on top (a linear layer over the pooled output) for
|
| 1711 |
-
tasks like SUPERB Keyword Spotting.
|
| 1712 |
-
""",
|
| 1713 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING,
|
| 1714 |
-
)
|
| 1715 |
-
class Wav2Vec2ConformerForSequenceClassification(Wav2Vec2ConformerPreTrainedModel):
|
| 1716 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForSequenceClassification.__init__ with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer
|
| 1717 |
-
def __init__(self, config):
|
| 1718 |
-
super().__init__(config)
|
| 1719 |
-
|
| 1720 |
-
if hasattr(config, "add_adapter") and config.add_adapter:
|
| 1721 |
-
raise ValueError(
|
| 1722 |
-
"Sequence classification does not support the use of Wav2Vec2Conformer adapters (config.add_adapter=True)"
|
| 1723 |
-
)
|
| 1724 |
-
self.wav2vec2_conformer = Wav2Vec2ConformerModel(config)
|
| 1725 |
-
num_layers = config.num_hidden_layers + 1 # transformer layers + input embeddings
|
| 1726 |
-
if config.use_weighted_layer_sum:
|
| 1727 |
-
self.layer_weights = nn.Parameter(torch.ones(num_layers) / num_layers)
|
| 1728 |
-
self.projector = nn.Linear(config.hidden_size, config.classifier_proj_size)
|
| 1729 |
-
self.classifier = nn.Linear(config.classifier_proj_size, config.num_labels)
|
| 1730 |
-
|
| 1731 |
-
# Initialize weights and apply final processing
|
| 1732 |
-
self.post_init()
|
| 1733 |
-
|
| 1734 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForSequenceClassification.freeze_feature_encoder with wav2vec2->wav2vec2_conformer
|
| 1735 |
-
def freeze_feature_encoder(self):
|
| 1736 |
-
"""
|
| 1737 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 1738 |
-
not be updated during training.
|
| 1739 |
-
"""
|
| 1740 |
-
self.wav2vec2_conformer.feature_extractor._freeze_parameters()
|
| 1741 |
-
|
| 1742 |
-
def freeze_base_model(self):
|
| 1743 |
-
"""
|
| 1744 |
-
Calling this function will disable the gradient computation for the base model so that its parameters will not
|
| 1745 |
-
be updated during training. Only the classification head will be updated.
|
| 1746 |
-
"""
|
| 1747 |
-
for param in self.wav2vec2_conformer.parameters():
|
| 1748 |
-
param.requires_grad = False
|
| 1749 |
-
|
| 1750 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 1751 |
-
@add_code_sample_docstrings(
|
| 1752 |
-
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 1753 |
-
output_type=SequenceClassifierOutput,
|
| 1754 |
-
config_class=_CONFIG_FOR_DOC,
|
| 1755 |
-
modality="audio",
|
| 1756 |
-
)
|
| 1757 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForSequenceClassification.forward with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer,WAV_2_VEC_2->WAV2VEC2_CONFORMER
|
| 1758 |
-
def forward(
|
| 1759 |
-
self,
|
| 1760 |
-
input_values: Optional[torch.Tensor],
|
| 1761 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 1762 |
-
output_attentions: Optional[bool] = None,
|
| 1763 |
-
output_hidden_states: Optional[bool] = None,
|
| 1764 |
-
return_dict: Optional[bool] = None,
|
| 1765 |
-
labels: Optional[torch.Tensor] = None,
|
| 1766 |
-
) -> Union[Tuple, SequenceClassifierOutput]:
|
| 1767 |
-
r"""
|
| 1768 |
-
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1769 |
-
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 1770 |
-
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 1771 |
-
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 1772 |
-
"""
|
| 1773 |
-
|
| 1774 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1775 |
-
output_hidden_states = True if self.config.use_weighted_layer_sum else output_hidden_states
|
| 1776 |
-
|
| 1777 |
-
outputs = self.wav2vec2_conformer(
|
| 1778 |
-
input_values,
|
| 1779 |
-
attention_mask=attention_mask,
|
| 1780 |
-
output_attentions=output_attentions,
|
| 1781 |
-
output_hidden_states=output_hidden_states,
|
| 1782 |
-
return_dict=return_dict,
|
| 1783 |
-
)
|
| 1784 |
-
|
| 1785 |
-
if self.config.use_weighted_layer_sum:
|
| 1786 |
-
hidden_states = outputs[_HIDDEN_STATES_START_POSITION]
|
| 1787 |
-
hidden_states = torch.stack(hidden_states, dim=1)
|
| 1788 |
-
norm_weights = nn.functional.softmax(self.layer_weights, dim=-1)
|
| 1789 |
-
hidden_states = (hidden_states * norm_weights.view(-1, 1, 1)).sum(dim=1)
|
| 1790 |
-
else:
|
| 1791 |
-
hidden_states = outputs[0]
|
| 1792 |
-
|
| 1793 |
-
hidden_states = self.projector(hidden_states)
|
| 1794 |
-
if attention_mask is None:
|
| 1795 |
-
pooled_output = hidden_states.mean(dim=1)
|
| 1796 |
-
else:
|
| 1797 |
-
padding_mask = self._get_feature_vector_attention_mask(hidden_states.shape[1], attention_mask)
|
| 1798 |
-
hidden_states[~padding_mask] = 0.0
|
| 1799 |
-
pooled_output = hidden_states.sum(dim=1) / padding_mask.sum(dim=1).view(-1, 1)
|
| 1800 |
-
|
| 1801 |
-
logits = self.classifier(pooled_output)
|
| 1802 |
-
|
| 1803 |
-
loss = None
|
| 1804 |
-
if labels is not None:
|
| 1805 |
-
loss_fct = CrossEntropyLoss()
|
| 1806 |
-
loss = loss_fct(logits.view(-1, self.config.num_labels), labels.view(-1))
|
| 1807 |
-
|
| 1808 |
-
if not return_dict:
|
| 1809 |
-
output = (logits,) + outputs[_HIDDEN_STATES_START_POSITION:]
|
| 1810 |
-
return ((loss,) + output) if loss is not None else output
|
| 1811 |
-
|
| 1812 |
-
return SequenceClassifierOutput(
|
| 1813 |
-
loss=loss,
|
| 1814 |
-
logits=logits,
|
| 1815 |
-
hidden_states=outputs.hidden_states,
|
| 1816 |
-
attentions=outputs.attentions,
|
| 1817 |
-
)
|
| 1818 |
-
|
| 1819 |
-
|
| 1820 |
-
@add_start_docstrings(
|
| 1821 |
-
"""
|
| 1822 |
-
Wav2Vec2Conformer Model with a frame classification head on top for tasks like Speaker Diarization.
|
| 1823 |
-
""",
|
| 1824 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING,
|
| 1825 |
-
)
|
| 1826 |
-
class Wav2Vec2ConformerForAudioFrameClassification(Wav2Vec2ConformerPreTrainedModel):
|
| 1827 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForAudioFrameClassification.__init__ with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer,WAV_2_VEC_2->WAV2VEC2_CONFORMER
|
| 1828 |
-
def __init__(self, config):
|
| 1829 |
-
super().__init__(config)
|
| 1830 |
-
|
| 1831 |
-
if hasattr(config, "add_adapter") and config.add_adapter:
|
| 1832 |
-
raise ValueError(
|
| 1833 |
-
"Audio frame classification does not support the use of Wav2Vec2Conformer adapters (config.add_adapter=True)"
|
| 1834 |
-
)
|
| 1835 |
-
self.wav2vec2_conformer = Wav2Vec2ConformerModel(config)
|
| 1836 |
-
num_layers = config.num_hidden_layers + 1 # transformer layers + input embeddings
|
| 1837 |
-
if config.use_weighted_layer_sum:
|
| 1838 |
-
self.layer_weights = nn.Parameter(torch.ones(num_layers) / num_layers)
|
| 1839 |
-
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 1840 |
-
self.num_labels = config.num_labels
|
| 1841 |
-
|
| 1842 |
-
self.init_weights()
|
| 1843 |
-
|
| 1844 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForAudioFrameClassification.freeze_feature_encoder with wav2vec2->wav2vec2_conformer
|
| 1845 |
-
def freeze_feature_encoder(self):
|
| 1846 |
-
"""
|
| 1847 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 1848 |
-
not be updated during training.
|
| 1849 |
-
"""
|
| 1850 |
-
self.wav2vec2_conformer.feature_extractor._freeze_parameters()
|
| 1851 |
-
|
| 1852 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForAudioFrameClassification.freeze_base_model with wav2vec2->wav2vec2_conformer
|
| 1853 |
-
def freeze_base_model(self):
|
| 1854 |
-
"""
|
| 1855 |
-
Calling this function will disable the gradient computation for the base model so that its parameters will not
|
| 1856 |
-
be updated during training. Only the classification head will be updated.
|
| 1857 |
-
"""
|
| 1858 |
-
for param in self.wav2vec2_conformer.parameters():
|
| 1859 |
-
param.requires_grad = False
|
| 1860 |
-
|
| 1861 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 1862 |
-
@add_code_sample_docstrings(
|
| 1863 |
-
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 1864 |
-
output_type=TokenClassifierOutput,
|
| 1865 |
-
config_class=_CONFIG_FOR_DOC,
|
| 1866 |
-
modality="audio",
|
| 1867 |
-
)
|
| 1868 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForAudioFrameClassification.forward with wav2vec2->wav2vec2_conformer
|
| 1869 |
-
def forward(
|
| 1870 |
-
self,
|
| 1871 |
-
input_values: Optional[torch.Tensor],
|
| 1872 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 1873 |
-
labels: Optional[torch.Tensor] = None,
|
| 1874 |
-
output_attentions: Optional[bool] = None,
|
| 1875 |
-
output_hidden_states: Optional[bool] = None,
|
| 1876 |
-
return_dict: Optional[bool] = None,
|
| 1877 |
-
) -> Union[Tuple, TokenClassifierOutput]:
|
| 1878 |
-
r"""
|
| 1879 |
-
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1880 |
-
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 1881 |
-
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 1882 |
-
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 1883 |
-
"""
|
| 1884 |
-
|
| 1885 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1886 |
-
output_hidden_states = True if self.config.use_weighted_layer_sum else output_hidden_states
|
| 1887 |
-
|
| 1888 |
-
outputs = self.wav2vec2_conformer(
|
| 1889 |
-
input_values,
|
| 1890 |
-
attention_mask=attention_mask,
|
| 1891 |
-
output_attentions=output_attentions,
|
| 1892 |
-
output_hidden_states=output_hidden_states,
|
| 1893 |
-
return_dict=return_dict,
|
| 1894 |
-
)
|
| 1895 |
-
|
| 1896 |
-
if self.config.use_weighted_layer_sum:
|
| 1897 |
-
hidden_states = outputs[_HIDDEN_STATES_START_POSITION]
|
| 1898 |
-
hidden_states = torch.stack(hidden_states, dim=1)
|
| 1899 |
-
norm_weights = nn.functional.softmax(self.layer_weights, dim=-1)
|
| 1900 |
-
hidden_states = (hidden_states * norm_weights.view(-1, 1, 1)).sum(dim=1)
|
| 1901 |
-
else:
|
| 1902 |
-
hidden_states = outputs[0]
|
| 1903 |
-
|
| 1904 |
-
logits = self.classifier(hidden_states)
|
| 1905 |
-
|
| 1906 |
-
loss = None
|
| 1907 |
-
if labels is not None:
|
| 1908 |
-
loss_fct = CrossEntropyLoss()
|
| 1909 |
-
loss = loss_fct(logits.view(-1, self.num_labels), torch.argmax(labels.view(-1, self.num_labels), axis=1))
|
| 1910 |
-
|
| 1911 |
-
if not return_dict:
|
| 1912 |
-
output = (logits,) + outputs[_HIDDEN_STATES_START_POSITION:]
|
| 1913 |
-
return output
|
| 1914 |
-
|
| 1915 |
-
return TokenClassifierOutput(
|
| 1916 |
-
loss=loss,
|
| 1917 |
-
logits=logits,
|
| 1918 |
-
hidden_states=outputs.hidden_states,
|
| 1919 |
-
attentions=outputs.attentions,
|
| 1920 |
-
)
|
| 1921 |
-
|
| 1922 |
-
|
| 1923 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.AMSoftmaxLoss
|
| 1924 |
-
class AMSoftmaxLoss(nn.Module):
|
| 1925 |
-
def __init__(self, input_dim, num_labels, scale=30.0, margin=0.4):
|
| 1926 |
-
super(AMSoftmaxLoss, self).__init__()
|
| 1927 |
-
self.scale = scale
|
| 1928 |
-
self.margin = margin
|
| 1929 |
-
self.num_labels = num_labels
|
| 1930 |
-
self.weight = nn.Parameter(torch.randn(input_dim, num_labels), requires_grad=True)
|
| 1931 |
-
self.loss = nn.CrossEntropyLoss()
|
| 1932 |
-
|
| 1933 |
-
def forward(self, hidden_states, labels):
|
| 1934 |
-
labels = labels.flatten()
|
| 1935 |
-
weight = nn.functional.normalize(self.weight, dim=0)
|
| 1936 |
-
hidden_states = nn.functional.normalize(hidden_states, dim=1)
|
| 1937 |
-
cos_theta = torch.mm(hidden_states, weight)
|
| 1938 |
-
psi = cos_theta - self.margin
|
| 1939 |
-
|
| 1940 |
-
onehot = nn.functional.one_hot(labels, self.num_labels)
|
| 1941 |
-
logits = self.scale * torch.where(onehot.bool(), psi, cos_theta)
|
| 1942 |
-
loss = self.loss(logits, labels)
|
| 1943 |
-
|
| 1944 |
-
return loss
|
| 1945 |
-
|
| 1946 |
-
|
| 1947 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.TDNNLayer
|
| 1948 |
-
class TDNNLayer(nn.Module):
|
| 1949 |
-
def __init__(self, config, layer_id=0):
|
| 1950 |
-
super().__init__()
|
| 1951 |
-
self.in_conv_dim = config.tdnn_dim[layer_id - 1] if layer_id > 0 else config.tdnn_dim[layer_id]
|
| 1952 |
-
self.out_conv_dim = config.tdnn_dim[layer_id]
|
| 1953 |
-
self.kernel_size = config.tdnn_kernel[layer_id]
|
| 1954 |
-
self.dilation = config.tdnn_dilation[layer_id]
|
| 1955 |
-
|
| 1956 |
-
self.kernel = nn.Linear(self.in_conv_dim * self.kernel_size, self.out_conv_dim)
|
| 1957 |
-
self.activation = nn.ReLU()
|
| 1958 |
-
|
| 1959 |
-
def forward(self, hidden_states):
|
| 1960 |
-
hidden_states = hidden_states.unsqueeze(1)
|
| 1961 |
-
hidden_states = nn.functional.unfold(
|
| 1962 |
-
hidden_states,
|
| 1963 |
-
(self.kernel_size, self.in_conv_dim),
|
| 1964 |
-
stride=(1, self.in_conv_dim),
|
| 1965 |
-
dilation=(self.dilation, 1),
|
| 1966 |
-
)
|
| 1967 |
-
hidden_states = hidden_states.transpose(1, 2)
|
| 1968 |
-
hidden_states = self.kernel(hidden_states)
|
| 1969 |
-
|
| 1970 |
-
hidden_states = self.activation(hidden_states)
|
| 1971 |
-
return hidden_states
|
| 1972 |
-
|
| 1973 |
-
|
| 1974 |
-
@add_start_docstrings(
|
| 1975 |
-
"""
|
| 1976 |
-
Wav2Vec2Conformer Model with an XVector feature extraction head on top for tasks like Speaker Verification.
|
| 1977 |
-
""",
|
| 1978 |
-
WAV2VEC2_CONFORMER_START_DOCSTRING,
|
| 1979 |
-
)
|
| 1980 |
-
class Wav2Vec2ConformerForXVector(Wav2Vec2ConformerPreTrainedModel):
|
| 1981 |
-
def __init__(self, config):
|
| 1982 |
-
super().__init__(config)
|
| 1983 |
-
|
| 1984 |
-
self.wav2vec2_conformer = Wav2Vec2ConformerModel(config)
|
| 1985 |
-
num_layers = config.num_hidden_layers + 1 # transformer layers + input embeddings
|
| 1986 |
-
if config.use_weighted_layer_sum:
|
| 1987 |
-
self.layer_weights = nn.Parameter(torch.ones(num_layers) / num_layers)
|
| 1988 |
-
self.projector = nn.Linear(config.hidden_size, config.tdnn_dim[0])
|
| 1989 |
-
|
| 1990 |
-
tdnn_layers = [TDNNLayer(config, i) for i in range(len(config.tdnn_dim))]
|
| 1991 |
-
self.tdnn = nn.ModuleList(tdnn_layers)
|
| 1992 |
-
|
| 1993 |
-
self.feature_extractor = nn.Linear(config.tdnn_dim[-1] * 2, config.xvector_output_dim)
|
| 1994 |
-
self.classifier = nn.Linear(config.xvector_output_dim, config.xvector_output_dim)
|
| 1995 |
-
|
| 1996 |
-
self.objective = AMSoftmaxLoss(config.xvector_output_dim, config.num_labels)
|
| 1997 |
-
|
| 1998 |
-
self.init_weights()
|
| 1999 |
-
|
| 2000 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForXVector.freeze_feature_encoder with wav2vec2->wav2vec2_conformer
|
| 2001 |
-
def freeze_feature_encoder(self):
|
| 2002 |
-
"""
|
| 2003 |
-
Calling this function will disable the gradient computation for the feature encoder so that its parameter will
|
| 2004 |
-
not be updated during training.
|
| 2005 |
-
"""
|
| 2006 |
-
self.wav2vec2_conformer.feature_extractor._freeze_parameters()
|
| 2007 |
-
|
| 2008 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForXVector.freeze_base_model with wav2vec2->wav2vec2_conformer
|
| 2009 |
-
def freeze_base_model(self):
|
| 2010 |
-
"""
|
| 2011 |
-
Calling this function will disable the gradient computation for the base model so that its parameters will not
|
| 2012 |
-
be updated during training. Only the classification head will be updated.
|
| 2013 |
-
"""
|
| 2014 |
-
for param in self.wav2vec2_conformer.parameters():
|
| 2015 |
-
param.requires_grad = False
|
| 2016 |
-
|
| 2017 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForXVector._get_tdnn_output_lengths with wav2vec2->wav2vec2_conformer
|
| 2018 |
-
def _get_tdnn_output_lengths(self, input_lengths: Union[torch.LongTensor, int]):
|
| 2019 |
-
"""
|
| 2020 |
-
Computes the output length of the TDNN layers
|
| 2021 |
-
"""
|
| 2022 |
-
|
| 2023 |
-
def _conv_out_length(input_length, kernel_size, stride):
|
| 2024 |
-
# 1D convolutional layer output length formula taken
|
| 2025 |
-
# from https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html
|
| 2026 |
-
return (input_length - kernel_size) // stride + 1
|
| 2027 |
-
|
| 2028 |
-
for kernel_size in self.config.tdnn_kernel:
|
| 2029 |
-
input_lengths = _conv_out_length(input_lengths, kernel_size, 1)
|
| 2030 |
-
|
| 2031 |
-
return input_lengths
|
| 2032 |
-
|
| 2033 |
-
@add_start_docstrings_to_model_forward(WAV2VEC2_CONFORMER_INPUTS_DOCSTRING)
|
| 2034 |
-
@add_code_sample_docstrings(
|
| 2035 |
-
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 2036 |
-
output_type=XVectorOutput,
|
| 2037 |
-
config_class=_CONFIG_FOR_DOC,
|
| 2038 |
-
modality="audio",
|
| 2039 |
-
)
|
| 2040 |
-
# Copied from transformers.models.wav2vec2.modeling_wav2vec2.Wav2Vec2ForXVector.forward with Wav2Vec2->Wav2Vec2Conformer,wav2vec2->wav2vec2_conformer,WAV_2_VEC_2->WAV2VEC2_CONFORMER
|
| 2041 |
-
def forward(
|
| 2042 |
-
self,
|
| 2043 |
-
input_values: Optional[torch.Tensor],
|
| 2044 |
-
attention_mask: Optional[torch.Tensor] = None,
|
| 2045 |
-
output_attentions: Optional[bool] = None,
|
| 2046 |
-
output_hidden_states: Optional[bool] = None,
|
| 2047 |
-
return_dict: Optional[bool] = None,
|
| 2048 |
-
labels: Optional[torch.Tensor] = None,
|
| 2049 |
-
) -> Union[Tuple, XVectorOutput]:
|
| 2050 |
-
r"""
|
| 2051 |
-
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 2052 |
-
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 2053 |
-
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 2054 |
-
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 2055 |
-
"""
|
| 2056 |
-
|
| 2057 |
-
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 2058 |
-
output_hidden_states = True if self.config.use_weighted_layer_sum else output_hidden_states
|
| 2059 |
-
|
| 2060 |
-
outputs = self.wav2vec2_conformer(
|
| 2061 |
-
input_values,
|
| 2062 |
-
attention_mask=attention_mask,
|
| 2063 |
-
output_attentions=output_attentions,
|
| 2064 |
-
output_hidden_states=output_hidden_states,
|
| 2065 |
-
return_dict=return_dict,
|
| 2066 |
-
)
|
| 2067 |
-
|
| 2068 |
-
if self.config.use_weighted_layer_sum:
|
| 2069 |
-
hidden_states = outputs[_HIDDEN_STATES_START_POSITION]
|
| 2070 |
-
hidden_states = torch.stack(hidden_states, dim=1)
|
| 2071 |
-
norm_weights = nn.functional.softmax(self.layer_weights, dim=-1)
|
| 2072 |
-
hidden_states = (hidden_states * norm_weights.view(-1, 1, 1)).sum(dim=1)
|
| 2073 |
-
else:
|
| 2074 |
-
hidden_states = outputs[0]
|
| 2075 |
-
|
| 2076 |
-
hidden_states = self.projector(hidden_states)
|
| 2077 |
-
|
| 2078 |
-
for tdnn_layer in self.tdnn:
|
| 2079 |
-
hidden_states = tdnn_layer(hidden_states)
|
| 2080 |
-
|
| 2081 |
-
# Statistic Pooling
|
| 2082 |
-
if attention_mask is None:
|
| 2083 |
-
mean_features = hidden_states.mean(dim=1)
|
| 2084 |
-
std_features = hidden_states.std(dim=1)
|
| 2085 |
-
else:
|
| 2086 |
-
feat_extract_output_lengths = self._get_feat_extract_output_lengths(attention_mask.sum(dim=1))
|
| 2087 |
-
tdnn_output_lengths = self._get_tdnn_output_lengths(feat_extract_output_lengths)
|
| 2088 |
-
mean_features = []
|
| 2089 |
-
std_features = []
|
| 2090 |
-
for i, length in enumerate(tdnn_output_lengths):
|
| 2091 |
-
mean_features.append(hidden_states[i, :length].mean(dim=0))
|
| 2092 |
-
std_features.append(hidden_states[i, :length].std(dim=0))
|
| 2093 |
-
mean_features = torch.stack(mean_features)
|
| 2094 |
-
std_features = torch.stack(std_features)
|
| 2095 |
-
statistic_pooling = torch.cat([mean_features, std_features], dim=-1)
|
| 2096 |
-
|
| 2097 |
-
output_embeddings = self.feature_extractor(statistic_pooling)
|
| 2098 |
-
logits = self.classifier(output_embeddings)
|
| 2099 |
-
|
| 2100 |
-
loss = None
|
| 2101 |
-
if labels is not None:
|
| 2102 |
-
loss = self.objective(logits, labels)
|
| 2103 |
-
|
| 2104 |
-
if not return_dict:
|
| 2105 |
-
output = (logits, output_embeddings) + outputs[_HIDDEN_STATES_START_POSITION:]
|
| 2106 |
-
return ((loss,) + output) if loss is not None else output
|
| 2107 |
-
|
| 2108 |
-
return XVectorOutput(
|
| 2109 |
-
loss=loss,
|
| 2110 |
-
logits=logits,
|
| 2111 |
-
embeddings=output_embeddings,
|
| 2112 |
-
hidden_states=outputs.hidden_states,
|
| 2113 |
-
attentions=outputs.attentions,
|
| 2114 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/random_quantizer.py
DELETED
|
@@ -1,68 +0,0 @@
|
|
| 1 |
-
import torch
|
| 2 |
-
from torch import nn, einsum
|
| 3 |
-
from einops import rearrange
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class RandomProjectionQuantizer(nn.Module):
|
| 7 |
-
"""
|
| 8 |
-
Random projection and codebook lookup module
|
| 9 |
-
|
| 10 |
-
Some code is borrowed from:
|
| 11 |
-
https://github.com/lucidrains/vector-quantize-pytorch/blob/master/vector_quantize_pytorch/random_projection_quantizer.py
|
| 12 |
-
But I did normalization using pre-computed global mean & variance instead of using layer norm.
|
| 13 |
-
"""
|
| 14 |
-
|
| 15 |
-
def __init__(
|
| 16 |
-
self,
|
| 17 |
-
input_dim,
|
| 18 |
-
codebook_dim,
|
| 19 |
-
codebook_size,
|
| 20 |
-
seed=142,
|
| 21 |
-
):
|
| 22 |
-
super().__init__()
|
| 23 |
-
|
| 24 |
-
# random seed
|
| 25 |
-
torch.manual_seed(seed)
|
| 26 |
-
|
| 27 |
-
# randomly initialized projection
|
| 28 |
-
random_projection = torch.empty(input_dim, codebook_dim)
|
| 29 |
-
nn.init.xavier_normal_(random_projection)
|
| 30 |
-
self.register_buffer("random_projection", random_projection)
|
| 31 |
-
|
| 32 |
-
# randomly initialized codebook
|
| 33 |
-
codebook = torch.empty(codebook_size, codebook_dim)
|
| 34 |
-
nn.init.normal_(codebook)
|
| 35 |
-
self.register_buffer("codebook", codebook)
|
| 36 |
-
|
| 37 |
-
def codebook_lookup(self, x):
|
| 38 |
-
# reshape
|
| 39 |
-
b = x.shape[0]
|
| 40 |
-
x = rearrange(x, "b n e -> (b n) e")
|
| 41 |
-
|
| 42 |
-
# L2 normalization
|
| 43 |
-
normalized_x = nn.functional.normalize(x, dim=1, p=2)
|
| 44 |
-
normalized_codebook = nn.functional.normalize(self.codebook, dim=1, p=2)
|
| 45 |
-
|
| 46 |
-
# compute distances
|
| 47 |
-
distances = torch.cdist(normalized_codebook, normalized_x)
|
| 48 |
-
|
| 49 |
-
# get nearest
|
| 50 |
-
nearest_indices = torch.argmin(distances, dim=0)
|
| 51 |
-
|
| 52 |
-
# reshape
|
| 53 |
-
xq = rearrange(nearest_indices, "(b n) -> b n", b=b)
|
| 54 |
-
|
| 55 |
-
return xq
|
| 56 |
-
|
| 57 |
-
@torch.no_grad()
|
| 58 |
-
def forward(self, x):
|
| 59 |
-
# always eval
|
| 60 |
-
self.eval()
|
| 61 |
-
|
| 62 |
-
# random projection [batch, length, input_dim] -> [batch, length, codebook_dim]
|
| 63 |
-
x = einsum("b n d, d e -> b n e", x, self.random_projection)
|
| 64 |
-
|
| 65 |
-
# codebook lookup
|
| 66 |
-
xq = self.codebook_lookup(x)
|
| 67 |
-
|
| 68 |
-
return xq
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/modules/rvq.py
DELETED
|
@@ -1,314 +0,0 @@
|
|
| 1 |
-
|
| 2 |
-
from typing import Union
|
| 3 |
-
|
| 4 |
-
import numpy as np
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn as nn
|
| 7 |
-
import torch.nn.functional as F
|
| 8 |
-
from einops import rearrange
|
| 9 |
-
try:
|
| 10 |
-
from torch.nn.utils import weight_norm
|
| 11 |
-
except:
|
| 12 |
-
try:
|
| 13 |
-
from torch.nn.utils.parametrizations import weight_norm
|
| 14 |
-
except:
|
| 15 |
-
from torch.nn.utils.parametrize import weight_norm
|
| 16 |
-
|
| 17 |
-
def WNConv1d(*args, **kwargs):
|
| 18 |
-
return weight_norm(nn.Conv1d(*args, **kwargs))
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
class VectorQuantize(nn.Module):
|
| 22 |
-
"""
|
| 23 |
-
Implementation of VQ similar to Karpathy's repo:
|
| 24 |
-
https://github.com/karpathy/deep-vector-quantization
|
| 25 |
-
Additionally uses following tricks from Improved VQGAN
|
| 26 |
-
(https://arxiv.org/pdf/2110.04627.pdf):
|
| 27 |
-
1. Factorized codes: Perform nearest neighbor lookup in low-dimensional space
|
| 28 |
-
for improved codebook usage
|
| 29 |
-
2. l2-normalized codes: Converts euclidean distance to cosine similarity which
|
| 30 |
-
improves training stability
|
| 31 |
-
"""
|
| 32 |
-
|
| 33 |
-
def __init__(self, input_dim: int, codebook_size: int, codebook_dim: int, stale_tolerance: int = 1000, mfcc_clustering=False, n_layer=1):
|
| 34 |
-
super().__init__()
|
| 35 |
-
self.codebook_size = codebook_size
|
| 36 |
-
self.codebook_dim = codebook_dim
|
| 37 |
-
self.mfcc_clustering = mfcc_clustering
|
| 38 |
-
|
| 39 |
-
ProjClass = nn.Identity if mfcc_clustering else WNConv1d
|
| 40 |
-
if n_layer==1:
|
| 41 |
-
self.in_proj = ProjClass(input_dim, codebook_dim, kernel_size=1)
|
| 42 |
-
self.out_proj = ProjClass(codebook_dim, input_dim, kernel_size=1)
|
| 43 |
-
elif n_layer >= 2:
|
| 44 |
-
ndim_hidden = 128
|
| 45 |
-
self.in_proj = nn.Sequential(
|
| 46 |
-
ProjClass(input_dim, ndim_hidden, kernel_size=1),
|
| 47 |
-
*[nn.Sequential(nn.ReLU(), ProjClass(ndim_hidden, ndim_hidden, kernel_size=1),) for _ in range(n_layer-2)],
|
| 48 |
-
nn.ReLU(),
|
| 49 |
-
ProjClass(ndim_hidden, codebook_dim, kernel_size=1)
|
| 50 |
-
)
|
| 51 |
-
self.out_proj = nn.Sequential(
|
| 52 |
-
ProjClass(codebook_dim, ndim_hidden, kernel_size=1),
|
| 53 |
-
nn.ReLU(),
|
| 54 |
-
*[nn.Sequential(ProjClass(ndim_hidden, ndim_hidden, kernel_size=1), nn.ReLU()) for _ in range(n_layer-2)],
|
| 55 |
-
ProjClass(ndim_hidden, input_dim, kernel_size=1),
|
| 56 |
-
)
|
| 57 |
-
self.codebook = nn.Embedding(codebook_size, codebook_dim)
|
| 58 |
-
self.register_buffer("stale_counter", torch.zeros(self.codebook_size,))
|
| 59 |
-
self.stale_tolerance = stale_tolerance
|
| 60 |
-
|
| 61 |
-
def forward(self, z):
|
| 62 |
-
"""Quantized the input tensor using a fixed codebook and returns
|
| 63 |
-
the corresponding codebook vectors
|
| 64 |
-
|
| 65 |
-
Parameters
|
| 66 |
-
----------
|
| 67 |
-
z : Tensor[B x D x T]
|
| 68 |
-
|
| 69 |
-
Returns
|
| 70 |
-
-------
|
| 71 |
-
Tensor[B x D x T]
|
| 72 |
-
Quantized continuous representation of input
|
| 73 |
-
Tensor[1]
|
| 74 |
-
Commitment loss to train encoder to predict vectors closer to codebook
|
| 75 |
-
entries
|
| 76 |
-
Tensor[1]
|
| 77 |
-
Codebook loss to update the codebook
|
| 78 |
-
Tensor[B x T]
|
| 79 |
-
Codebook indices (quantized discrete representation of input)
|
| 80 |
-
Tensor[B x D x T]
|
| 81 |
-
Projected latents (continuous representation of input before quantization)
|
| 82 |
-
"""
|
| 83 |
-
|
| 84 |
-
# Factorized codes (ViT-VQGAN) Project input into low-dimensional space
|
| 85 |
-
|
| 86 |
-
z_e = self.in_proj(z) # z_e : (B x D x T)
|
| 87 |
-
z_q, indices = self.decode_latents(z_e)
|
| 88 |
-
|
| 89 |
-
commitment_loss = F.mse_loss(z_e, z_q.detach(), reduction="none").mean([1, 2])
|
| 90 |
-
codebook_loss = F.mse_loss(z_q, z_e.detach(), reduction="none").mean([1, 2])
|
| 91 |
-
|
| 92 |
-
z_q = (
|
| 93 |
-
z_e + (z_q - z_e).detach()
|
| 94 |
-
) # noop in forward pass, straight-through gradient estimator in backward pass
|
| 95 |
-
|
| 96 |
-
z_q = self.out_proj(z_q)
|
| 97 |
-
|
| 98 |
-
return z_q, commitment_loss, codebook_loss, indices, z_e
|
| 99 |
-
|
| 100 |
-
def embed_code(self, embed_id):
|
| 101 |
-
return F.embedding(embed_id, self.codebook.weight)
|
| 102 |
-
|
| 103 |
-
def decode_code(self, embed_id):
|
| 104 |
-
return self.embed_code(embed_id).transpose(1, 2)
|
| 105 |
-
|
| 106 |
-
def decode_latents(self, latents):
|
| 107 |
-
encodings = rearrange(latents, "b d t -> (b t) d")
|
| 108 |
-
codebook = self.codebook.weight # codebook: (N x D)
|
| 109 |
-
|
| 110 |
-
# L2 normalize encodings and codebook (ViT-VQGAN)
|
| 111 |
-
encodings = F.normalize(encodings)
|
| 112 |
-
codebook = F.normalize(codebook)
|
| 113 |
-
|
| 114 |
-
# Compute euclidean distance with codebook
|
| 115 |
-
dist = (
|
| 116 |
-
encodings.pow(2).sum(1, keepdim=True)
|
| 117 |
-
- 2 * encodings @ codebook.t()
|
| 118 |
-
+ codebook.pow(2).sum(1, keepdim=True).t()
|
| 119 |
-
)
|
| 120 |
-
indices = rearrange((-dist).max(1)[1], "(b t) -> b t", b=latents.size(0))
|
| 121 |
-
z_q = self.decode_code(indices)
|
| 122 |
-
|
| 123 |
-
if(self.training):
|
| 124 |
-
onehots = torch.nn.functional.one_hot(indices, self.codebook_size).float() # B, T, codebook_size
|
| 125 |
-
stale_codes = (onehots.sum(0).sum(0) == 0).float()
|
| 126 |
-
self.stale_counter = self.stale_counter * stale_codes + stale_codes
|
| 127 |
-
|
| 128 |
-
# random replace codes that haven't been used for a while
|
| 129 |
-
replace_code = (self.stale_counter == self.stale_tolerance).float() # codebook_size
|
| 130 |
-
if replace_code.sum(-1) > 0:
|
| 131 |
-
print("Replace {} codes".format(replace_code.sum(-1)))
|
| 132 |
-
random_input_idx = torch.randperm(encodings.shape[0])
|
| 133 |
-
random_input = encodings[random_input_idx].view(encodings.shape)
|
| 134 |
-
if random_input.shape[0] < self.codebook_size:
|
| 135 |
-
random_input = torch.cat([random_input]*(self.codebook_size // random_input.shape[0] + 1), 0)
|
| 136 |
-
random_input = random_input[:self.codebook_size,:].contiguous() # codebook_size, dim
|
| 137 |
-
|
| 138 |
-
self.codebook.weight.data = self.codebook.weight.data * (1 - replace_code).unsqueeze(-1) + random_input * replace_code.unsqueeze(-1)
|
| 139 |
-
self.stale_counter = self.stale_counter * (1 - replace_code)
|
| 140 |
-
|
| 141 |
-
return z_q, indices
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
class ResidualVectorQuantize(nn.Module):
|
| 145 |
-
"""
|
| 146 |
-
Introduced in SoundStream: An end2end neural audio codec
|
| 147 |
-
https://arxiv.org/abs/2107.03312
|
| 148 |
-
"""
|
| 149 |
-
|
| 150 |
-
def __init__(
|
| 151 |
-
self,
|
| 152 |
-
input_dim: int = 512,
|
| 153 |
-
n_codebooks: int = 9,
|
| 154 |
-
codebook_size: int = 1024,
|
| 155 |
-
codebook_dim: Union[int, list] = 8,
|
| 156 |
-
quantizer_dropout: float = 0.0,
|
| 157 |
-
stale_tolerance: int = 100,
|
| 158 |
-
use_multi_layer_num:int = 1,
|
| 159 |
-
):
|
| 160 |
-
super().__init__()
|
| 161 |
-
if isinstance(codebook_dim, int):
|
| 162 |
-
codebook_dim = [codebook_dim for _ in range(n_codebooks)]
|
| 163 |
-
|
| 164 |
-
self.n_codebooks = n_codebooks
|
| 165 |
-
self.codebook_dim = codebook_dim
|
| 166 |
-
self.codebook_size = codebook_size
|
| 167 |
-
|
| 168 |
-
self.quantizers = nn.ModuleList(
|
| 169 |
-
[
|
| 170 |
-
VectorQuantize(input_dim, codebook_size, codebook_dim[i], stale_tolerance=stale_tolerance, n_layer=use_multi_layer_num)
|
| 171 |
-
for i in range(n_codebooks)
|
| 172 |
-
]
|
| 173 |
-
)
|
| 174 |
-
self.quantizer_dropout = quantizer_dropout
|
| 175 |
-
|
| 176 |
-
def forward(self, z, n_quantizers: int = None):
|
| 177 |
-
"""Quantized the input tensor using a fixed set of `n` codebooks and returns
|
| 178 |
-
the corresponding codebook vectors
|
| 179 |
-
Parameters
|
| 180 |
-
----------
|
| 181 |
-
z : Tensor[B x D x T]
|
| 182 |
-
n_quantizers : int, optional
|
| 183 |
-
No. of quantizers to use
|
| 184 |
-
(n_quantizers < self.n_codebooks ex: for quantizer dropout)
|
| 185 |
-
Note: if `self.quantizer_dropout` is True, this argument is ignored
|
| 186 |
-
when in training mode, and a random number of quantizers is used.
|
| 187 |
-
Returns
|
| 188 |
-
-------
|
| 189 |
-
dict
|
| 190 |
-
A dictionary with the following keys:
|
| 191 |
-
|
| 192 |
-
"z" : Tensor[B x D x T]
|
| 193 |
-
Quantized continuous representation of input
|
| 194 |
-
"codes" : Tensor[B x N x T]
|
| 195 |
-
Codebook indices for each codebook
|
| 196 |
-
(quantized discrete representation of input)
|
| 197 |
-
"latents" : Tensor[B x N*D x T]
|
| 198 |
-
Projected latents (continuous representation of input before quantization)
|
| 199 |
-
"vq/commitment_loss" : Tensor[1]
|
| 200 |
-
Commitment loss to train encoder to predict vectors closer to codebook
|
| 201 |
-
entries
|
| 202 |
-
"vq/codebook_loss" : Tensor[1]
|
| 203 |
-
Codebook loss to update the codebook
|
| 204 |
-
"""
|
| 205 |
-
z_q = 0
|
| 206 |
-
residual = z
|
| 207 |
-
commitment_loss = 0
|
| 208 |
-
codebook_loss = 0
|
| 209 |
-
|
| 210 |
-
codebook_indices = []
|
| 211 |
-
latents = []
|
| 212 |
-
|
| 213 |
-
if n_quantizers is None:
|
| 214 |
-
n_quantizers = self.n_codebooks
|
| 215 |
-
if self.training:
|
| 216 |
-
n_quantizers = torch.ones((z.shape[0],)) * self.n_codebooks + 1
|
| 217 |
-
dropout = torch.randint(1, self.n_codebooks + 1, (z.shape[0],))
|
| 218 |
-
n_dropout = int(z.shape[0] * self.quantizer_dropout)
|
| 219 |
-
n_quantizers[:n_dropout] = dropout[:n_dropout]
|
| 220 |
-
n_quantizers = n_quantizers.to(z.device)
|
| 221 |
-
else:
|
| 222 |
-
n_quantizers = torch.ones((z.shape[0],)) * n_quantizers + 1
|
| 223 |
-
n_quantizers = n_quantizers.to(z.device)
|
| 224 |
-
|
| 225 |
-
for i, quantizer in enumerate(self.quantizers):
|
| 226 |
-
# if self.training is False and i >= n_quantizers:
|
| 227 |
-
# break
|
| 228 |
-
|
| 229 |
-
z_q_i, commitment_loss_i, codebook_loss_i, indices_i, z_e_i = quantizer(
|
| 230 |
-
residual
|
| 231 |
-
)
|
| 232 |
-
|
| 233 |
-
# Create mask to apply quantizer dropout
|
| 234 |
-
mask = (
|
| 235 |
-
torch.full((z.shape[0],), fill_value=i, device=z.device) < n_quantizers
|
| 236 |
-
)
|
| 237 |
-
z_q = z_q + z_q_i * mask[:, None, None]
|
| 238 |
-
residual = residual - z_q_i
|
| 239 |
-
|
| 240 |
-
# Sum losses
|
| 241 |
-
commitment_loss += (commitment_loss_i * mask).mean()
|
| 242 |
-
codebook_loss += (codebook_loss_i * mask).mean()
|
| 243 |
-
|
| 244 |
-
codebook_indices.append(indices_i)
|
| 245 |
-
latents.append(z_e_i)
|
| 246 |
-
|
| 247 |
-
codes = torch.stack(codebook_indices, dim=1)
|
| 248 |
-
latents = torch.cat(latents, dim=1)
|
| 249 |
-
|
| 250 |
-
encodings = F.one_hot(codes, self.codebook_size).float() # B N T 1024
|
| 251 |
-
|
| 252 |
-
return z_q, codes, latents, commitment_loss, codebook_loss, n_quantizers.clamp(max=self.n_codebooks).long() - 1
|
| 253 |
-
|
| 254 |
-
def get_loss(self, x, quantized_prompt_embeds, commitment_loss, codebook_loss):
|
| 255 |
-
final_loss = commitment_loss * 0.25 + codebook_loss * 1.0 + (x - quantized_prompt_embeds).abs().mean()
|
| 256 |
-
return final_loss
|
| 257 |
-
|
| 258 |
-
def from_codes(self, codes: torch.Tensor):
|
| 259 |
-
"""Given the quantized codes, reconstruct the continuous representation
|
| 260 |
-
Parameters
|
| 261 |
-
----------
|
| 262 |
-
codes : Tensor[B x N x T]
|
| 263 |
-
Quantized discrete representation of input
|
| 264 |
-
Returns
|
| 265 |
-
-------
|
| 266 |
-
Tensor[B x D x T]
|
| 267 |
-
Quantized continuous representation of input
|
| 268 |
-
"""
|
| 269 |
-
z_q = 0.0
|
| 270 |
-
z_p = []
|
| 271 |
-
n_codebooks = codes.shape[1]
|
| 272 |
-
for i in range(n_codebooks):
|
| 273 |
-
z_p_i = self.quantizers[i].decode_code(codes[:, i, :])
|
| 274 |
-
z_p.append(z_p_i)
|
| 275 |
-
|
| 276 |
-
z_q_i = self.quantizers[i].out_proj(z_p_i)
|
| 277 |
-
z_q = z_q + z_q_i
|
| 278 |
-
return z_q, torch.cat(z_p, dim=1), codes
|
| 279 |
-
|
| 280 |
-
def from_latents(self, latents: torch.Tensor):
|
| 281 |
-
"""Given the unquantized latents, reconstruct the
|
| 282 |
-
continuous representation after quantization.
|
| 283 |
-
|
| 284 |
-
Parameters
|
| 285 |
-
----------
|
| 286 |
-
latents : Tensor[B x N x T]
|
| 287 |
-
Continuous representation of input after projection
|
| 288 |
-
|
| 289 |
-
Returns
|
| 290 |
-
-------
|
| 291 |
-
Tensor[B x D x T]
|
| 292 |
-
Quantized representation of full-projected space
|
| 293 |
-
Tensor[B x D x T]
|
| 294 |
-
Quantized representation of latent space
|
| 295 |
-
"""
|
| 296 |
-
z_q = 0
|
| 297 |
-
z_p = []
|
| 298 |
-
codes = []
|
| 299 |
-
dims = np.cumsum([0] + [q.codebook_dim for q in self.quantizers])
|
| 300 |
-
|
| 301 |
-
n_codebooks = np.where(dims <= latents.shape[1])[0].max(axis=0, keepdims=True)[
|
| 302 |
-
0
|
| 303 |
-
]
|
| 304 |
-
for i in range(n_codebooks):
|
| 305 |
-
j, k = dims[i], dims[i + 1]
|
| 306 |
-
z_p_i, codes_i = self.quantizers[i].decode_latents(latents[:, j:k, :])
|
| 307 |
-
z_p.append(z_p_i)
|
| 308 |
-
codes.append(codes_i)
|
| 309 |
-
|
| 310 |
-
z_q_i = self.quantizers[i].out_proj(z_p_i)
|
| 311 |
-
z_q = z_q + z_q_i
|
| 312 |
-
|
| 313 |
-
return z_q, torch.cat(z_p, dim=1), torch.stack(codes, dim=1)
|
| 314 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq/muq.py
DELETED
|
@@ -1,90 +0,0 @@
|
|
| 1 |
-
import torch.nn as nn
|
| 2 |
-
import torch
|
| 3 |
-
from .models.muq_model import MuQModel
|
| 4 |
-
from dataclasses import dataclass, field
|
| 5 |
-
from typing import List, Optional
|
| 6 |
-
from transformers.modeling_outputs import BaseModelOutput
|
| 7 |
-
from huggingface_hub import PyTorchModelHubMixin
|
| 8 |
-
|
| 9 |
-
@dataclass
|
| 10 |
-
class MuQConfig:
|
| 11 |
-
label_rate:int = field(default=25)
|
| 12 |
-
num_codebooks:int = field(default=1)
|
| 13 |
-
codebook_dim:int = field(default=16)
|
| 14 |
-
codebook_size:int = field(default=4096)
|
| 15 |
-
features:List[str] = field(default_factory=lambda:["melspec_2048"])
|
| 16 |
-
hop_length:int = field(default=240)
|
| 17 |
-
n_mels:int = field(default=128)
|
| 18 |
-
conv_dim:int = field(default=512)
|
| 19 |
-
encoder_dim:int = field(default=1024)
|
| 20 |
-
encoder_depth:int = field(default=12)
|
| 21 |
-
mask_hop:float = field(default=0.4)
|
| 22 |
-
mask_prob:float = field(default=0.6)
|
| 23 |
-
is_flash:bool = field(default=False)
|
| 24 |
-
stat:Optional[dict] = field(default_factory=dict)
|
| 25 |
-
w2v2_config:Optional[dict] = field(default_factory=dict)
|
| 26 |
-
use_rvq_target:bool = field(default=False)
|
| 27 |
-
use_vq_target:bool = field(default=False)
|
| 28 |
-
use_encodec_target:bool = field(default=False)
|
| 29 |
-
rvq_ckpt_path: Optional[str] = field(default=None)
|
| 30 |
-
recon_loss_ratio: Optional[float] = field(default=None)
|
| 31 |
-
resume_checkpoint: Optional[str] = None
|
| 32 |
-
rvq_n_codebooks:int = field(default=8)
|
| 33 |
-
rvq_multi_layer_num:int = field(default=1)
|
| 34 |
-
|
| 35 |
-
class MuQ(nn.Module, PyTorchModelHubMixin):
|
| 36 |
-
def __init__(self, config: MuQConfig):
|
| 37 |
-
super().__init__()
|
| 38 |
-
if isinstance(config, dict):
|
| 39 |
-
config = MuQConfig(**config)
|
| 40 |
-
self.config = config
|
| 41 |
-
self.model = MuQModel(
|
| 42 |
-
num_codebooks=config.num_codebooks,
|
| 43 |
-
codebook_dim=config.codebook_dim,
|
| 44 |
-
codebook_size=config.codebook_size,
|
| 45 |
-
features=config.features,
|
| 46 |
-
hop_length=config.hop_length,
|
| 47 |
-
n_mels=config.n_mels,
|
| 48 |
-
conv_dim=config.conv_dim,
|
| 49 |
-
encoder_dim=config.encoder_dim,
|
| 50 |
-
encoder_depth=config.encoder_depth,
|
| 51 |
-
mask_hop=config.mask_hop,
|
| 52 |
-
mask_prob=config.mask_prob,
|
| 53 |
-
is_flash=config.is_flash,
|
| 54 |
-
stat=config.stat,
|
| 55 |
-
w2v2_config=config.w2v2_config,
|
| 56 |
-
use_rvq_target=config.use_rvq_target,
|
| 57 |
-
use_vq_target=config.use_vq_target,
|
| 58 |
-
use_encodec_target=config.use_encodec_target,
|
| 59 |
-
rvq_ckpt_path=config.rvq_ckpt_path,
|
| 60 |
-
recon_loss_ratio=config.recon_loss_ratio,
|
| 61 |
-
label_rate=config.label_rate,
|
| 62 |
-
rvq_n_codebooks=config.rvq_n_codebooks,
|
| 63 |
-
rvq_multi_layer_num=config.rvq_multi_layer_num,
|
| 64 |
-
)
|
| 65 |
-
|
| 66 |
-
def forward(self, x, attention_mask:Optional[torch.Tensor]=None, output_hidden_states:bool=True) ->BaseModelOutput:
|
| 67 |
-
"""
|
| 68 |
-
Forward pass through the MuQ model and extract features.
|
| 69 |
-
|
| 70 |
-
Args:
|
| 71 |
-
x (torch.Tensor): Input waveform tensor of shape (batch_size, time).
|
| 72 |
-
attention_mask (torch.Tensor, optional): Mask to avoid performing attention on padding token indices.
|
| 73 |
-
Default is None.
|
| 74 |
-
output_hidden_states (bool, optional): Whether to return all hidden states or only the last one.
|
| 75 |
-
Default is False.
|
| 76 |
-
|
| 77 |
-
Returns:
|
| 78 |
-
BaseModelOutput: An object containing the last hidden state and optionally all hidden states.
|
| 79 |
-
- last_hidden_state (torch.Tensor): The last hidden state of the model, i.e. extracted MuQ features, of shape (batch_size, sequence_length, hidden_size).
|
| 80 |
-
- hidden_states (tuple(torch.Tensor), optional): A tuple containing all hidden states produced by the model,
|
| 81 |
-
each of shape (batch_size, sequence_length, hidden_size). Only returned if output_hidden_states is True.
|
| 82 |
-
"""
|
| 83 |
-
_, hidden_states = self.model.get_predictions(x, attention_mask=attention_mask, is_features_only=True)
|
| 84 |
-
last_hidden_state = hidden_states[-1]
|
| 85 |
-
if not output_hidden_states:
|
| 86 |
-
return BaseModelOutput(last_hidden_state=last_hidden_state)
|
| 87 |
-
return BaseModelOutput(
|
| 88 |
-
last_hidden_state=last_hidden_state,
|
| 89 |
-
hidden_states=hidden_states
|
| 90 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
from .muq_mulan import MuQMuLan, MuQMuLanConfig, MuLanConfig, ModalModelConfig, TextTransformerConfig, AudioTransformerConfig
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/models/__init__.py
DELETED
|
File without changes
|
src/third_party/MuQ/src/muq/muq_mulan/models/audio.py
DELETED
|
@@ -1,294 +0,0 @@
|
|
| 1 |
-
from contextlib import suppress
|
| 2 |
-
import torch
|
| 3 |
-
import torch.nn as nn
|
| 4 |
-
from einops import rearrange, repeat, reduce
|
| 5 |
-
from einops.layers.torch import Rearrange
|
| 6 |
-
from torchaudio.transforms import Spectrogram, TimeStretch, FrequencyMasking, TimeMasking
|
| 7 |
-
from transformers import Wav2Vec2FeatureExtractor,AutoModel
|
| 8 |
-
from ..modules.transformer import Transformer, LayerNorm, posemb_sincos_2d
|
| 9 |
-
from ..modules.utils import print_once, round_down_nearest_multiple, frozen_params, Sequential
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def pair(t):
|
| 13 |
-
return (t, t) if not isinstance(t, tuple) else t
|
| 14 |
-
|
| 15 |
-
class AudioSpectrogramTransformer(nn.Module):
|
| 16 |
-
def __init__(
|
| 17 |
-
self,
|
| 18 |
-
dim,
|
| 19 |
-
depth,
|
| 20 |
-
patch_size = 16,
|
| 21 |
-
dim_head = 64,
|
| 22 |
-
heads = 8,
|
| 23 |
-
attn_dropout = 0.,
|
| 24 |
-
ff_mult = 4,
|
| 25 |
-
ff_dropout = 0.,
|
| 26 |
-
accept_spec = False,
|
| 27 |
-
accept_spec_time_first = True,
|
| 28 |
-
spec_n_fft = 128,
|
| 29 |
-
spec_power = 2,
|
| 30 |
-
spec_win_length = 24,
|
| 31 |
-
spec_hop_length = None,
|
| 32 |
-
spec_pad = 0,
|
| 33 |
-
spec_center = True,
|
| 34 |
-
spec_pad_mode = 'reflect',
|
| 35 |
-
spec_aug_stretch_factor = 0.8,
|
| 36 |
-
spec_aug_freq_mask = 80,
|
| 37 |
-
spec_aug_time_mask = 80,
|
| 38 |
-
patch_dropout_prob = 0.25
|
| 39 |
-
):
|
| 40 |
-
super().__init__()
|
| 41 |
-
self.dim = dim
|
| 42 |
-
self.depth = depth
|
| 43 |
-
|
| 44 |
-
self.patch_size = pair(patch_size)
|
| 45 |
-
patch_input_dim = self.patch_size[0] * self.patch_size[1]
|
| 46 |
-
|
| 47 |
-
self.to_patch_tokens = Sequential(
|
| 48 |
-
Rearrange('b (h p1) (w p2) -> b h w (p1 p2)', p1 = self.patch_size[0], p2 = self.patch_size[1]),
|
| 49 |
-
nn.LayerNorm(patch_input_dim),
|
| 50 |
-
nn.Linear(patch_input_dim, dim),
|
| 51 |
-
nn.LayerNorm(dim)
|
| 52 |
-
)
|
| 53 |
-
|
| 54 |
-
self.accept_spec = accept_spec
|
| 55 |
-
self.accept_spec_time_first = accept_spec_time_first
|
| 56 |
-
|
| 57 |
-
self.spec = Spectrogram(
|
| 58 |
-
n_fft = spec_n_fft,
|
| 59 |
-
power = spec_power,
|
| 60 |
-
win_length = spec_win_length,
|
| 61 |
-
hop_length = spec_hop_length,
|
| 62 |
-
pad = spec_pad,
|
| 63 |
-
center = spec_center,
|
| 64 |
-
pad_mode = spec_pad_mode
|
| 65 |
-
)
|
| 66 |
-
|
| 67 |
-
# SpecAugment - seems to be widely used in audio field https://arxiv.org/abs/1904.08779
|
| 68 |
-
|
| 69 |
-
self.aug = torch.nn.Sequential(
|
| 70 |
-
TimeStretch(spec_aug_stretch_factor, fixed_rate = True),
|
| 71 |
-
FrequencyMasking(freq_mask_param = spec_aug_freq_mask),
|
| 72 |
-
TimeMasking(time_mask_param = spec_aug_time_mask),
|
| 73 |
-
)
|
| 74 |
-
|
| 75 |
-
self.transformer = Transformer(
|
| 76 |
-
dim = dim,
|
| 77 |
-
depth = depth,
|
| 78 |
-
dim_head = dim_head,
|
| 79 |
-
heads = heads,
|
| 80 |
-
attn_dropout = attn_dropout,
|
| 81 |
-
ff_mult = ff_mult,
|
| 82 |
-
ff_dropout = ff_dropout
|
| 83 |
-
)
|
| 84 |
-
|
| 85 |
-
self.norm = LayerNorm(dim)
|
| 86 |
-
|
| 87 |
-
# patch dropout
|
| 88 |
-
|
| 89 |
-
self.patch_dropout_prob = patch_dropout_prob
|
| 90 |
-
|
| 91 |
-
# 2d dynamic positional bias
|
| 92 |
-
|
| 93 |
-
mlp_hidden_dim = dim // 4
|
| 94 |
-
|
| 95 |
-
self.dynamic_pos_bias_mlp = nn.Sequential(
|
| 96 |
-
nn.Linear(2, mlp_hidden_dim),
|
| 97 |
-
nn.SiLU(),
|
| 98 |
-
nn.Linear(mlp_hidden_dim, mlp_hidden_dim),
|
| 99 |
-
nn.SiLU(),
|
| 100 |
-
nn.Linear(mlp_hidden_dim, heads),
|
| 101 |
-
Rearrange('... i j h -> ... h i j')
|
| 102 |
-
)
|
| 103 |
-
|
| 104 |
-
def forward(
|
| 105 |
-
self,
|
| 106 |
-
x,
|
| 107 |
-
force_no_patch_dropout = False,
|
| 108 |
-
return_all_layers = False
|
| 109 |
-
):
|
| 110 |
-
batch, device = x.shape[0], x.device
|
| 111 |
-
assert (self.accept_spec and x.ndim == 3) or (not self.accept_spec and x.ndim == 2)
|
| 112 |
-
|
| 113 |
-
if self.accept_spec and self.accept_spec_time_first:
|
| 114 |
-
x = rearrange(x, 'b t f -> b f t')
|
| 115 |
-
|
| 116 |
-
if not self.accept_spec:
|
| 117 |
-
x = self.spec(x)
|
| 118 |
-
|
| 119 |
-
if self.training:
|
| 120 |
-
x = self.aug(x)
|
| 121 |
-
|
| 122 |
-
# automatically crop if audio does not yield a 2d spectrogram that is divisible by patch sizes
|
| 123 |
-
|
| 124 |
-
height, width = x.shape[-2:]
|
| 125 |
-
patch_height, patch_width = self.patch_size
|
| 126 |
-
|
| 127 |
-
rounded_height, rounded_width = map(lambda args: round_down_nearest_multiple(*args), ((height, patch_height), (width, patch_width)))
|
| 128 |
-
|
| 129 |
-
if (height, width) != (rounded_height, rounded_width): # just keep printing to be annoying until it is fixed
|
| 130 |
-
print_once(f'spectrogram yielded shape of {(height, width)}, but had to be cropped to {(rounded_height, rounded_width)} to be patchified for transformer')
|
| 131 |
-
|
| 132 |
-
x = x[..., :rounded_height, :rounded_width]
|
| 133 |
-
|
| 134 |
-
# to patches
|
| 135 |
-
|
| 136 |
-
x = self.to_patch_tokens(x)
|
| 137 |
-
|
| 138 |
-
# get number of patches along height and width
|
| 139 |
-
|
| 140 |
-
_, num_patch_height, num_patch_width, _ = x.shape
|
| 141 |
-
|
| 142 |
-
# get 2d relative positions
|
| 143 |
-
|
| 144 |
-
grid = torch.stack(torch.meshgrid(
|
| 145 |
-
torch.arange(num_patch_height, device = device),
|
| 146 |
-
torch.arange(num_patch_width, device = device)
|
| 147 |
-
, indexing = 'ij'), dim = -1)
|
| 148 |
-
|
| 149 |
-
grid = rearrange(grid, '... c -> (...) c')
|
| 150 |
-
|
| 151 |
-
# 2d sinusoidal positional embedding
|
| 152 |
-
|
| 153 |
-
x = x + posemb_sincos_2d(x)
|
| 154 |
-
|
| 155 |
-
x = rearrange(x, 'b ... c -> b (...) c')
|
| 156 |
-
|
| 157 |
-
# patch dropout
|
| 158 |
-
|
| 159 |
-
if self.training and self.patch_dropout_prob > 0. and not force_no_patch_dropout:
|
| 160 |
-
n, device = x.shape[1], x.device
|
| 161 |
-
|
| 162 |
-
batch_indices = torch.arange(batch, device = device)
|
| 163 |
-
batch_indices = rearrange(batch_indices, '... -> ... 1')
|
| 164 |
-
num_patches_keep = max(1, int(n * (1 - self.patch_dropout_prob)))
|
| 165 |
-
patch_indices_keep = torch.randn(batch, n, device = device).topk(num_patches_keep, dim = -1).indices
|
| 166 |
-
|
| 167 |
-
x = x[batch_indices, patch_indices_keep]
|
| 168 |
-
|
| 169 |
-
grid = repeat(grid, '... -> b ...', b = batch)
|
| 170 |
-
grid = grid[batch_indices, patch_indices_keep]
|
| 171 |
-
|
| 172 |
-
# 2d relative positional bias
|
| 173 |
-
|
| 174 |
-
rel_dist = rearrange(grid, '... i c -> ... i 1 c') - rearrange(grid, '... j c -> ... 1 j c')
|
| 175 |
-
rel_pos_bias = self.dynamic_pos_bias_mlp(rel_dist.float())
|
| 176 |
-
|
| 177 |
-
# attention, what else
|
| 178 |
-
|
| 179 |
-
x, all_layers = self.transformer(x, rel_pos_bias = rel_pos_bias, return_all_layers = True)
|
| 180 |
-
|
| 181 |
-
# final global average and norm (most recent papers show this is superior to CLS token)
|
| 182 |
-
|
| 183 |
-
x = reduce(x, 'b n d -> b d', 'mean')
|
| 184 |
-
|
| 185 |
-
out = self.norm(x)
|
| 186 |
-
|
| 187 |
-
if not return_all_layers:
|
| 188 |
-
return out
|
| 189 |
-
|
| 190 |
-
return out, all_layers
|
| 191 |
-
|
| 192 |
-
class AudioSpectrogramTransformerPretrained(nn.Module):
|
| 193 |
-
def __init__(
|
| 194 |
-
self,
|
| 195 |
-
model_name = 'm-a-p/MERT-v1-330M',
|
| 196 |
-
dim = 768,
|
| 197 |
-
model_dim = 1024,
|
| 198 |
-
sr = 24000,
|
| 199 |
-
tf_depth = 12,
|
| 200 |
-
dim_head = 64,
|
| 201 |
-
heads = 8,
|
| 202 |
-
attn_dropout = 0.,
|
| 203 |
-
ff_dropout = 0.,
|
| 204 |
-
ff_mult = 4,
|
| 205 |
-
use_layer_idx = -1,
|
| 206 |
-
frozen_pretrained = True,
|
| 207 |
-
hf_hub_cache_dir = None,
|
| 208 |
-
):
|
| 209 |
-
super().__init__()
|
| 210 |
-
self.model_name = model_name
|
| 211 |
-
self.dim = dim
|
| 212 |
-
self.sr = sr
|
| 213 |
-
self.use_layer_idx = use_layer_idx # Which layer's features should be used
|
| 214 |
-
self.hf_hub_cache_dir = hf_hub_cache_dir
|
| 215 |
-
|
| 216 |
-
self.model_name
|
| 217 |
-
|
| 218 |
-
self._init_pretrained_model(model_name)
|
| 219 |
-
|
| 220 |
-
self.aggregator = nn.Conv1d(in_channels=25, out_channels=1, kernel_size=1)
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
self.transformer = Transformer(
|
| 224 |
-
dim = dim,
|
| 225 |
-
depth = tf_depth,
|
| 226 |
-
dim_head = dim_head,
|
| 227 |
-
heads = heads,
|
| 228 |
-
attn_dropout = attn_dropout,
|
| 229 |
-
ff_dropout = ff_dropout,
|
| 230 |
-
ff_mult = ff_mult
|
| 231 |
-
) # if tf_depth > 0 else torch.nn.Identity()
|
| 232 |
-
|
| 233 |
-
self.proj = nn.Linear(model_dim, dim)
|
| 234 |
-
|
| 235 |
-
if frozen_pretrained:
|
| 236 |
-
frozen_params(self.model)
|
| 237 |
-
frozen_params(self.aggregator)
|
| 238 |
-
self.frozen_pretrained = frozen_pretrained
|
| 239 |
-
|
| 240 |
-
def _init_pretrained_model(self, model_name):
|
| 241 |
-
if 'muq' in model_name.lower():
|
| 242 |
-
from muq import MuQ
|
| 243 |
-
self.model = MuQ.from_pretrained(model_name, cache_dir=self.hf_hub_cache_dir)
|
| 244 |
-
else:
|
| 245 |
-
self.model = AutoModel.from_pretrained(model_name, trust_remote_code=True, cache_dir=self.hf_hub_cache_dir)
|
| 246 |
-
self.processor = Wav2Vec2FeatureExtractor.from_pretrained(model_name,trust_remote_code=True, cache_dir=self.hf_hub_cache_dir)
|
| 247 |
-
|
| 248 |
-
assert self.processor.sampling_rate == self.sr
|
| 249 |
-
|
| 250 |
-
@property
|
| 251 |
-
def device(self):
|
| 252 |
-
return next(self.model.parameters()).device
|
| 253 |
-
|
| 254 |
-
@property
|
| 255 |
-
def dtype(self):
|
| 256 |
-
return next(self.model.parameters()).dtype
|
| 257 |
-
|
| 258 |
-
def _forward_pretrained_model(self, x):
|
| 259 |
-
if 'muq' in self.model_name.lower():
|
| 260 |
-
outputs = self.model(x, output_hidden_states=True)
|
| 261 |
-
return outputs.hidden_states # 13 layer x [batch_size, Time steps, 1024 feature_dim]
|
| 262 |
-
else:
|
| 263 |
-
inputs = self.processor(x, sampling_rate=self.sr, return_tensors="pt")
|
| 264 |
-
input_values = inputs['input_values'].squeeze(0).to(self.device, dtype = self.dtype)
|
| 265 |
-
outputs = self.model(input_values, output_hidden_states=True) # [25 layer, batch_size, Time steps, 1024 feature_dim]
|
| 266 |
-
return outputs.hidden_states
|
| 267 |
-
|
| 268 |
-
def forward(
|
| 269 |
-
self,
|
| 270 |
-
x,
|
| 271 |
-
return_all_layers = False,
|
| 272 |
-
return_mean = True,
|
| 273 |
-
no_proj = False,
|
| 274 |
-
):
|
| 275 |
-
batch, device = x.shape[0], x.device
|
| 276 |
-
|
| 277 |
-
with torch.no_grad() if self.frozen_pretrained else suppress():
|
| 278 |
-
outputs = self._forward_pretrained_model(x)
|
| 279 |
-
layer_hidden_states = outputs[self.use_layer_idx]
|
| 280 |
-
|
| 281 |
-
if no_proj:
|
| 282 |
-
outputs = layer_hidden_states
|
| 283 |
-
else:
|
| 284 |
-
outputs = self.proj(layer_hidden_states)
|
| 285 |
-
outputs, layer_results = self.transformer(outputs, return_all_layers=True)
|
| 286 |
-
|
| 287 |
-
if return_mean:
|
| 288 |
-
outputs = outputs.mean(dim = -2)
|
| 289 |
-
|
| 290 |
-
if return_all_layers:
|
| 291 |
-
return outputs, layer_results
|
| 292 |
-
return outputs
|
| 293 |
-
|
| 294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/models/mulan.py
DELETED
|
@@ -1,148 +0,0 @@
|
|
| 1 |
-
import math
|
| 2 |
-
from typing import List, Optional, Union
|
| 3 |
-
from collections import OrderedDict
|
| 4 |
-
from functools import partial
|
| 5 |
-
|
| 6 |
-
import torch
|
| 7 |
-
from torch import nn, einsum
|
| 8 |
-
|
| 9 |
-
from .audio import AudioSpectrogramTransformer, AudioSpectrogramTransformerPretrained
|
| 10 |
-
from .text import TextTransformer, TextTransformerPretrained
|
| 11 |
-
from ..modules.contrastive import RankSoftmaxContrastiveLearning, SoftmaxContrastiveLearning, SigmoidContrastiveLearning, MultiLayerContrastiveLoss, interspersed_indices
|
| 12 |
-
from ..modules.utils import exists, default, l2norm
|
| 13 |
-
|
| 14 |
-
class MuLanModel(nn.Module):
|
| 15 |
-
def __init__(
|
| 16 |
-
self,
|
| 17 |
-
audio_transformer: Union[AudioSpectrogramTransformer, AudioSpectrogramTransformerPretrained],
|
| 18 |
-
text_transformer: Union[TextTransformer, TextTransformerPretrained],
|
| 19 |
-
dim_latent = 128, # they use 128
|
| 20 |
-
decoupled_contrastive_learning = True, # think this was used, make it optional
|
| 21 |
-
hierarchical_contrastive_loss = False,
|
| 22 |
-
hierarchical_contrastive_loss_layers = None,
|
| 23 |
-
sigmoid_contrastive_loss = False,
|
| 24 |
-
rank_contrast = False, # apply contrast on rank dimension
|
| 25 |
-
proj_to_latent = True,
|
| 26 |
-
norm_type = 'l2norm',
|
| 27 |
-
**kwargs,
|
| 28 |
-
):
|
| 29 |
-
super().__init__()
|
| 30 |
-
self.dim_latent = dim_latent
|
| 31 |
-
|
| 32 |
-
# audio and text transformer
|
| 33 |
-
self.audio = audio_transformer
|
| 34 |
-
self.text = text_transformer
|
| 35 |
-
|
| 36 |
-
# two linear layers to project embeddings to latent space
|
| 37 |
-
if proj_to_latent:
|
| 38 |
-
self.text_to_latents = nn.Linear(self.text.dim, dim_latent)
|
| 39 |
-
self.audio_to_latents = nn.Linear(self.audio.dim, dim_latent)
|
| 40 |
-
|
| 41 |
-
self.sigmoid_contrastive_loss = sigmoid_contrastive_loss
|
| 42 |
-
self.decoupled_contrastive_learning = decoupled_contrastive_learning
|
| 43 |
-
self.rank_contrast = rank_contrast
|
| 44 |
-
self.norm_type = norm_type
|
| 45 |
-
|
| 46 |
-
# use decoupled contrastive learning or not, where self.contrast is loss module for contrastive learning
|
| 47 |
-
if sigmoid_contrastive_loss:
|
| 48 |
-
klass = SigmoidContrastiveLearning
|
| 49 |
-
else:
|
| 50 |
-
if rank_contrast:
|
| 51 |
-
klass = partial(RankSoftmaxContrastiveLearning, decoupled_contrastive_learning = decoupled_contrastive_learning)
|
| 52 |
-
else:
|
| 53 |
-
klass = partial(SoftmaxContrastiveLearning, decoupled_contrastive_learning = decoupled_contrastive_learning)
|
| 54 |
-
|
| 55 |
-
self.contrast = klass()
|
| 56 |
-
|
| 57 |
-
self.multi_layer_contrastive_learning = None
|
| 58 |
-
|
| 59 |
-
if hierarchical_contrastive_loss:
|
| 60 |
-
num_layers = default(hierarchical_contrastive_loss_layers, min(audio_transformer.depth, text_transformer.depth) - 1)
|
| 61 |
-
assert num_layers > 0
|
| 62 |
-
|
| 63 |
-
self.register_buffer('text_layers_indices', interspersed_indices(num_layers, text_transformer.depth))
|
| 64 |
-
self.register_buffer('audio_layers_indices', interspersed_indices(num_layers, audio_transformer.depth))
|
| 65 |
-
|
| 66 |
-
self.multi_layer_contrastive_learning = MultiLayerContrastiveLoss(
|
| 67 |
-
audio_dim = self.audio.dim,
|
| 68 |
-
text_dim = self.text.dim,
|
| 69 |
-
dim_latent = dim_latent,
|
| 70 |
-
layers = num_layers,
|
| 71 |
-
decoupled_contrastive_learning = decoupled_contrastive_learning,
|
| 72 |
-
sigmoid_contrastive_loss = sigmoid_contrastive_loss
|
| 73 |
-
)
|
| 74 |
-
|
| 75 |
-
def get_audio_latents(
|
| 76 |
-
self,
|
| 77 |
-
wavs,
|
| 78 |
-
return_all_layers = False,
|
| 79 |
-
):
|
| 80 |
-
audio_embeds, audio_layers = self.audio(wavs, return_all_layers = True)
|
| 81 |
-
audio_latents = self.audio_to_latents(audio_embeds)
|
| 82 |
-
out = self._norm_latents(audio_latents) #->[Batch, Feat=128]
|
| 83 |
-
|
| 84 |
-
if not return_all_layers:
|
| 85 |
-
return out
|
| 86 |
-
|
| 87 |
-
return out, audio_layers #[nLayer=5, Batch=2, 15, 512]
|
| 88 |
-
|
| 89 |
-
def get_text_latents(
|
| 90 |
-
self,
|
| 91 |
-
texts = None,
|
| 92 |
-
raw_texts: Optional[List[str]] = None,
|
| 93 |
-
return_all_layers = False
|
| 94 |
-
):
|
| 95 |
-
text_embeds, text_layers = self.text(texts, raw_texts = raw_texts, return_all_layers = True)
|
| 96 |
-
text_latents = self.text_to_latents(text_embeds)
|
| 97 |
-
out = self._norm_latents(text_latents)
|
| 98 |
-
|
| 99 |
-
if not return_all_layers:
|
| 100 |
-
return out
|
| 101 |
-
|
| 102 |
-
return out, text_layers
|
| 103 |
-
|
| 104 |
-
def _norm_latents(self, latents):
|
| 105 |
-
if self.norm_type == 'l2norm':
|
| 106 |
-
return l2norm(latents)
|
| 107 |
-
else:
|
| 108 |
-
return self.norm(latents)
|
| 109 |
-
|
| 110 |
-
def forward(
|
| 111 |
-
self,
|
| 112 |
-
wavs,
|
| 113 |
-
texts = None,
|
| 114 |
-
raw_texts: Optional[List[str]] = None,
|
| 115 |
-
return_latents = False,
|
| 116 |
-
return_similarities = False,
|
| 117 |
-
return_pairwise_similarities = False,
|
| 118 |
-
):
|
| 119 |
-
batch, device = wavs.shape[0], wavs.device
|
| 120 |
-
|
| 121 |
-
# both latents are of [Batch, Feat=128]
|
| 122 |
-
audio_latents, audio_layers = self.get_audio_latents(wavs, return_all_layers = True)
|
| 123 |
-
text_latents, text_layers = self.get_text_latents(texts, raw_texts = raw_texts, return_all_layers = True)
|
| 124 |
-
|
| 125 |
-
if return_latents: # used in inference
|
| 126 |
-
return audio_latents, text_latents
|
| 127 |
-
|
| 128 |
-
if return_similarities:
|
| 129 |
-
return einsum('i d, i d -> i', audio_latents, text_latents)
|
| 130 |
-
|
| 131 |
-
if return_pairwise_similarities:
|
| 132 |
-
cosine_sim = einsum('i d, j d -> i j', audio_latents, text_latents)
|
| 133 |
-
return cosine_sim
|
| 134 |
-
|
| 135 |
-
cl_loss = self.contrast(audio_latents, text_latents) #contrastive loss
|
| 136 |
-
|
| 137 |
-
if not exists(self.multi_layer_contrastive_learning):
|
| 138 |
-
return cl_loss
|
| 139 |
-
|
| 140 |
-
audio_layers = audio_layers[self.audio_layers_indices]
|
| 141 |
-
text_layers = text_layers[self.text_layers_indices]
|
| 142 |
-
|
| 143 |
-
hierarchical_cl_loss = self.multi_layer_contrastive_learning(
|
| 144 |
-
audio_layers = audio_layers,
|
| 145 |
-
text_layers = text_layers
|
| 146 |
-
)
|
| 147 |
-
|
| 148 |
-
return cl_loss + hierarchical_cl_loss
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/models/text.py
DELETED
|
@@ -1,241 +0,0 @@
|
|
| 1 |
-
from typing import Optional, List
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
import torch.nn as nn
|
| 5 |
-
import torch.nn.functional as F
|
| 6 |
-
from x_clip.tokenizer import tokenizer
|
| 7 |
-
from einops import rearrange, repeat, reduce, pack, unpack
|
| 8 |
-
from transformers import AutoTokenizer,XLMRobertaModel,AutoModelForCausalLM
|
| 9 |
-
|
| 10 |
-
from ..modules.utils import *
|
| 11 |
-
from ..modules.transformer import Transformer, LayerNorm
|
| 12 |
-
from ..modules.utils import frozen_params
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
# text transformer
|
| 16 |
-
|
| 17 |
-
class TextTransformer(nn.Module):
|
| 18 |
-
def __init__(
|
| 19 |
-
self,
|
| 20 |
-
dim,
|
| 21 |
-
depth,
|
| 22 |
-
num_tokens = tokenizer.vocab_size,
|
| 23 |
-
max_seq_len = 256,
|
| 24 |
-
dim_head = 64,
|
| 25 |
-
heads = 8,
|
| 26 |
-
attn_dropout = 0.,
|
| 27 |
-
ff_dropout = 0.,
|
| 28 |
-
ff_mult = 4,
|
| 29 |
-
pad_id = 0
|
| 30 |
-
):
|
| 31 |
-
super().__init__()
|
| 32 |
-
self.dim = dim
|
| 33 |
-
|
| 34 |
-
self.token_emb = nn.Embedding(num_tokens, dim)
|
| 35 |
-
self.pos_emb = nn.Embedding(max_seq_len, dim)
|
| 36 |
-
|
| 37 |
-
self.depth = depth
|
| 38 |
-
self.max_seq_len = max_seq_len
|
| 39 |
-
|
| 40 |
-
self.cls_token = nn.Parameter(torch.randn(dim))
|
| 41 |
-
|
| 42 |
-
self.transformer = Transformer(
|
| 43 |
-
dim = dim,
|
| 44 |
-
depth = depth,
|
| 45 |
-
dim_head = dim_head,
|
| 46 |
-
heads = heads,
|
| 47 |
-
attn_dropout = attn_dropout,
|
| 48 |
-
ff_dropout = ff_dropout,
|
| 49 |
-
ff_mult = ff_mult
|
| 50 |
-
)
|
| 51 |
-
|
| 52 |
-
self.pad_id = pad_id
|
| 53 |
-
self.norm = LayerNorm(dim)
|
| 54 |
-
|
| 55 |
-
@property
|
| 56 |
-
def device(self):
|
| 57 |
-
return next(self.parameters()).device
|
| 58 |
-
|
| 59 |
-
def forward(
|
| 60 |
-
self,
|
| 61 |
-
x = None,
|
| 62 |
-
raw_texts: Optional[List[str]] = None,
|
| 63 |
-
mask = None,
|
| 64 |
-
return_all_layers = False
|
| 65 |
-
):
|
| 66 |
-
assert exists(x) ^ exists(raw_texts)
|
| 67 |
-
|
| 68 |
-
if exists(raw_texts):
|
| 69 |
-
x = tokenizer.tokenize(raw_texts).to(self.device)
|
| 70 |
-
|
| 71 |
-
if not exists(mask):
|
| 72 |
-
mask = x != self.pad_id
|
| 73 |
-
|
| 74 |
-
b, n, device = *x.shape, x.device
|
| 75 |
-
|
| 76 |
-
# token embedding + positional embedding
|
| 77 |
-
|
| 78 |
-
x = self.token_emb(x)
|
| 79 |
-
|
| 80 |
-
assert n <= self.max_seq_len, f'text sequence length {n} must be less than {self.max_seq_len}'
|
| 81 |
-
|
| 82 |
-
x = x + self.pos_emb(torch.arange(n, device = device))
|
| 83 |
-
|
| 84 |
-
# cls tokens, as in bert
|
| 85 |
-
|
| 86 |
-
cls_tokens = repeat(self.cls_token, 'd -> b d', b = b)
|
| 87 |
-
x, ps = pack([cls_tokens, x], 'b * d')
|
| 88 |
-
|
| 89 |
-
# account for attending to cls token with self attention mask
|
| 90 |
-
|
| 91 |
-
mask = F.pad(mask, (1, 0), value = True)
|
| 92 |
-
|
| 93 |
-
# attention
|
| 94 |
-
|
| 95 |
-
x, all_layers = self.transformer(x, mask = mask, return_all_layers = True)
|
| 96 |
-
|
| 97 |
-
# unpack the cls tokens
|
| 98 |
-
|
| 99 |
-
cls_tokens, _ = unpack(x, ps, 'b * d')
|
| 100 |
-
|
| 101 |
-
out = self.norm(cls_tokens)
|
| 102 |
-
|
| 103 |
-
if not return_all_layers:
|
| 104 |
-
return out
|
| 105 |
-
|
| 106 |
-
return out, all_layers
|
| 107 |
-
|
| 108 |
-
class TextPretrainedModelType:
|
| 109 |
-
Roberta = 'roberta'
|
| 110 |
-
Qwen = 'qwen'
|
| 111 |
-
|
| 112 |
-
class TextTransformerPretrained(nn.Module):
|
| 113 |
-
def __init__(
|
| 114 |
-
self,
|
| 115 |
-
model_name = 'xlm-roberta-base',
|
| 116 |
-
dim = 768,
|
| 117 |
-
model_dim = None,
|
| 118 |
-
max_seq_len = 256,
|
| 119 |
-
tf_depth = 12,
|
| 120 |
-
dim_head = 64,
|
| 121 |
-
heads = 8,
|
| 122 |
-
attn_dropout = 0.,
|
| 123 |
-
ff_dropout = 0.,
|
| 124 |
-
ff_mult = 4,
|
| 125 |
-
frozen_pretrained = True,
|
| 126 |
-
hf_hub_cache_dir = None,
|
| 127 |
-
):
|
| 128 |
-
super().__init__()
|
| 129 |
-
self.dim = dim
|
| 130 |
-
|
| 131 |
-
self.model_name = model_name
|
| 132 |
-
|
| 133 |
-
self.hf_hub_cache_dir = hf_hub_cache_dir
|
| 134 |
-
|
| 135 |
-
self.pretrained_model_type = self._get_pretrained_model_type(model_name)
|
| 136 |
-
|
| 137 |
-
self.model = self._init_pretrained_model()
|
| 138 |
-
|
| 139 |
-
self._tokenizer = None
|
| 140 |
-
|
| 141 |
-
self.max_seq_len = max_seq_len
|
| 142 |
-
|
| 143 |
-
self.transformer = Transformer(
|
| 144 |
-
dim = dim,
|
| 145 |
-
depth = tf_depth,
|
| 146 |
-
dim_head = dim_head,
|
| 147 |
-
heads = heads,
|
| 148 |
-
attn_dropout = attn_dropout,
|
| 149 |
-
ff_dropout = ff_dropout,
|
| 150 |
-
ff_mult = ff_mult
|
| 151 |
-
) # if tf_depth > 0 else torch.nn.Identity()
|
| 152 |
-
|
| 153 |
-
is_proj = exists(model_dim) and model_dim != dim
|
| 154 |
-
|
| 155 |
-
self.proj = nn.Linear(model_dim, dim) if is_proj else torch.nn.Identity()
|
| 156 |
-
if frozen_pretrained:
|
| 157 |
-
frozen_params(self.model)
|
| 158 |
-
self.frozen_pretrained = frozen_pretrained
|
| 159 |
-
|
| 160 |
-
@staticmethod
|
| 161 |
-
def _get_pretrained_model_type(model_name):
|
| 162 |
-
if 'xlm-roberta' in model_name:
|
| 163 |
-
return TextPretrainedModelType.Roberta
|
| 164 |
-
elif 'Qwen' in model_name:
|
| 165 |
-
return TextPretrainedModelType.Qwen
|
| 166 |
-
else:
|
| 167 |
-
raise ValueError(f"Unknown pretrained model named: {model_name}")
|
| 168 |
-
|
| 169 |
-
def _init_pretrained_model(self):
|
| 170 |
-
if self.pretrained_model_type == TextPretrainedModelType.Roberta:
|
| 171 |
-
model = XLMRobertaModel.from_pretrained(self.model_name, trust_remote_code=True, cache_dir=self.hf_hub_cache_dir)
|
| 172 |
-
elif self.pretrained_model_type == TextPretrainedModelType.Qwen:
|
| 173 |
-
model = AutoModelForCausalLM.from_pretrained(self.model_name, trust_remote_code=True, fp16=True, cache_dir=self.hf_hub_cache_dir)
|
| 174 |
-
else:
|
| 175 |
-
raise ValueError(f"Failed to init pretrained model type: {self.pretrained_model_type}")
|
| 176 |
-
return model
|
| 177 |
-
|
| 178 |
-
def _init_tokenizer(self):
|
| 179 |
-
if self.pretrained_model_type == TextPretrainedModelType.Roberta:
|
| 180 |
-
tokenizer = AutoTokenizer.from_pretrained(self.model_name, trust_remote_code=True, cache_dir=self.hf_hub_cache_dir)
|
| 181 |
-
elif self.pretrained_model_type == TextPretrainedModelType.Qwen:
|
| 182 |
-
tokenizer = AutoTokenizer.from_pretrained(self.model_name, trust_remote_code=True, cache_dir=self.hf_hub_cache_dir)
|
| 183 |
-
tokenizer.pad_token = '<|im_end|>'
|
| 184 |
-
else:
|
| 185 |
-
raise ValueError(f"Failed to init tokenizer of pretrained model type: {self.pretrained_model_type}")
|
| 186 |
-
return tokenizer
|
| 187 |
-
|
| 188 |
-
@property
|
| 189 |
-
def tokenizer(self):
|
| 190 |
-
if not exists(self._tokenizer):
|
| 191 |
-
self._tokenizer = self._init_tokenizer()
|
| 192 |
-
return self._tokenizer
|
| 193 |
-
|
| 194 |
-
@property
|
| 195 |
-
def device(self):
|
| 196 |
-
return next(self.model.parameters()).device
|
| 197 |
-
|
| 198 |
-
@property
|
| 199 |
-
def dtype(self):
|
| 200 |
-
return next(self.transformer.parameters()).dtype
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
def pred_pretrained_model_hidden(self, **kw):
|
| 204 |
-
if self.pretrained_model_type == TextPretrainedModelType.Roberta:
|
| 205 |
-
outputs = self.model(**kw)
|
| 206 |
-
outputs = outputs.last_hidden_state
|
| 207 |
-
elif self.pretrained_model_type == TextPretrainedModelType.Qwen:
|
| 208 |
-
last_hidden_state = self.model(**kw, output_hidden_states=True)['hidden_states'][-1]
|
| 209 |
-
outputs = last_hidden_state.to(dtype = self.dtype)
|
| 210 |
-
else:
|
| 211 |
-
raise ValueError(f"Unknown pretrained model type: {self.pretrained_model_type}")
|
| 212 |
-
return outputs
|
| 213 |
-
|
| 214 |
-
def forward(
|
| 215 |
-
self,
|
| 216 |
-
x = None,
|
| 217 |
-
raw_texts: Optional[List[str]] = None,
|
| 218 |
-
mask = None,
|
| 219 |
-
return_all_layers = False,
|
| 220 |
-
return_mean = True
|
| 221 |
-
):
|
| 222 |
-
assert exists(x) ^ exists(raw_texts)
|
| 223 |
-
with torch.no_grad():
|
| 224 |
-
if exists(raw_texts):
|
| 225 |
-
inputs = self.tokenizer(raw_texts, return_tensors='pt', padding=True)
|
| 226 |
-
inputs = inputs.to(self.device)
|
| 227 |
-
|
| 228 |
-
if exists(mask):
|
| 229 |
-
inputs['attention_mask'] = mask
|
| 230 |
-
|
| 231 |
-
outputs = self.pred_pretrained_model_hidden(**inputs)
|
| 232 |
-
|
| 233 |
-
outputs = self.proj(outputs)
|
| 234 |
-
|
| 235 |
-
outputs, layer_results = self.transformer(outputs, return_all_layers=True)
|
| 236 |
-
if return_mean:
|
| 237 |
-
outputs = outputs.mean(dim = -2)
|
| 238 |
-
|
| 239 |
-
if return_all_layers:
|
| 240 |
-
return outputs, layer_results
|
| 241 |
-
return outputs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/modules/__init__.py
DELETED
|
File without changes
|
src/third_party/MuQ/src/muq/muq_mulan/modules/contrastive.py
DELETED
|
@@ -1,238 +0,0 @@
|
|
| 1 |
-
import math
|
| 2 |
-
from functools import partial
|
| 3 |
-
|
| 4 |
-
import torch.nn as nn
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn.functional as F
|
| 7 |
-
from einops import rearrange, reduce
|
| 8 |
-
from torch import einsum
|
| 9 |
-
import torch.distributed as dist
|
| 10 |
-
|
| 11 |
-
from .utils import exists, l2norm, log, print_once
|
| 12 |
-
from .distributed import AllGather
|
| 13 |
-
from .extend_distributed import all_gather
|
| 14 |
-
from .transformer import LayerNorm
|
| 15 |
-
|
| 16 |
-
def matrix_diag(t):
|
| 17 |
-
device = t.device
|
| 18 |
-
i, j = t.shape[-2:]
|
| 19 |
-
num_diag_el = min(i, j)
|
| 20 |
-
i_range = torch.arange(i, device = device)
|
| 21 |
-
j_range = torch.arange(j, device = device)
|
| 22 |
-
diag_mask = rearrange(i_range, 'i -> i 1') == rearrange(j_range, 'j -> 1 j')
|
| 23 |
-
diag_el = t.masked_select(diag_mask)
|
| 24 |
-
return rearrange(diag_el, '(b d) -> b d', d = num_diag_el)
|
| 25 |
-
|
| 26 |
-
# contrastive losses
|
| 27 |
-
|
| 28 |
-
class SoftmaxContrastiveLearning(nn.Module):
|
| 29 |
-
def __init__(
|
| 30 |
-
self,
|
| 31 |
-
*,
|
| 32 |
-
layers = 1,
|
| 33 |
-
decoupled_contrastive_learning = False,
|
| 34 |
-
init_temp = 10
|
| 35 |
-
):
|
| 36 |
-
super().__init__()
|
| 37 |
-
self.temperatures = nn.Parameter(torch.ones(layers, 1, 1) * math.log(init_temp))
|
| 38 |
-
self.decoupled_contrastive_learning = decoupled_contrastive_learning
|
| 39 |
-
|
| 40 |
-
self.all_gather = AllGather(dim = 2)
|
| 41 |
-
|
| 42 |
-
@property
|
| 43 |
-
def device(self):
|
| 44 |
-
return next(self.parameters()).device
|
| 45 |
-
|
| 46 |
-
def forward(self, audio_latents, text_latents):
|
| 47 |
-
if audio_latents.ndim == 2:
|
| 48 |
-
audio_latents = rearrange(audio_latents, '... -> 1 ...')
|
| 49 |
-
|
| 50 |
-
if text_latents.ndim == 2:
|
| 51 |
-
text_latents = rearrange(text_latents, '... -> 1 ...')
|
| 52 |
-
|
| 53 |
-
batch = audio_latents.shape[1]
|
| 54 |
-
|
| 55 |
-
if self.all_gather.is_distributed:
|
| 56 |
-
latents = torch.stack((audio_latents, text_latents))
|
| 57 |
-
latents, _ = self.all_gather(latents)
|
| 58 |
-
audio_latents, text_latents = latents
|
| 59 |
-
|
| 60 |
-
sims = einsum('l i d, l j d -> l i j', audio_latents, text_latents)
|
| 61 |
-
|
| 62 |
-
sims = sims * self.temperatures.exp()
|
| 63 |
-
|
| 64 |
-
cosine_sims_exp = sims.exp() # Similarity matrix [Rank, N, N]
|
| 65 |
-
|
| 66 |
-
numerator = matrix_diag(cosine_sims_exp) # Take diagonal elements, that is, for t [l, i, j], take all elements of i==j to obtain a array of l * min (i, j)
|
| 67 |
-
|
| 68 |
-
if self.decoupled_contrastive_learning:
|
| 69 |
-
eye = torch.eye(batch, device = self.device, dtype = torch.bool)
|
| 70 |
-
cosine_sims_exp = cosine_sims_exp.masked_fill(eye, 0.) # Set the diagonal to 0
|
| 71 |
-
|
| 72 |
-
denominator_i = reduce(cosine_sims_exp, 'l i j -> l i', 'sum')
|
| 73 |
-
denominator_j = reduce(cosine_sims_exp, 'l i j -> l j', 'sum')
|
| 74 |
-
|
| 75 |
-
contrastive_loss = -log(numerator) + 0.5 * (log(denominator_i) + log(denominator_j))
|
| 76 |
-
|
| 77 |
-
contrastive_loss = reduce(contrastive_loss, 'l n -> l', 'mean')
|
| 78 |
-
return contrastive_loss.sum()
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
class RankSoftmaxContrastiveLearning(nn.Module):
|
| 82 |
-
def __init__(
|
| 83 |
-
self,
|
| 84 |
-
*,
|
| 85 |
-
layers = 1,
|
| 86 |
-
decoupled_contrastive_learning = False,
|
| 87 |
-
init_temp = 10,
|
| 88 |
-
):
|
| 89 |
-
super().__init__()
|
| 90 |
-
self.temperatures = nn.Parameter(torch.ones(layers, 1, 1) * math.log(init_temp))
|
| 91 |
-
self.decoupled_contrastive_learning = decoupled_contrastive_learning
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
@property
|
| 95 |
-
def device(self):
|
| 96 |
-
return next(self.parameters()).device
|
| 97 |
-
|
| 98 |
-
def forward(self, audio_latents, text_latents):
|
| 99 |
-
if audio_latents.ndim == 2:
|
| 100 |
-
audio_latents = rearrange(audio_latents, '... -> 1 ...')
|
| 101 |
-
|
| 102 |
-
if text_latents.ndim == 2:
|
| 103 |
-
text_latents = rearrange(text_latents, '... -> 1 ...')
|
| 104 |
-
|
| 105 |
-
audio_latents = all_gather(audio_latents, None)
|
| 106 |
-
text_latents = all_gather(text_latents, None)
|
| 107 |
-
|
| 108 |
-
print_once("audio_latents:"+str(audio_latents.shape) + "text_latents:" + str(text_latents.shape))
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
batch = audio_latents.shape[1]
|
| 112 |
-
rank = audio_latents.shape[0]
|
| 113 |
-
|
| 114 |
-
audio_latents = rearrange(audio_latents, 'l i d -> (l i) d')
|
| 115 |
-
text_latents = rearrange(text_latents, 'l j d -> (l j) d')
|
| 116 |
-
|
| 117 |
-
sims = einsum('i d, j d -> i j', audio_latents, text_latents)
|
| 118 |
-
|
| 119 |
-
sims = sims * self.temperatures.exp()
|
| 120 |
-
|
| 121 |
-
sims = rearrange(sims, '1 i j -> i j')
|
| 122 |
-
|
| 123 |
-
cosine_sims_exp = sims.exp() # Similarity matrix [Rank, N, N]
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
numerator = matrix_diag(cosine_sims_exp) # Take diagonal elements, that is, for t [l, i, j], take all elements of i==j to obtain a array of l * min (i, j)
|
| 127 |
-
|
| 128 |
-
if self.decoupled_contrastive_learning:
|
| 129 |
-
eye = torch.eye(batch*rank, device = self.device, dtype = torch.bool)
|
| 130 |
-
cosine_sims_exp = cosine_sims_exp.masked_fill(eye, 0.) # Set the diagonal to 0
|
| 131 |
-
|
| 132 |
-
denominator_i = reduce(cosine_sims_exp, 'i j -> i', 'sum')
|
| 133 |
-
denominator_j = reduce(cosine_sims_exp, 'i j -> j', 'sum')
|
| 134 |
-
|
| 135 |
-
contrastive_loss = -log(numerator) + 0.5 * (log(denominator_i) + log(denominator_j))
|
| 136 |
-
|
| 137 |
-
contrastive_loss = reduce(contrastive_loss, '1 n -> 1', 'mean')
|
| 138 |
-
return contrastive_loss
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
class SigmoidContrastiveLearning(nn.Module):
|
| 142 |
-
""" https://arxiv.org/abs/2303.15343 """
|
| 143 |
-
|
| 144 |
-
def __init__(
|
| 145 |
-
self,
|
| 146 |
-
*,
|
| 147 |
-
layers = 1,
|
| 148 |
-
init_temp = 10,
|
| 149 |
-
init_bias = -10
|
| 150 |
-
):
|
| 151 |
-
super().__init__()
|
| 152 |
-
self.temperatures = nn.Parameter(torch.ones(layers, 1, 1) * math.log(init_temp))
|
| 153 |
-
self.bias = nn.Parameter(torch.ones(layers, 1, 1) * init_bias)
|
| 154 |
-
|
| 155 |
-
self.all_gather = AllGather(dim = 1, all_reduce_grads = True)
|
| 156 |
-
|
| 157 |
-
@property
|
| 158 |
-
def device(self):
|
| 159 |
-
return next(self.parameters()).device
|
| 160 |
-
|
| 161 |
-
def forward(self, audio_latents, text_latents):
|
| 162 |
-
device = self.device
|
| 163 |
-
|
| 164 |
-
if audio_latents.ndim == 2:
|
| 165 |
-
audio_latents = rearrange(audio_latents, '... -> 1 ...') # To [Rank, Batch, Latent]
|
| 166 |
-
|
| 167 |
-
if text_latents.ndim == 2:
|
| 168 |
-
text_latents = rearrange(text_latents, '... -> 1 ...')
|
| 169 |
-
|
| 170 |
-
text_latents, rank_sizes = self.all_gather(text_latents)
|
| 171 |
-
|
| 172 |
-
n = text_latents.shape[1]
|
| 173 |
-
|
| 174 |
-
sims = einsum('l i d, l j d -> l i j', audio_latents, text_latents) # Calculate dot product similarity between pairs
|
| 175 |
-
|
| 176 |
-
sims = sims * self.temperatures.exp() + self.bias
|
| 177 |
-
|
| 178 |
-
labels = torch.eye(n, device = device)
|
| 179 |
-
|
| 180 |
-
if exists(rank_sizes):
|
| 181 |
-
labels_by_ranks = labels.split(rank_sizes.tolist(), dim = 0)
|
| 182 |
-
labels = labels_by_ranks[dist.get_rank()] # labels to the n elements of the current rank
|
| 183 |
-
|
| 184 |
-
labels = 2 * rearrange(labels, 'i j -> 1 i j') - torch.ones_like(sims)
|
| 185 |
-
|
| 186 |
-
return -F.logsigmoid(labels * sims).sum() / n
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
# hierarchical cl loss
|
| 192 |
-
|
| 193 |
-
def interspersed_indices(layers, total_layers):
|
| 194 |
-
assert total_layers >= layers
|
| 195 |
-
step = total_layers / layers
|
| 196 |
-
return (torch.arange(0, layers) * step).floor().long()
|
| 197 |
-
|
| 198 |
-
class MultiLayerContrastiveLoss(nn.Module):
|
| 199 |
-
def __init__(
|
| 200 |
-
self,
|
| 201 |
-
*,
|
| 202 |
-
audio_dim,
|
| 203 |
-
text_dim,
|
| 204 |
-
dim_latent,
|
| 205 |
-
layers,
|
| 206 |
-
decoupled_contrastive_learning = False,
|
| 207 |
-
sigmoid_contrastive_loss = False
|
| 208 |
-
):
|
| 209 |
-
super().__init__()
|
| 210 |
-
self.layers = layers
|
| 211 |
-
|
| 212 |
-
self.audio_norm = LayerNorm(audio_dim, scale = False)
|
| 213 |
-
self.audio_gamma = nn.Parameter(torch.ones(layers, 1, audio_dim))
|
| 214 |
-
self.audio_latent_weight = nn.Parameter(torch.randn(layers, audio_dim, dim_latent))
|
| 215 |
-
self.audio_latent_bias = nn.Parameter(torch.randn(layers, 1, dim_latent))
|
| 216 |
-
|
| 217 |
-
self.text_norm = LayerNorm(text_dim, scale = False)
|
| 218 |
-
self.text_gamma = nn.Parameter(torch.ones(layers, 1, text_dim))
|
| 219 |
-
self.text_latent_weight = nn.Parameter(torch.randn(layers, text_dim, dim_latent))
|
| 220 |
-
self.text_latent_bias = nn.Parameter(torch.randn(layers, 1, dim_latent))
|
| 221 |
-
|
| 222 |
-
klass = SigmoidContrastiveLearning if sigmoid_contrastive_loss else partial(SoftmaxContrastiveLearning, decoupled_contrastive_learning = decoupled_contrastive_learning)
|
| 223 |
-
self.contrast = klass(layers = layers)
|
| 224 |
-
|
| 225 |
-
def forward(self, *, audio_layers, text_layers):
|
| 226 |
-
device, batch = audio_layers.device, audio_layers.shape[1]
|
| 227 |
-
|
| 228 |
-
audio_gap = reduce(audio_layers, 'l b n d -> l b d', 'mean')
|
| 229 |
-
audio_embeds = self.audio_norm(audio_gap) * self.audio_gamma
|
| 230 |
-
audio_latents = einsum('l b d, l d e -> l b e', audio_embeds, self.audio_latent_weight) + self.audio_latent_bias
|
| 231 |
-
audio_latents = l2norm(audio_latents)
|
| 232 |
-
|
| 233 |
-
text_cls_tokens = text_layers[:, :, 0]
|
| 234 |
-
text_embeds = self.text_norm(text_cls_tokens) * self.text_gamma
|
| 235 |
-
text_latents = einsum('l b d, l d e -> l b e', text_embeds, self.text_latent_weight) + self.text_latent_bias
|
| 236 |
-
text_latents = l2norm(text_latents)
|
| 237 |
-
|
| 238 |
-
return self.contrast(audio_latents, text_latents)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/modules/distributed.py
DELETED
|
@@ -1,83 +0,0 @@
|
|
| 1 |
-
import torch
|
| 2 |
-
from torch import nn
|
| 3 |
-
from torch.autograd import Function
|
| 4 |
-
import torch.distributed as dist
|
| 5 |
-
|
| 6 |
-
from einops import rearrange
|
| 7 |
-
|
| 8 |
-
def exists(val):
|
| 9 |
-
return val is not None
|
| 10 |
-
|
| 11 |
-
# distributed helpers
|
| 12 |
-
|
| 13 |
-
def all_gather_same_dim(t):
|
| 14 |
-
world_size = dist.get_world_size()
|
| 15 |
-
gathered_tensors = [torch.empty_like(t, device = t.device, dtype = t.dtype) for i in range(world_size)]
|
| 16 |
-
dist.all_gather(gathered_tensors, t)
|
| 17 |
-
return gathered_tensors
|
| 18 |
-
|
| 19 |
-
def all_gather_variable_dim(t, dim = 0, sizes = None):
|
| 20 |
-
device, rank, world_size = t.device, dist.get_rank(), dist.get_world_size()
|
| 21 |
-
|
| 22 |
-
if not exists(sizes):
|
| 23 |
-
size = torch.tensor(t.shape[dim], device = device, dtype = torch.long)
|
| 24 |
-
sizes = all_gather_same_dim(size)
|
| 25 |
-
sizes = torch.stack(sizes)
|
| 26 |
-
|
| 27 |
-
if torch.unique(sizes).numel() == 1:
|
| 28 |
-
gathered_tensors = all_gather_same_dim(t)
|
| 29 |
-
return torch.cat(gathered_tensors, dim = dim), sizes
|
| 30 |
-
|
| 31 |
-
max_size = sizes.amax().item()
|
| 32 |
-
|
| 33 |
-
padded_t = pad_dim_to(t, max_size, dim = dim)
|
| 34 |
-
gathered_tensors = all_gather_same_dim(padded_t)
|
| 35 |
-
|
| 36 |
-
gathered_tensor = torch.cat(gathered_tensors, dim = dim)
|
| 37 |
-
seq = torch.arange(max_size, device = device)
|
| 38 |
-
|
| 39 |
-
mask = rearrange(seq, 'j -> 1 j') < rearrange(sizes, 'i -> i 1')
|
| 40 |
-
mask = rearrange(mask, 'i j -> (i j)')
|
| 41 |
-
seq = torch.arange(mask.shape[-1], device = device)
|
| 42 |
-
indices = seq[mask]
|
| 43 |
-
|
| 44 |
-
gathered_tensor = gathered_tensor.index_select(dim, indices)
|
| 45 |
-
|
| 46 |
-
return gathered_tensor, sizes
|
| 47 |
-
|
| 48 |
-
class AllGatherFunction(Function):
|
| 49 |
-
@staticmethod
|
| 50 |
-
def forward(ctx, x, dim, sizes, all_reduce_grads):
|
| 51 |
-
x, batch_sizes = all_gather_variable_dim(x, dim = dim, sizes = sizes)
|
| 52 |
-
ctx.dim = dim
|
| 53 |
-
ctx.all_reduce_grads = all_reduce_grads
|
| 54 |
-
ctx.batch_sizes = batch_sizes.tolist()
|
| 55 |
-
return x, batch_sizes
|
| 56 |
-
|
| 57 |
-
@staticmethod
|
| 58 |
-
def backward(ctx, grads, _):
|
| 59 |
-
batch_sizes, rank = ctx.batch_sizes, dist.get_rank()
|
| 60 |
-
if ctx.all_reduce_grads:
|
| 61 |
-
dist.all_reduce(grads)
|
| 62 |
-
|
| 63 |
-
grads_by_rank = grads.split(batch_sizes, dim = ctx.dim)
|
| 64 |
-
return grads_by_rank[rank], None, None, None
|
| 65 |
-
|
| 66 |
-
class AllGather(nn.Module):
|
| 67 |
-
def __init__(
|
| 68 |
-
self,
|
| 69 |
-
dim,
|
| 70 |
-
*,
|
| 71 |
-
all_reduce_grads = False
|
| 72 |
-
):
|
| 73 |
-
super().__init__()
|
| 74 |
-
self.dim = dim
|
| 75 |
-
self.all_reduce_grads = all_reduce_grads
|
| 76 |
-
self.is_distributed = dist.is_initialized() and dist.get_world_size() > 1
|
| 77 |
-
|
| 78 |
-
def forward(
|
| 79 |
-
self,
|
| 80 |
-
x,
|
| 81 |
-
sizes = None
|
| 82 |
-
):
|
| 83 |
-
return AllGatherFunction.apply(x, self.dim, sizes, self.all_reduce_grads)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/modules/extend_distributed.py
DELETED
|
@@ -1,604 +0,0 @@
|
|
| 1 |
-
|
| 2 |
-
import builtins
|
| 3 |
-
import os
|
| 4 |
-
import sys
|
| 5 |
-
|
| 6 |
-
import torch
|
| 7 |
-
import torch.distributed as dist
|
| 8 |
-
from torch.autograd import Function
|
| 9 |
-
from torch.autograd.profiler import record_function
|
| 10 |
-
from torch.nn.parallel import DistributedDataParallel as DDP
|
| 11 |
-
|
| 12 |
-
import torch.distributed as dist
|
| 13 |
-
|
| 14 |
-
try:
|
| 15 |
-
import torch_ccl
|
| 16 |
-
except ImportError as e:
|
| 17 |
-
# print(e)
|
| 18 |
-
torch_ccl = False
|
| 19 |
-
|
| 20 |
-
try:
|
| 21 |
-
import torch_ucc
|
| 22 |
-
except ImportError as e:
|
| 23 |
-
torch_ucc = False
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
my_rank = -1
|
| 27 |
-
my_size = -1
|
| 28 |
-
my_local_rank = 1
|
| 29 |
-
my_local_size = 1
|
| 30 |
-
alltoall_supported = False
|
| 31 |
-
a2a_impl = os.environ.get("DLRM_ALLTOALL_IMPL", "")
|
| 32 |
-
|
| 33 |
-
myreq = None
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
def env2int(env_list, default=-1):
|
| 37 |
-
for e in env_list:
|
| 38 |
-
val = int(os.environ.get(e, -1))
|
| 39 |
-
if val >= 0:
|
| 40 |
-
return val
|
| 41 |
-
return default
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def get_my_slice(n):
|
| 45 |
-
k, m = divmod(n, my_size)
|
| 46 |
-
return slice(
|
| 47 |
-
my_rank * k + min(my_rank, m), (my_rank + 1) * k + min(my_rank + 1, m), 1
|
| 48 |
-
)
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
def get_split_lengths(n):
|
| 52 |
-
k, m = divmod(n, my_size)
|
| 53 |
-
if m == 0:
|
| 54 |
-
splits = None
|
| 55 |
-
my_len = k
|
| 56 |
-
else:
|
| 57 |
-
splits = [(k + 1) if i < m else k for i in range(my_size)]
|
| 58 |
-
my_len = splits[my_rank]
|
| 59 |
-
return (my_len, splits)
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
def init_distributed(rank=-1, local_rank=-1, size=-1, use_gpu=False, backend=""):
|
| 63 |
-
global myreq
|
| 64 |
-
global my_rank
|
| 65 |
-
global my_size
|
| 66 |
-
global my_local_rank
|
| 67 |
-
global my_local_size
|
| 68 |
-
global a2a_impl
|
| 69 |
-
global alltoall_supported
|
| 70 |
-
|
| 71 |
-
# guess MPI ranks from env (works for IMPI, OMPI and MVAPICH2)
|
| 72 |
-
num_mpi_ranks = env2int(
|
| 73 |
-
["PMI_SIZE", "OMPI_COMM_WORLD_SIZE", "MV2_COMM_WORLD_SIZE", "WORLD_SIZE"]
|
| 74 |
-
)
|
| 75 |
-
if backend == "" and num_mpi_ranks > 1:
|
| 76 |
-
if torch_ccl and env2int(["CCL_WORKER_COUNT"]) > 0:
|
| 77 |
-
backend = "ccl"
|
| 78 |
-
elif use_gpu and dist.is_nccl_available():
|
| 79 |
-
backend = "nccl"
|
| 80 |
-
elif dist.is_mpi_available():
|
| 81 |
-
backend = "mpi"
|
| 82 |
-
else:
|
| 83 |
-
print(
|
| 84 |
-
"WARNING: MPI multi-process launch detected but PyTorch MPI backend not available."
|
| 85 |
-
)
|
| 86 |
-
backend = "gloo"
|
| 87 |
-
|
| 88 |
-
if backend != "":
|
| 89 |
-
# guess Rank and size
|
| 90 |
-
if rank == -1:
|
| 91 |
-
rank = env2int(
|
| 92 |
-
["PMI_RANK", "OMPI_COMM_WORLD_RANK", "MV2_COMM_WORLD_RANK", "RANK"], 0
|
| 93 |
-
)
|
| 94 |
-
if size == -1:
|
| 95 |
-
size = env2int(
|
| 96 |
-
[
|
| 97 |
-
"PMI_SIZE",
|
| 98 |
-
"OMPI_COMM_WORLD_SIZE",
|
| 99 |
-
"MV2_COMM_WORLD_SIZE",
|
| 100 |
-
"WORLD_SIZE",
|
| 101 |
-
],
|
| 102 |
-
1,
|
| 103 |
-
)
|
| 104 |
-
if not os.environ.get("RANK", None) and rank != -1:
|
| 105 |
-
os.environ["RANK"] = str(rank)
|
| 106 |
-
if not os.environ.get("WORLD_SIZE", None) and size != -1:
|
| 107 |
-
os.environ["WORLD_SIZE"] = str(size)
|
| 108 |
-
if not os.environ.get("MASTER_PORT", None):
|
| 109 |
-
os.environ["MASTER_PORT"] = "29500"
|
| 110 |
-
if not os.environ.get("MASTER_ADDR", None):
|
| 111 |
-
local_size = env2int(
|
| 112 |
-
[
|
| 113 |
-
"MPI_LOCALNRANKS",
|
| 114 |
-
"OMPI_COMM_WORLD_LOCAL_SIZE",
|
| 115 |
-
"MV2_COMM_WORLD_LOCAL_SIZE",
|
| 116 |
-
],
|
| 117 |
-
1,
|
| 118 |
-
)
|
| 119 |
-
if local_size != size and backend != "mpi":
|
| 120 |
-
print(
|
| 121 |
-
"Warning: Looks like distributed multinode run but MASTER_ADDR env not set, using '127.0.0.1' as default"
|
| 122 |
-
)
|
| 123 |
-
print(
|
| 124 |
-
"If this run hangs, try exporting rank 0's hostname as MASTER_ADDR"
|
| 125 |
-
)
|
| 126 |
-
os.environ["MASTER_ADDR"] = "127.0.0.1"
|
| 127 |
-
|
| 128 |
-
if size > 1:
|
| 129 |
-
if local_rank == -1:
|
| 130 |
-
my_local_rank = env2int(
|
| 131 |
-
[
|
| 132 |
-
"MPI_LOCALRANKID",
|
| 133 |
-
"OMPI_COMM_WORLD_LOCAL_RANK",
|
| 134 |
-
"MV2_COMM_WORLD_LOCAL_RANK",
|
| 135 |
-
"LOCAL_RANK",
|
| 136 |
-
],
|
| 137 |
-
0,
|
| 138 |
-
)
|
| 139 |
-
else:
|
| 140 |
-
my_local_rank = local_rank
|
| 141 |
-
my_local_size = env2int(
|
| 142 |
-
[
|
| 143 |
-
"MPI_LOCALNRANKS",
|
| 144 |
-
"OMPI_COMM_WORLD_LOCAL_SIZE",
|
| 145 |
-
"MV2_COMM_WORLD_LOCAL_SIZE",
|
| 146 |
-
],
|
| 147 |
-
1,
|
| 148 |
-
)
|
| 149 |
-
if use_gpu:
|
| 150 |
-
if my_local_size > torch.cuda.device_count():
|
| 151 |
-
print(
|
| 152 |
-
"Not sufficient GPUs available... local_size = %d, ngpus = %d"
|
| 153 |
-
% (my_local_size, torch.cuda.device_count())
|
| 154 |
-
)
|
| 155 |
-
sys.exit(1)
|
| 156 |
-
torch.cuda.set_device(my_local_rank)
|
| 157 |
-
dist.init_process_group(backend, rank=rank, world_size=size)
|
| 158 |
-
my_rank = dist.get_rank()
|
| 159 |
-
my_size = dist.get_world_size()
|
| 160 |
-
if my_rank == 0:
|
| 161 |
-
print("Running on %d ranks using %s backend" % (my_size, backend))
|
| 162 |
-
if hasattr(dist, "all_to_all_single"):
|
| 163 |
-
try:
|
| 164 |
-
t = torch.zeros([4])
|
| 165 |
-
if use_gpu:
|
| 166 |
-
t = t.cuda()
|
| 167 |
-
dist.all_to_all_single(t, t)
|
| 168 |
-
alltoall_supported = True
|
| 169 |
-
except RuntimeError as err:
|
| 170 |
-
print("fail to enable all_to_all_single primitive: %s" % err)
|
| 171 |
-
if a2a_impl == "alltoall" and alltoall_supported == False:
|
| 172 |
-
print(
|
| 173 |
-
"Requested DLRM_ALLTOALL_IMPL=%s but backend %s does not support it, use scatter/gather based alltoall"
|
| 174 |
-
% (a2a_impl, backend)
|
| 175 |
-
)
|
| 176 |
-
a2a_impl = "scatter"
|
| 177 |
-
if a2a_impl != "":
|
| 178 |
-
print("Using DLRM_ALLTOALL_IMPL=%s" % a2a_impl)
|
| 179 |
-
else:
|
| 180 |
-
my_rank = 0
|
| 181 |
-
my_size = 1
|
| 182 |
-
my_local_rank = 0
|
| 183 |
-
my_local_size = 1
|
| 184 |
-
print_all(
|
| 185 |
-
"world size: %d, current rank: %d, local rank: %d"
|
| 186 |
-
% (my_size, my_rank, my_local_rank)
|
| 187 |
-
)
|
| 188 |
-
myreq = Request()
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
class Request(object):
|
| 192 |
-
def __init__(self):
|
| 193 |
-
self.req = None
|
| 194 |
-
self.tensor = None
|
| 195 |
-
self.WaitFunction = All2All_Scatter_Wait
|
| 196 |
-
|
| 197 |
-
def wait(self):
|
| 198 |
-
ret = self.WaitFunction.apply(*self.tensor)
|
| 199 |
-
self.req = None
|
| 200 |
-
self.tensor = None
|
| 201 |
-
return ret
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
class All2All_ScatterList_Req(Function):
|
| 205 |
-
@staticmethod
|
| 206 |
-
def forward(ctx, a2a_info, *inputs):
|
| 207 |
-
global myreq
|
| 208 |
-
batch_split_lengths = (
|
| 209 |
-
a2a_info.global_batch_partition_slices
|
| 210 |
-
if a2a_info.global_batch_partition_slices
|
| 211 |
-
else a2a_info.local_batch_num
|
| 212 |
-
)
|
| 213 |
-
table_split_lengths = (
|
| 214 |
-
a2a_info.global_table_wise_parition_slices
|
| 215 |
-
if a2a_info.global_table_wise_parition_slices
|
| 216 |
-
else [a2a_info.local_table_num] * my_size
|
| 217 |
-
)
|
| 218 |
-
gather_list = []
|
| 219 |
-
req_list = []
|
| 220 |
-
for i in range(my_size):
|
| 221 |
-
for j in range(table_split_lengths[i]):
|
| 222 |
-
out_tensor = inputs[0].new_empty(
|
| 223 |
-
[a2a_info.local_batch_num, a2a_info.emb_dim]
|
| 224 |
-
)
|
| 225 |
-
scatter_list = (
|
| 226 |
-
list(inputs[j].split(batch_split_lengths, dim=0))
|
| 227 |
-
if i == my_rank
|
| 228 |
-
else []
|
| 229 |
-
)
|
| 230 |
-
req = dist.scatter(out_tensor, scatter_list, src=i, async_op=True)
|
| 231 |
-
gather_list.append(out_tensor)
|
| 232 |
-
req_list.append(req)
|
| 233 |
-
myreq.req = req_list
|
| 234 |
-
myreq.tensor = tuple(gather_list)
|
| 235 |
-
myreq.a2a_info = a2a_info
|
| 236 |
-
return myreq.tensor
|
| 237 |
-
|
| 238 |
-
@staticmethod
|
| 239 |
-
def backward(ctx, *grad_output):
|
| 240 |
-
global myreq
|
| 241 |
-
for r in myreq.req:
|
| 242 |
-
r.wait()
|
| 243 |
-
myreq.req = None
|
| 244 |
-
grad_inputs = myreq.tensor
|
| 245 |
-
myreq.tensor = None
|
| 246 |
-
return (None, *grad_inputs)
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
class All2All_ScatterList_Wait(Function):
|
| 250 |
-
@staticmethod
|
| 251 |
-
def forward(ctx, *output):
|
| 252 |
-
global myreq
|
| 253 |
-
ctx.a2a_info = myreq.a2a_info
|
| 254 |
-
for r in myreq.req:
|
| 255 |
-
r.wait()
|
| 256 |
-
myreq.req = None
|
| 257 |
-
myreq.tensor = None
|
| 258 |
-
return output
|
| 259 |
-
|
| 260 |
-
@staticmethod
|
| 261 |
-
def backward(ctx, *grad_output):
|
| 262 |
-
global myreq
|
| 263 |
-
a2a_info = ctx.a2a_info
|
| 264 |
-
grad_output = [t.contiguous() for t in grad_output]
|
| 265 |
-
batch_split_lengths = (
|
| 266 |
-
a2a_info.global_batch_partition_slices
|
| 267 |
-
if a2a_info.global_batch_partition_slices
|
| 268 |
-
else [a2a_info.local_batch_num] * my_size
|
| 269 |
-
)
|
| 270 |
-
per_rank_table_splits = (
|
| 271 |
-
a2a_info.global_table_wise_parition_slices
|
| 272 |
-
if a2a_info.global_table_wise_parition_slices
|
| 273 |
-
else [a2a_info.local_table_num] * my_size
|
| 274 |
-
)
|
| 275 |
-
grad_inputs = [
|
| 276 |
-
grad_output[0].new_empty([ctx.a2a_info.batch_size, ctx.a2a_info.emb_dim])
|
| 277 |
-
for _ in range(a2a_info.local_table_num)
|
| 278 |
-
]
|
| 279 |
-
req_list = []
|
| 280 |
-
ind = 0
|
| 281 |
-
for i in range(my_size):
|
| 282 |
-
for j in range(per_rank_table_splits[i]):
|
| 283 |
-
gather_list = (
|
| 284 |
-
list(grad_inputs[j].split(batch_split_lengths, dim=0))
|
| 285 |
-
if i == my_rank
|
| 286 |
-
else None
|
| 287 |
-
)
|
| 288 |
-
req = dist.gather(grad_output[ind], gather_list, dst=i, async_op=True)
|
| 289 |
-
req_list.append(req)
|
| 290 |
-
ind += 1
|
| 291 |
-
myreq.req = req_list
|
| 292 |
-
myreq.tensor = grad_inputs
|
| 293 |
-
return tuple(grad_output)
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
class All2All_Scatter_Req(Function):
|
| 297 |
-
@staticmethod
|
| 298 |
-
def forward(ctx, a2a_info, *inputs):
|
| 299 |
-
global myreq
|
| 300 |
-
batch_split_lengths = (
|
| 301 |
-
a2a_info.global_batch_partition_slices
|
| 302 |
-
if a2a_info.global_batch_partition_slices
|
| 303 |
-
else a2a_info.local_batch_num
|
| 304 |
-
)
|
| 305 |
-
table_split_lengths = (
|
| 306 |
-
a2a_info.global_table_wise_parition_slices
|
| 307 |
-
if a2a_info.global_table_wise_parition_slices
|
| 308 |
-
else [a2a_info.local_table_num] * my_size
|
| 309 |
-
)
|
| 310 |
-
input = torch.cat(inputs, dim=1)
|
| 311 |
-
scatter_list = list(input.split(batch_split_lengths, dim=0))
|
| 312 |
-
gather_list = []
|
| 313 |
-
req_list = []
|
| 314 |
-
for i in range(my_size):
|
| 315 |
-
out_tensor = input.new_empty(
|
| 316 |
-
[a2a_info.local_batch_num, table_split_lengths[i] * a2a_info.emb_dim]
|
| 317 |
-
)
|
| 318 |
-
req = dist.scatter(
|
| 319 |
-
out_tensor, scatter_list if i == my_rank else [], src=i, async_op=True
|
| 320 |
-
)
|
| 321 |
-
gather_list.append(out_tensor)
|
| 322 |
-
req_list.append(req)
|
| 323 |
-
myreq.req = req_list
|
| 324 |
-
myreq.tensor = tuple(gather_list)
|
| 325 |
-
myreq.a2a_info = a2a_info
|
| 326 |
-
ctx.a2a_info = a2a_info
|
| 327 |
-
return myreq.tensor
|
| 328 |
-
|
| 329 |
-
@staticmethod
|
| 330 |
-
def backward(ctx, *grad_output):
|
| 331 |
-
global myreq
|
| 332 |
-
for r in myreq.req:
|
| 333 |
-
r.wait()
|
| 334 |
-
myreq.req = None
|
| 335 |
-
grad_input = myreq.tensor
|
| 336 |
-
grad_inputs = grad_input.split(ctx.a2a_info.emb_dim, dim=1)
|
| 337 |
-
myreq.tensor = None
|
| 338 |
-
return (None, *grad_inputs)
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
class All2All_Scatter_Wait(Function):
|
| 342 |
-
@staticmethod
|
| 343 |
-
def forward(ctx, *output):
|
| 344 |
-
global myreq
|
| 345 |
-
ctx.a2a_info = myreq.a2a_info
|
| 346 |
-
for r in myreq.req:
|
| 347 |
-
r.wait()
|
| 348 |
-
myreq.req = None
|
| 349 |
-
myreq.tensor = None
|
| 350 |
-
return output
|
| 351 |
-
|
| 352 |
-
@staticmethod
|
| 353 |
-
def backward(ctx, *grad_output):
|
| 354 |
-
global myreq
|
| 355 |
-
assert len(grad_output) == my_size
|
| 356 |
-
scatter_list = [t.contiguous() for t in grad_output]
|
| 357 |
-
a2a_info = ctx.a2a_info
|
| 358 |
-
batch_split_lengths = (
|
| 359 |
-
a2a_info.global_batch_partition_slices
|
| 360 |
-
if a2a_info.global_batch_partition_slices
|
| 361 |
-
else a2a_info.local_batch_num
|
| 362 |
-
)
|
| 363 |
-
table_split_lengths = (
|
| 364 |
-
a2a_info.global_table_wise_parition_slices
|
| 365 |
-
if a2a_info.global_table_wise_parition_slices
|
| 366 |
-
else [a2a_info.local_table_num] * my_size
|
| 367 |
-
)
|
| 368 |
-
grad_input = grad_output[0].new_empty(
|
| 369 |
-
[a2a_info.batch_size, a2a_info.emb_dim * a2a_info.local_table_num]
|
| 370 |
-
)
|
| 371 |
-
gather_list = list(grad_input.split(batch_split_lengths, dim=0))
|
| 372 |
-
req_list = []
|
| 373 |
-
for i in range(my_size):
|
| 374 |
-
req = dist.gather(
|
| 375 |
-
scatter_list[i],
|
| 376 |
-
gather_list if i == my_rank else [],
|
| 377 |
-
dst=i,
|
| 378 |
-
async_op=True,
|
| 379 |
-
)
|
| 380 |
-
req_list.append(req)
|
| 381 |
-
myreq.req = req_list
|
| 382 |
-
myreq.tensor = grad_input
|
| 383 |
-
return grad_output
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
class All2All_Req(Function):
|
| 387 |
-
@staticmethod
|
| 388 |
-
def forward(ctx, a2a_info, *inputs):
|
| 389 |
-
global myreq
|
| 390 |
-
with record_function("DLRM alltoall_req_fwd_single"):
|
| 391 |
-
batch_split_lengths = a2a_info.global_batch_partition_slices
|
| 392 |
-
if batch_split_lengths:
|
| 393 |
-
batch_split_lengths = [
|
| 394 |
-
m * a2a_info.emb_dim * a2a_info.local_table_num
|
| 395 |
-
for m in batch_split_lengths
|
| 396 |
-
]
|
| 397 |
-
table_split_lengths = a2a_info.global_table_wise_parition_slices
|
| 398 |
-
if table_split_lengths:
|
| 399 |
-
table_split_lengths = [
|
| 400 |
-
a2a_info.local_batch_num * e * a2a_info.emb_dim
|
| 401 |
-
for e in table_split_lengths
|
| 402 |
-
]
|
| 403 |
-
input = torch.cat(inputs, dim=1).view([-1])
|
| 404 |
-
output = input.new_empty(
|
| 405 |
-
[
|
| 406 |
-
a2a_info.global_table_num
|
| 407 |
-
* a2a_info.local_batch_num
|
| 408 |
-
* a2a_info.emb_dim
|
| 409 |
-
]
|
| 410 |
-
)
|
| 411 |
-
req = dist.all_to_all_single(
|
| 412 |
-
output, input, table_split_lengths, batch_split_lengths, async_op=True
|
| 413 |
-
)
|
| 414 |
-
|
| 415 |
-
myreq.req = req
|
| 416 |
-
myreq.tensor = []
|
| 417 |
-
myreq.tensor.append(output)
|
| 418 |
-
myreq.tensor = tuple(myreq.tensor)
|
| 419 |
-
a2a_info.batch_split_lengths = batch_split_lengths
|
| 420 |
-
a2a_info.table_split_lengths = table_split_lengths
|
| 421 |
-
myreq.a2a_info = a2a_info
|
| 422 |
-
ctx.a2a_info = a2a_info
|
| 423 |
-
return myreq.tensor
|
| 424 |
-
|
| 425 |
-
@staticmethod
|
| 426 |
-
def backward(ctx, *grad_output):
|
| 427 |
-
global myreq
|
| 428 |
-
with record_function("DLRM alltoall_req_bwd_single"):
|
| 429 |
-
a2a_info = ctx.a2a_info
|
| 430 |
-
myreq.req.wait()
|
| 431 |
-
myreq.req = None
|
| 432 |
-
grad_input = myreq.tensor
|
| 433 |
-
grad_inputs = grad_input.view([a2a_info.batch_size, -1]).split(
|
| 434 |
-
a2a_info.emb_dim, dim=1
|
| 435 |
-
)
|
| 436 |
-
grad_inputs = [gin.contiguous() for gin in grad_inputs]
|
| 437 |
-
myreq.tensor = None
|
| 438 |
-
return (None, *grad_inputs)
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
class All2All_Wait(Function):
|
| 442 |
-
@staticmethod
|
| 443 |
-
def forward(ctx, *output):
|
| 444 |
-
global myreq
|
| 445 |
-
with record_function("DLRM alltoall_wait_fwd_single"):
|
| 446 |
-
a2a_info = myreq.a2a_info
|
| 447 |
-
ctx.a2a_info = a2a_info
|
| 448 |
-
myreq.req.wait()
|
| 449 |
-
myreq.req = None
|
| 450 |
-
myreq.tensor = None
|
| 451 |
-
table_split_lengths = (
|
| 452 |
-
a2a_info.table_split_lengths
|
| 453 |
-
if a2a_info.table_split_lengths
|
| 454 |
-
else a2a_info.local_table_num
|
| 455 |
-
* a2a_info.local_batch_num
|
| 456 |
-
* a2a_info.emb_dim
|
| 457 |
-
)
|
| 458 |
-
outputs = output[0].split(table_split_lengths)
|
| 459 |
-
outputs = tuple(
|
| 460 |
-
[out.view([a2a_info.local_batch_num, -1]) for out in outputs]
|
| 461 |
-
)
|
| 462 |
-
return outputs
|
| 463 |
-
|
| 464 |
-
@staticmethod
|
| 465 |
-
def backward(ctx, *grad_outputs):
|
| 466 |
-
global myreq
|
| 467 |
-
with record_function("DLRM alltoall_wait_bwd_single"):
|
| 468 |
-
a2a_info = ctx.a2a_info
|
| 469 |
-
grad_outputs = [gout.contiguous().view([-1]) for gout in grad_outputs]
|
| 470 |
-
grad_output = torch.cat(grad_outputs)
|
| 471 |
-
grad_input = grad_output.new_empty(
|
| 472 |
-
[a2a_info.batch_size * a2a_info.local_table_num * a2a_info.emb_dim]
|
| 473 |
-
)
|
| 474 |
-
req = dist.all_to_all_single(
|
| 475 |
-
grad_input,
|
| 476 |
-
grad_output,
|
| 477 |
-
a2a_info.batch_split_lengths,
|
| 478 |
-
a2a_info.table_split_lengths,
|
| 479 |
-
async_op=True,
|
| 480 |
-
)
|
| 481 |
-
myreq.req = req
|
| 482 |
-
myreq.tensor = grad_input
|
| 483 |
-
return (grad_output,)
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
class AllGather(Function):
|
| 487 |
-
@staticmethod
|
| 488 |
-
def forward(ctx, input, global_lengths, dim=0):
|
| 489 |
-
if not isinstance(global_lengths, (list, tuple)):
|
| 490 |
-
global_lengths = [global_lengths] * my_size
|
| 491 |
-
|
| 492 |
-
assert len(global_lengths) == my_size
|
| 493 |
-
assert global_lengths[my_rank] == input.size(dim)
|
| 494 |
-
local_start = sum(global_lengths[:my_rank])
|
| 495 |
-
|
| 496 |
-
output_size = list(input.size())
|
| 497 |
-
|
| 498 |
-
ctx.dim = dim
|
| 499 |
-
ctx.local_start = local_start
|
| 500 |
-
ctx.local_length = global_lengths[my_rank]
|
| 501 |
-
|
| 502 |
-
input = input.contiguous()
|
| 503 |
-
if dim == 0:
|
| 504 |
-
out_len = sum(global_lengths)
|
| 505 |
-
output_size[dim] = out_len
|
| 506 |
-
output = input.new_empty(output_size)
|
| 507 |
-
gather_list = list(output.split(global_lengths, dim=0))
|
| 508 |
-
else:
|
| 509 |
-
gather_list = [torch.empty_like(input) for _ in range(my_size)]
|
| 510 |
-
gather_list = []
|
| 511 |
-
for length in global_lengths:
|
| 512 |
-
output_size[dim] = length
|
| 513 |
-
gather_list.append(input.new_empty(output_size))
|
| 514 |
-
|
| 515 |
-
dist.all_gather(gather_list, input)
|
| 516 |
-
|
| 517 |
-
if dim != 0:
|
| 518 |
-
output = torch.cat(gather_list, dim=dim)
|
| 519 |
-
|
| 520 |
-
return output
|
| 521 |
-
|
| 522 |
-
@staticmethod
|
| 523 |
-
def backward(ctx, grad_output):
|
| 524 |
-
# print("Inside All2AllBackward")
|
| 525 |
-
dim = ctx.dim
|
| 526 |
-
start = ctx.local_start
|
| 527 |
-
length = ctx.local_length
|
| 528 |
-
|
| 529 |
-
grad_input = grad_output.narrow(dim, start, length)
|
| 530 |
-
|
| 531 |
-
return (grad_input, None, None)
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
class All2AllInfo(object):
|
| 535 |
-
pass
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
def alltoall(inputs, per_rank_table_splits):
|
| 539 |
-
global myreq
|
| 540 |
-
batch_size, emb_dim = inputs[0].size()
|
| 541 |
-
a2a_info = All2AllInfo()
|
| 542 |
-
a2a_info.local_table_num = len(inputs)
|
| 543 |
-
a2a_info.global_table_wise_parition_slices = per_rank_table_splits
|
| 544 |
-
(
|
| 545 |
-
a2a_info.local_batch_num,
|
| 546 |
-
a2a_info.global_batch_partition_slices,
|
| 547 |
-
) = get_split_lengths(batch_size)
|
| 548 |
-
a2a_info.emb_dim = emb_dim
|
| 549 |
-
a2a_info.batch_size = batch_size
|
| 550 |
-
a2a_info.global_table_num = (
|
| 551 |
-
sum(per_rank_table_splits)
|
| 552 |
-
if per_rank_table_splits
|
| 553 |
-
else a2a_info.local_table_num * my_size
|
| 554 |
-
)
|
| 555 |
-
|
| 556 |
-
if a2a_impl == "" and alltoall_supported or a2a_impl == "alltoall":
|
| 557 |
-
# print("Using All2All_Req")
|
| 558 |
-
output = All2All_Req.apply(a2a_info, *inputs)
|
| 559 |
-
myreq.WaitFunction = All2All_Wait
|
| 560 |
-
elif a2a_impl == "" or a2a_impl == "scatter":
|
| 561 |
-
# print("Using All2All_Scatter_Req")
|
| 562 |
-
output = All2All_Scatter_Req.apply(a2a_info, *inputs)
|
| 563 |
-
myreq.WaitFunction = All2All_Scatter_Wait
|
| 564 |
-
elif a2a_impl == "scatter_list":
|
| 565 |
-
# print("Using All2All_ScatterList_Req")
|
| 566 |
-
output = All2All_ScatterList_Req.apply(a2a_info, *inputs)
|
| 567 |
-
myreq.WaitFunction = All2All_ScatterList_Wait
|
| 568 |
-
else:
|
| 569 |
-
print(
|
| 570 |
-
"Unknown value set for DLRM_ALLTOALL_IMPL (%s), "
|
| 571 |
-
"please use one of [alltoall, scatter, scatter_list]" % a2a_impl
|
| 572 |
-
)
|
| 573 |
-
return myreq
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
def all_gather(input, lengths, dim=0):
|
| 577 |
-
global my_rank, my_size
|
| 578 |
-
if my_size == -1:
|
| 579 |
-
my_size = dist.get_world_size()
|
| 580 |
-
my_rank = dist.get_rank()
|
| 581 |
-
if not lengths:
|
| 582 |
-
lengths = [input.size(0)] * my_size
|
| 583 |
-
return AllGather.apply(input, lengths, dim)
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
def barrier():
|
| 587 |
-
if my_size > 1:
|
| 588 |
-
dist.barrier()
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
# Override builtin print function to print only from rank 0
|
| 592 |
-
orig_print = builtins.print
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
def rank0_print(*args, **kwargs):
|
| 596 |
-
if my_rank <= 0 or kwargs.get("print_all", False):
|
| 597 |
-
orig_print(*args, **kwargs)
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
# builtins.print = rank0_print
|
| 601 |
-
|
| 602 |
-
# Allow printing from all rank with explicit print_all
|
| 603 |
-
def print_all(*args, **kwargs):
|
| 604 |
-
orig_print(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/modules/transformer.py
DELETED
|
@@ -1,185 +0,0 @@
|
|
| 1 |
-
# attention
|
| 2 |
-
from torch import einsum
|
| 3 |
-
import torch.nn as nn
|
| 4 |
-
import torch.nn.functional as F
|
| 5 |
-
import torch
|
| 6 |
-
from einops import rearrange
|
| 7 |
-
from .utils import l2norm, default, exists
|
| 8 |
-
|
| 9 |
-
# 2d sinusoidal positional embedding
|
| 10 |
-
# simple vit paper shows it is good enough compared to learned
|
| 11 |
-
|
| 12 |
-
def posemb_sincos_2d(patches, temperature = 10000, dtype = torch.float32):
|
| 13 |
-
_, h, w, dim, device, dtype = *patches.shape, patches.device, patches.dtype
|
| 14 |
-
|
| 15 |
-
y, x = torch.meshgrid(torch.arange(h, device = device), torch.arange(w, device = device), indexing = 'ij')
|
| 16 |
-
assert (dim % 4) == 0, 'feature dimension must be multiple of 4 for sincos emb'
|
| 17 |
-
|
| 18 |
-
omega = torch.arange(dim // 4, device = device) / (dim // 4 - 1)
|
| 19 |
-
omega = 1. / (temperature ** omega)
|
| 20 |
-
|
| 21 |
-
y = y.flatten()[:, None] * omega[None, :]
|
| 22 |
-
x = x.flatten()[:, None] * omega[None, :]
|
| 23 |
-
|
| 24 |
-
pe = torch.cat((x.sin(), x.cos(), y.sin(), y.cos()), dim = 1)
|
| 25 |
-
pe = pe.type(dtype)
|
| 26 |
-
|
| 27 |
-
return rearrange(pe, '(h w) d -> h w d', h = h, w = w)
|
| 28 |
-
|
| 29 |
-
# biasless layernorm
|
| 30 |
-
|
| 31 |
-
class LayerNorm(nn.Module):
|
| 32 |
-
def __init__(self, dim, scale = True):
|
| 33 |
-
super().__init__()
|
| 34 |
-
self.learned_gamma = nn.Parameter(torch.ones(dim)) if scale else None
|
| 35 |
-
|
| 36 |
-
self.register_buffer('gamma', torch.ones(dim), persistent = False)
|
| 37 |
-
self.register_buffer('beta', torch.zeros(dim), persistent = False)
|
| 38 |
-
|
| 39 |
-
def forward(self, x):
|
| 40 |
-
return F.layer_norm(x, x.shape[-1:], default(self.learned_gamma, self.gamma), self.beta)
|
| 41 |
-
|
| 42 |
-
# feedforward
|
| 43 |
-
|
| 44 |
-
class GEGLU(nn.Module):
|
| 45 |
-
def forward(self, x):
|
| 46 |
-
x, gate = x.chunk(2, dim = -1)
|
| 47 |
-
return F.gelu(gate) * x
|
| 48 |
-
|
| 49 |
-
def FeedForward(dim, mult = 4, dropout = 0.):
|
| 50 |
-
dim_hidden = int(dim * mult * 2 / 3)
|
| 51 |
-
|
| 52 |
-
return nn.Sequential(
|
| 53 |
-
LayerNorm(dim),
|
| 54 |
-
nn.Linear(dim, dim_hidden * 2, bias = False),
|
| 55 |
-
GEGLU(),
|
| 56 |
-
nn.Dropout(dropout),
|
| 57 |
-
nn.Linear(dim_hidden, dim, bias = False)
|
| 58 |
-
)
|
| 59 |
-
|
| 60 |
-
class Attention(nn.Module):
|
| 61 |
-
def __init__(
|
| 62 |
-
self,
|
| 63 |
-
dim,
|
| 64 |
-
causal = False,
|
| 65 |
-
dim_head = 64,
|
| 66 |
-
heads = 8,
|
| 67 |
-
dropout = 0.,
|
| 68 |
-
scale = 8
|
| 69 |
-
):
|
| 70 |
-
super().__init__()
|
| 71 |
-
self.heads = heads
|
| 72 |
-
self.scale = scale
|
| 73 |
-
self.causal = causal
|
| 74 |
-
inner_dim = dim_head * heads
|
| 75 |
-
|
| 76 |
-
self.norm = LayerNorm(dim)
|
| 77 |
-
|
| 78 |
-
self.attn_dropout = nn.Dropout(dropout)
|
| 79 |
-
|
| 80 |
-
self.to_q = nn.Linear(dim, inner_dim, bias = False)
|
| 81 |
-
self.to_kv = nn.Linear(dim, inner_dim * 2, bias = False)
|
| 82 |
-
|
| 83 |
-
self.q_scale = nn.Parameter(torch.ones(dim_head))
|
| 84 |
-
self.k_scale = nn.Parameter(torch.ones(dim_head))
|
| 85 |
-
|
| 86 |
-
self.to_out = nn.Sequential(
|
| 87 |
-
nn.Linear(inner_dim, dim, bias = False),
|
| 88 |
-
nn.Dropout(dropout)
|
| 89 |
-
)
|
| 90 |
-
|
| 91 |
-
def forward(
|
| 92 |
-
self,
|
| 93 |
-
x,
|
| 94 |
-
rel_pos_bias = None,
|
| 95 |
-
mask = None
|
| 96 |
-
):
|
| 97 |
-
b, n, _, device = *x.shape, x.device
|
| 98 |
-
|
| 99 |
-
# prenorm
|
| 100 |
-
|
| 101 |
-
x = self.norm(x)
|
| 102 |
-
|
| 103 |
-
# project for queries, keys, values
|
| 104 |
-
|
| 105 |
-
q, k, v = self.to_q(x), *self.to_kv(x).chunk(2, dim = -1)
|
| 106 |
-
|
| 107 |
-
# split for multi-headed attention
|
| 108 |
-
|
| 109 |
-
q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = self.heads), (q, k, v))
|
| 110 |
-
|
| 111 |
-
# qk rmsnorm, technique circulating within brain used to stabilize a 22B parameter vision model training
|
| 112 |
-
|
| 113 |
-
q, k = map(l2norm, (q, k))
|
| 114 |
-
q = q * self.q_scale
|
| 115 |
-
k = k * self.k_scale
|
| 116 |
-
|
| 117 |
-
# similarities
|
| 118 |
-
|
| 119 |
-
sim = einsum('b h i d, b h j d -> b h i j', q, k) * self.scale
|
| 120 |
-
|
| 121 |
-
if exists(rel_pos_bias):
|
| 122 |
-
sim = sim + rel_pos_bias
|
| 123 |
-
|
| 124 |
-
if exists(mask):
|
| 125 |
-
mask = rearrange(mask, 'b j -> b 1 1 j')
|
| 126 |
-
sim = sim.masked_fill(~mask, -torch.finfo(sim.dtype).max)
|
| 127 |
-
|
| 128 |
-
if self.causal:
|
| 129 |
-
i, j = sim.shape[-2:]
|
| 130 |
-
causal_mask = torch.ones((i, j), dtype = torch.bool, device = x.device).triu(j - i + 1)
|
| 131 |
-
sim = sim.masked_fill(causal_mask, -torch.finfo(sim.dtype).max)
|
| 132 |
-
|
| 133 |
-
# attention
|
| 134 |
-
|
| 135 |
-
attn = sim.softmax(dim = -1)
|
| 136 |
-
attn = self.attn_dropout(attn)
|
| 137 |
-
|
| 138 |
-
# aggregate
|
| 139 |
-
|
| 140 |
-
out = einsum('b h i j, b h j d -> b h i d', attn, v)
|
| 141 |
-
|
| 142 |
-
# merge heads
|
| 143 |
-
|
| 144 |
-
out = rearrange(out, 'b h n d -> b n (h d)')
|
| 145 |
-
return self.to_out(out)
|
| 146 |
-
|
| 147 |
-
# transformer
|
| 148 |
-
|
| 149 |
-
class Transformer(nn.Module):
|
| 150 |
-
def __init__(
|
| 151 |
-
self,
|
| 152 |
-
dim,
|
| 153 |
-
depth,
|
| 154 |
-
dim_head = 64,
|
| 155 |
-
heads = 8,
|
| 156 |
-
attn_dropout = 0.,
|
| 157 |
-
ff_mult = 4,
|
| 158 |
-
ff_dropout = 0.
|
| 159 |
-
):
|
| 160 |
-
super().__init__()
|
| 161 |
-
self.layers = nn.ModuleList([])
|
| 162 |
-
for _ in range(depth):
|
| 163 |
-
self.layers.append(nn.ModuleList([
|
| 164 |
-
Attention(dim = dim, dim_head = dim_head, heads = heads, dropout = attn_dropout),
|
| 165 |
-
FeedForward(dim = dim, mult = ff_mult, dropout = ff_dropout),
|
| 166 |
-
]))
|
| 167 |
-
|
| 168 |
-
def forward(
|
| 169 |
-
self,
|
| 170 |
-
x,
|
| 171 |
-
rel_pos_bias = None,
|
| 172 |
-
mask = None,
|
| 173 |
-
return_all_layers = False
|
| 174 |
-
):
|
| 175 |
-
layers = []
|
| 176 |
-
|
| 177 |
-
for attn, ff in self.layers:
|
| 178 |
-
x = attn(x, rel_pos_bias = rel_pos_bias, mask = mask) + x
|
| 179 |
-
x = ff(x) + x
|
| 180 |
-
layers.append(x)
|
| 181 |
-
|
| 182 |
-
if not return_all_layers:
|
| 183 |
-
return x
|
| 184 |
-
|
| 185 |
-
return x, torch.stack(layers[:-1]) if len(self.layers)>1 else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/modules/utils.py
DELETED
|
@@ -1,45 +0,0 @@
|
|
| 1 |
-
from functools import wraps
|
| 2 |
-
import torch
|
| 3 |
-
from torch import nn
|
| 4 |
-
import torch.nn.functional as F
|
| 5 |
-
|
| 6 |
-
def exists(val):
|
| 7 |
-
return val is not None
|
| 8 |
-
|
| 9 |
-
def first(it):
|
| 10 |
-
return it[0]
|
| 11 |
-
|
| 12 |
-
def default(val, d):
|
| 13 |
-
return val if exists(val) else d
|
| 14 |
-
|
| 15 |
-
def round_down_nearest_multiple(n, divisor):
|
| 16 |
-
return n // divisor * divisor
|
| 17 |
-
|
| 18 |
-
def Sequential(*modules):
|
| 19 |
-
return nn.Sequential(*filter(exists, modules))
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def once(fn):
|
| 23 |
-
called = False
|
| 24 |
-
@wraps(fn)
|
| 25 |
-
def inner(x):
|
| 26 |
-
nonlocal called
|
| 27 |
-
if called:
|
| 28 |
-
return
|
| 29 |
-
called = True
|
| 30 |
-
return fn(x)
|
| 31 |
-
return inner
|
| 32 |
-
|
| 33 |
-
print_once = once(print)
|
| 34 |
-
|
| 35 |
-
# tensor functions
|
| 36 |
-
|
| 37 |
-
def log(t, eps = 1e-20):
|
| 38 |
-
return torch.log(t.clamp(min = eps))
|
| 39 |
-
|
| 40 |
-
def l2norm(t):
|
| 41 |
-
return F.normalize(t, p = 2, dim = -1)
|
| 42 |
-
|
| 43 |
-
def frozen_params(model:nn.Module):
|
| 44 |
-
for param in model.parameters():
|
| 45 |
-
param.requires_grad = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/muq/muq_mulan/muq_mulan.py
DELETED
|
@@ -1,271 +0,0 @@
|
|
| 1 |
-
from typing import List, Optional
|
| 2 |
-
from dataclasses import dataclass, field
|
| 3 |
-
import os
|
| 4 |
-
|
| 5 |
-
from torch.nn.parallel.distributed import DistributedDataParallel
|
| 6 |
-
import torch
|
| 7 |
-
import torch.nn as nn
|
| 8 |
-
from torch import einsum
|
| 9 |
-
from einops import rearrange
|
| 10 |
-
from huggingface_hub import PyTorchModelHubMixin
|
| 11 |
-
from easydict import EasyDict
|
| 12 |
-
|
| 13 |
-
from .models.mulan import MuLanModel
|
| 14 |
-
from .models.audio import AudioSpectrogramTransformerPretrained
|
| 15 |
-
from .models.text import TextTransformerPretrained
|
| 16 |
-
from .modules.utils import exists, frozen_params
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
@dataclass
|
| 20 |
-
class MuLanConfig:
|
| 21 |
-
sr:int = field(default=24000)
|
| 22 |
-
clip_secs:float = field(default=10)
|
| 23 |
-
dim_latent:int = field(default=512)
|
| 24 |
-
decoupled_contrastive_learning:bool = field(default=True)
|
| 25 |
-
hierarchical_contrastive_loss:bool = field(default=False)
|
| 26 |
-
hierarchical_contrastive_loss_layers:Optional[List] = field(default=None)
|
| 27 |
-
sigmoid_contrastive_loss:bool = field(default=False)
|
| 28 |
-
rank_contrast:bool = field(default=True)
|
| 29 |
-
|
| 30 |
-
@dataclass
|
| 31 |
-
class AudioTransformerConfig:
|
| 32 |
-
dim:int = field(default=768)
|
| 33 |
-
tf_depth:int = field(default=8)
|
| 34 |
-
heads:int = field(default=8)
|
| 35 |
-
dim_head:int = field(default=64)
|
| 36 |
-
attn_dropout:float = field(default=0.)
|
| 37 |
-
ff_dropout:float = field(default=0.)
|
| 38 |
-
ff_mult:int = field(default=4)
|
| 39 |
-
|
| 40 |
-
@dataclass
|
| 41 |
-
class TextTransformerConfig:
|
| 42 |
-
dim:int = field(default=768)
|
| 43 |
-
tf_depth:int = field(default=8)
|
| 44 |
-
max_seq_len:int = field(default=1024)
|
| 45 |
-
dim_head:int = field(default=64)
|
| 46 |
-
heads:int = field(default=8)
|
| 47 |
-
attn_dropout:float = field(default=0.)
|
| 48 |
-
ff_dropout:float = field(default=0.)
|
| 49 |
-
ff_mult:int = field(default=4)
|
| 50 |
-
|
| 51 |
-
@dataclass
|
| 52 |
-
class ModalModelConfig:
|
| 53 |
-
name:str = field(default='')
|
| 54 |
-
model_dim: Optional[int] = field(default=None)
|
| 55 |
-
use_layer_idx: int = field(default=-1)
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
@dataclass
|
| 59 |
-
class MuQMuLanConfig:
|
| 60 |
-
mulan: MuLanConfig
|
| 61 |
-
audio_model: ModalModelConfig
|
| 62 |
-
text_model: ModalModelConfig
|
| 63 |
-
audio_transformer: AudioTransformerConfig
|
| 64 |
-
text_transformer: TextTransformerConfig
|
| 65 |
-
|
| 66 |
-
class MuQMuLan(nn.Module, PyTorchModelHubMixin):
|
| 67 |
-
def __init__(self, config: MuQMuLanConfig, hf_hub_cache_dir=None):
|
| 68 |
-
super().__init__()
|
| 69 |
-
config = self._to_obj(config)
|
| 70 |
-
self.config = config
|
| 71 |
-
self.mulan = self.create_MuLan_from_config(config, hf_hub_cache_dir)
|
| 72 |
-
self.sr = config.mulan.sr
|
| 73 |
-
self.clip_secs = config.mulan.clip_secs
|
| 74 |
-
|
| 75 |
-
def _to_obj(self, config):
|
| 76 |
-
if isinstance(config, MuQMuLanConfig):
|
| 77 |
-
config = EasyDict(
|
| 78 |
-
mulan = config.mulan,
|
| 79 |
-
audio_model = config.audio_model,
|
| 80 |
-
text_model = config.text_model,
|
| 81 |
-
audio_transformer = config.audio_transformer,
|
| 82 |
-
text_transformer = config.text_transformer,
|
| 83 |
-
)
|
| 84 |
-
else:
|
| 85 |
-
config = EasyDict(config)
|
| 86 |
-
return config
|
| 87 |
-
|
| 88 |
-
@classmethod
|
| 89 |
-
def from_pretrained(cls, *args, cache_dir=None, **kwargs):
|
| 90 |
-
kwargs['hf_hub_cache_dir'] = cache_dir
|
| 91 |
-
return super().from_pretrained(*args, cache_dir=cache_dir, **kwargs)
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
@classmethod
|
| 95 |
-
def create_MuLan_from_config(cls, config:MuQMuLanConfig, hf_hub_cache_dir=None) -> MuLanModel:
|
| 96 |
-
|
| 97 |
-
audio_transformer = AudioSpectrogramTransformerPretrained(
|
| 98 |
-
model_name = config.audio_model.name,
|
| 99 |
-
model_dim = config.audio_model.model_dim,
|
| 100 |
-
use_layer_idx = config.audio_model.use_layer_idx,
|
| 101 |
-
**config.audio_transformer,
|
| 102 |
-
frozen_pretrained = False,
|
| 103 |
-
hf_hub_cache_dir = hf_hub_cache_dir,
|
| 104 |
-
)
|
| 105 |
-
text_transformer = TextTransformerPretrained(
|
| 106 |
-
model_name = config.text_model.name,
|
| 107 |
-
model_dim = config.text_model.model_dim,
|
| 108 |
-
**config.text_transformer,
|
| 109 |
-
frozen_pretrained = False,
|
| 110 |
-
hf_hub_cache_dir = hf_hub_cache_dir,
|
| 111 |
-
)
|
| 112 |
-
|
| 113 |
-
mulan = MuLanModel(
|
| 114 |
-
audio_transformer = audio_transformer,
|
| 115 |
-
text_transformer = text_transformer,
|
| 116 |
-
**config.mulan
|
| 117 |
-
)
|
| 118 |
-
|
| 119 |
-
return mulan
|
| 120 |
-
|
| 121 |
-
def frozen(self):
|
| 122 |
-
frozen_params(self)
|
| 123 |
-
|
| 124 |
-
@property
|
| 125 |
-
def device(self):
|
| 126 |
-
return next(self.parameters()).device
|
| 127 |
-
|
| 128 |
-
@property
|
| 129 |
-
def mulan_module(self):
|
| 130 |
-
if isinstance(self.mulan, DistributedDataParallel):
|
| 131 |
-
return self.mulan.module
|
| 132 |
-
else:
|
| 133 |
-
return self.mulan
|
| 134 |
-
|
| 135 |
-
def forward(self,
|
| 136 |
-
wavs: Optional[torch.Tensor] = None,
|
| 137 |
-
texts: Optional[List[str]] = None,
|
| 138 |
-
*,
|
| 139 |
-
parallel_processing = False,
|
| 140 |
-
) -> torch.Tensor:
|
| 141 |
-
"""
|
| 142 |
-
Extract audio or text features, takes audio OR texts batch as input.
|
| 143 |
-
Note that if the audio is longer than 10s, it will be crop to multi cips and returns the average latent.
|
| 144 |
-
The param `parallel_processing` is used to control whether to use parallel processing or not.
|
| 145 |
-
If set to True, it uses parallel processing extractraction, which is faster but uses more GPU memory.
|
| 146 |
-
If set to False(the default), it uses serial processing extraction, which is slower but memory-friendly.
|
| 147 |
-
|
| 148 |
-
Args:
|
| 149 |
-
wavs (Optional[torch.Tensor]): Audio waveform tensor. Defaults to None.
|
| 150 |
-
texts (Optional[List[str]]): List of text strings. Defaults to None.
|
| 151 |
-
parallel_processing (bool): Whether to use parallel processing. Defaults to False.
|
| 152 |
-
|
| 153 |
-
Returns:
|
| 154 |
-
torch.Tensor: Latent representation of audio or text input.
|
| 155 |
-
|
| 156 |
-
Raises:
|
| 157 |
-
AssertionError: If both wavs and texts are provided or if neither is provided.
|
| 158 |
-
|
| 159 |
-
Note:
|
| 160 |
-
- Either wavs or texts must be provided, but not both.
|
| 161 |
-
- If wavs is provided, it calls extract_audio_latents method to process audio.
|
| 162 |
-
- If texts is provided, it calls extract_text_latents method to process text.
|
| 163 |
-
"""
|
| 164 |
-
assert exists(wavs) ^ exists(texts), "Please provide either wavs or texts, but not both"
|
| 165 |
-
|
| 166 |
-
if exists(wavs):
|
| 167 |
-
return self.extract_audio_latents(wavs = wavs, parallel_processing = parallel_processing)
|
| 168 |
-
else:
|
| 169 |
-
return self.extract_text_latents(texts = texts)
|
| 170 |
-
|
| 171 |
-
def calc_similarity(self, audio_latents: torch.Tensor, text_latents: torch.Tensor) -> torch.Tensor:
|
| 172 |
-
"""
|
| 173 |
-
Calculate the dot-product similarity between audio and text latent representations.
|
| 174 |
-
It supports various dimensions of input tensors (with/without batch dimension) for both audio and text.
|
| 175 |
-
|
| 176 |
-
Note:
|
| 177 |
-
The effect of this function is basically equivalent to the dot product.
|
| 178 |
-
mulan.calc_similarity(lat_a, lat_t) <==> einsum('i d, j d -> i j', lat_a, lat_t)
|
| 179 |
-
|
| 180 |
-
Args:
|
| 181 |
-
audio_latents (torch.Tensor): Latent representation of audio.
|
| 182 |
-
text_latents (torch.Tensor): Latent representation of text.
|
| 183 |
-
|
| 184 |
-
Returns:
|
| 185 |
-
torch.Tensor: Similarity scores between audio and text latent representations.
|
| 186 |
-
|
| 187 |
-
"""
|
| 188 |
-
dim_a, dim_t = len(audio_latents.shape), len(text_latents.shape)
|
| 189 |
-
if dim_a == 2 and dim_t == 2:
|
| 190 |
-
return einsum('i d, j d -> i j', audio_latents, text_latents)
|
| 191 |
-
elif dim_a == 1 and dim_t == 1:
|
| 192 |
-
return torch.dot(audio_latents, text_latents)
|
| 193 |
-
elif dim_a == 2 and dim_t == 1:
|
| 194 |
-
return einsum('i d, d -> i', audio_latents, text_latents)
|
| 195 |
-
elif dim_a == 1 and dim_t == 2:
|
| 196 |
-
return einsum('d, j d -> j', audio_latents, text_latents)
|
| 197 |
-
|
| 198 |
-
raise RuntimeError(f"Invalid dimensions: audio {dim_a}, text {dim_t}")
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
def extract_audio_latents(self, wavs:torch.Tensor, *, parallel_processing = False) -> torch.Tensor:
|
| 202 |
-
"""
|
| 203 |
-
Extract latent representations from audio waveforms.
|
| 204 |
-
|
| 205 |
-
This function processes a batch of audio waveforms and extracts their latent representations.
|
| 206 |
-
It supports parallel processing for faster computation but uses more GPU memory.
|
| 207 |
-
|
| 208 |
-
Args:
|
| 209 |
-
wavs (torch.Tensor): A batch of audio waveform tensors.
|
| 210 |
-
parallel_processing (bool): Flag to enable parallel processing. Defaults to False.
|
| 211 |
-
|
| 212 |
-
Returns:
|
| 213 |
-
torch.Tensor: A tensor containing the latent representations of the input audio waveforms.
|
| 214 |
-
"""
|
| 215 |
-
audio_latents = []
|
| 216 |
-
|
| 217 |
-
def audio_to_latent(wav):
|
| 218 |
-
return self.mulan_module.get_audio_latents(wav)
|
| 219 |
-
for wav in wavs:
|
| 220 |
-
wav_tensors = []
|
| 221 |
-
if isinstance(wav, torch.Tensor):
|
| 222 |
-
wav_tensors = self._get_all_clips(wav)
|
| 223 |
-
else:
|
| 224 |
-
raise TypeError('wavs must be a Tensor')
|
| 225 |
-
|
| 226 |
-
if parallel_processing:
|
| 227 |
-
wav_tensors = wav_tensors.to(self.device)
|
| 228 |
-
audio_latent = audio_to_latent(wav_tensors)
|
| 229 |
-
audio_latent = audio_latent.mean(dim=0)
|
| 230 |
-
else:
|
| 231 |
-
wav_tensors = rearrange(wav_tensors, "i j -> i 1 j")
|
| 232 |
-
audio_latent = []
|
| 233 |
-
for wav_tensor in wav_tensors:
|
| 234 |
-
audio_latent.append(audio_to_latent(wav_tensor).squeeze(0))
|
| 235 |
-
del wav_tensor
|
| 236 |
-
audio_latent = torch.stack(audio_latent, dim=0)
|
| 237 |
-
audio_latent = audio_latent.mean(dim=0).to(self.device)
|
| 238 |
-
|
| 239 |
-
audio_latents.append(audio_latent)
|
| 240 |
-
audio_latents = torch.stack(audio_latents, dim=0)
|
| 241 |
-
return audio_latents
|
| 242 |
-
|
| 243 |
-
def extract_text_latents(self, texts: List[str]) -> torch.Tensor:
|
| 244 |
-
"""
|
| 245 |
-
Extract latent representations from text inputs.
|
| 246 |
-
|
| 247 |
-
This function processes a list of text strings and extracts their latent representations
|
| 248 |
-
using the MuLan model's text tower.
|
| 249 |
-
|
| 250 |
-
Args:
|
| 251 |
-
texts (List[str]): A list of text strings to be processed.
|
| 252 |
-
|
| 253 |
-
Returns:
|
| 254 |
-
torch.Tensor: A tensor containing the latent representations of the input texts.
|
| 255 |
-
"""
|
| 256 |
-
return self.mulan_module.get_text_latents(raw_texts=texts)
|
| 257 |
-
|
| 258 |
-
def _get_all_clips(self, audio):
|
| 259 |
-
origin_length = len(audio)
|
| 260 |
-
accum_length = 0
|
| 261 |
-
delta = self.sr * self.clip_secs
|
| 262 |
-
audio_clips = []
|
| 263 |
-
while accum_length + delta <= origin_length:
|
| 264 |
-
clip = audio[accum_length:accum_length + delta]
|
| 265 |
-
audio_clips.append(clip)
|
| 266 |
-
accum_length += delta
|
| 267 |
-
if accum_length < origin_length:
|
| 268 |
-
audio_clips.append(torch.cat([audio[accum_length:], audio[0:delta - (origin_length - accum_length)]]))
|
| 269 |
-
|
| 270 |
-
return torch.stack(audio_clips, dim=0)
|
| 271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/README.md
DELETED
|
@@ -1,107 +0,0 @@
|
|
| 1 |
-
`
|
| 2 |
-
# Guidance on MuQ-MuLan Training (Contrastive Learning)
|
| 3 |
-
|
| 4 |
-
This guide provides instructions for training **MuQ-MuLan**, a contrastive learning model that jointly encodes music and text.
|
| 5 |
-
|
| 6 |
-
We recommend training on **32 GPUs**, each with **at least 32 GB of memory**. Training typically takes **1–2 days**, depending on hardware environment.
|
| 7 |
-
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
## Step 1: Environment Setup
|
| 11 |
-
|
| 12 |
-
First, install all required dependencies listed in [requirements.txt](./requirements.txt):
|
| 13 |
-
|
| 14 |
-
```bash
|
| 15 |
-
pip install -r requirements.txt
|
| 16 |
-
```
|
| 17 |
-
|
| 18 |
-
Then, install this repository as a library in editable mode:
|
| 19 |
-
|
| 20 |
-
```bash
|
| 21 |
-
pip install -e .
|
| 22 |
-
```
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
---
|
| 26 |
-
|
| 27 |
-
## Step 2: Data Preparation
|
| 28 |
-
|
| 29 |
-
We provide an example setup using the [MTG-Jamendo](https://github.com/MTG/mtg-jamendo-dataset) open-source music dataset.
|
| 30 |
-
|
| 31 |
-
Please download our preprocessed data split files from [this link](https://drive.google.com/file/d/1PMCUpmtw8JwUv9Y-bNl8WIAZDtX8UaFY/view?usp=sharing) and place them in the appropriate directory.
|
| 32 |
-
|
| 33 |
-
If you wish to use your own dataset, ensure that your data follow the required format.
|
| 34 |
-
|
| 35 |
-
---
|
| 36 |
-
|
| 37 |
-
## Step 3: Run Training
|
| 38 |
-
|
| 39 |
-
### Option 1: Manual Configuration
|
| 40 |
-
|
| 41 |
-
This method will prompt you to configure distributed training manually via `accelerate`:
|
| 42 |
-
|
| 43 |
-
```bash
|
| 44 |
-
accelerate config
|
| 45 |
-
accelerate launch train.py
|
| 46 |
-
```
|
| 47 |
-
|
| 48 |
-
### Option 2: Using a Predefined Config File
|
| 49 |
-
|
| 50 |
-
We provide example config files for multi-node multi-GPU training. For example, to launch training on **4 nodes**, each with **8 GPUs**, run:
|
| 51 |
-
|
| 52 |
-
```bash
|
| 53 |
-
accelerate launch \
|
| 54 |
-
--config_file config/accelerate/32gpu4node_fp16.yaml \
|
| 55 |
-
--machine_rank $NODE_RANK \
|
| 56 |
-
--main_process_ip $CHIEF_IP \
|
| 57 |
-
--main_process_port 29500 \
|
| 58 |
-
train.py
|
| 59 |
-
```
|
| 60 |
-
|
| 61 |
-
* `$NODE_RANK`: Index of the current machine (0 for the main node).
|
| 62 |
-
* `$CHIEF_IP`: IP address of the main (rank-0) node.
|
| 63 |
-
* Adjust the config file as needed for different hardware setups.
|
| 64 |
-
|
| 65 |
-
If you are training on a **single machine**, simply set `--main_process_ip=127.0.0.1` and `--machine_rank=0`.
|
| 66 |
-
|
| 67 |
-
If you wish to use your own pretrained MuQ model for initialization, simply modify the `model.mulan.audio_model.name` field in `config/model/muq_mulan.yaml`.
|
| 68 |
-
|
| 69 |
-
---
|
| 70 |
-
|
| 71 |
-
## Step 4: Convert to HF Checkpoint
|
| 72 |
-
|
| 73 |
-
After training, convert your Fairseq-style checkpoint to HuggingFace format:
|
| 74 |
-
|
| 75 |
-
```bash
|
| 76 |
-
python scripts/convert_muqmulan_fairseq_ckpt_to_huggingface.py \
|
| 77 |
-
--checkpoint_path outputs/YYYY-MM-DD/hh-mm-ss/ckpt/mulan.1100.pt \
|
| 78 |
-
--save_dir outputs/hf-username/My-MuQ-MuLan-large
|
| 79 |
-
```
|
| 80 |
-
|
| 81 |
-
You can then load and use the model via the HuggingFace-style interface:
|
| 82 |
-
|
| 83 |
-
```python
|
| 84 |
-
from muq import MuQMuLan
|
| 85 |
-
|
| 86 |
-
# Load from local HuggingFace-style checkpoint
|
| 87 |
-
mulan = MuQMuLan.from_pretrained("outputs/hf-username/My-MuQ-MuLan-large")
|
| 88 |
-
mulan = mulan.to(device).eval()
|
| 89 |
-
|
| 90 |
-
# Extract music embeddings
|
| 91 |
-
audio_embeds = mulan(wavs=wavs)
|
| 92 |
-
|
| 93 |
-
# Extract text embeddings (in English or Chinese)
|
| 94 |
-
text_embeds = mulan(texts=texts)
|
| 95 |
-
|
| 96 |
-
# Compute similarity
|
| 97 |
-
sim = mulan.calc_similarity(audio_embeds, text_embeds)
|
| 98 |
-
```
|
| 99 |
-
|
| 100 |
-
You can also upload your converted checkpoint to the Hugging Face Hub using `huggingface-cli`. The uploaded model will remain fully compatible with the `MuQMuLan.from_pretrained()` interface.
|
| 101 |
-
|
| 102 |
-
---
|
| 103 |
-
|
| 104 |
-
## Evaluation
|
| 105 |
-
|
| 106 |
-
For evaluation, we recommend using the [sota-music-tagging-models](https://github.com/minzwon/sota-music-tagging-models/) toolkit. It supports various metrics and datasets widely used in music tagging and retrieval.
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/2gpu.yaml
DELETED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
distributed_type: MULTI_GPU
|
| 4 |
-
downcast_bf16: 'no'
|
| 5 |
-
enable_cpu_affinity: false
|
| 6 |
-
gpu_ids: all
|
| 7 |
-
machine_rank: 0
|
| 8 |
-
main_training_function: main
|
| 9 |
-
mixed_precision: 'no'
|
| 10 |
-
num_machines: 1
|
| 11 |
-
num_processes: 2
|
| 12 |
-
rdzv_backend: static
|
| 13 |
-
same_network: true
|
| 14 |
-
tpu_env: []
|
| 15 |
-
tpu_use_cluster: false
|
| 16 |
-
tpu_use_sudo: false
|
| 17 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node.yaml
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
distributed_type: MULTI_GPU
|
| 4 |
-
downcast_bf16: 'no'
|
| 5 |
-
enable_cpu_affinity: false
|
| 6 |
-
gpu_ids: all
|
| 7 |
-
machine_rank: 0
|
| 8 |
-
main_process_ip: '11.214.123.26'
|
| 9 |
-
main_process_port: 25545
|
| 10 |
-
main_training_function: main
|
| 11 |
-
mixed_precision: 'no'
|
| 12 |
-
num_machines: 4
|
| 13 |
-
num_processes: 32
|
| 14 |
-
rdzv_backend: static
|
| 15 |
-
same_network: true
|
| 16 |
-
tpu_env: []
|
| 17 |
-
tpu_use_cluster: false
|
| 18 |
-
tpu_use_sudo: false
|
| 19 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node_fp16.yaml
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
distributed_type: MULTI_GPU
|
| 4 |
-
downcast_bf16: 'no'
|
| 5 |
-
enable_cpu_affinity: false
|
| 6 |
-
gpu_ids: all
|
| 7 |
-
machine_rank: 0
|
| 8 |
-
main_process_ip: $INDEX
|
| 9 |
-
main_process_port: 25529
|
| 10 |
-
main_training_function: main
|
| 11 |
-
mixed_precision: fp16
|
| 12 |
-
num_machines: 4
|
| 13 |
-
num_processes: 32
|
| 14 |
-
rdzv_backend: static
|
| 15 |
-
same_network: true
|
| 16 |
-
tpu_env: []
|
| 17 |
-
tpu_use_cluster: false
|
| 18 |
-
tpu_use_sudo: false
|
| 19 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/32gpu4node_zero2.yaml
DELETED
|
@@ -1,25 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
deepspeed_config:
|
| 4 |
-
deepspeed_multinode_launcher: standard
|
| 5 |
-
gradient_accumulation_steps: 1
|
| 6 |
-
offload_optimizer_device: none
|
| 7 |
-
offload_param_device: none
|
| 8 |
-
zero3_init_flag: false
|
| 9 |
-
zero_stage: 2
|
| 10 |
-
distributed_type: DEEPSPEED
|
| 11 |
-
downcast_bf16: 'no'
|
| 12 |
-
enable_cpu_affinity: false
|
| 13 |
-
machine_rank: 0
|
| 14 |
-
main_process_ip: $CHIEF_IP
|
| 15 |
-
main_process_port: 25520
|
| 16 |
-
main_training_function: main
|
| 17 |
-
mixed_precision: 'no'
|
| 18 |
-
num_machines: 4
|
| 19 |
-
num_processes: 32
|
| 20 |
-
rdzv_backend: static
|
| 21 |
-
same_network: true
|
| 22 |
-
tpu_env: []
|
| 23 |
-
tpu_use_cluster: false
|
| 24 |
-
tpu_use_sudo: false
|
| 25 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/8gpu_fp16.yaml
DELETED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
distributed_type: MULTI_GPU
|
| 4 |
-
downcast_bf16: 'no'
|
| 5 |
-
enable_cpu_affinity: false
|
| 6 |
-
gpu_ids: all
|
| 7 |
-
machine_rank: 0
|
| 8 |
-
main_training_function: main
|
| 9 |
-
mixed_precision: fp16
|
| 10 |
-
num_machines: 1
|
| 11 |
-
num_processes: 8
|
| 12 |
-
rdzv_backend: static
|
| 13 |
-
same_network: true
|
| 14 |
-
tpu_env: []
|
| 15 |
-
tpu_use_cluster: false
|
| 16 |
-
tpu_use_sudo: false
|
| 17 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/third_party/MuQ/src/recipes/contrastive_learning/config/accelerate/8gpu_fp16_zero2.yaml
DELETED
|
@@ -1,22 +0,0 @@
|
|
| 1 |
-
compute_environment: LOCAL_MACHINE
|
| 2 |
-
debug: false
|
| 3 |
-
deepspeed_config:
|
| 4 |
-
gradient_accumulation_steps: 1
|
| 5 |
-
offload_optimizer_device: none
|
| 6 |
-
offload_param_device: none
|
| 7 |
-
zero3_init_flag: false
|
| 8 |
-
zero_stage: 2
|
| 9 |
-
distributed_type: DEEPSPEED
|
| 10 |
-
downcast_bf16: 'no'
|
| 11 |
-
enable_cpu_affinity: false
|
| 12 |
-
machine_rank: 0
|
| 13 |
-
main_training_function: main
|
| 14 |
-
mixed_precision: fp16
|
| 15 |
-
num_machines: 1
|
| 16 |
-
num_processes: 8
|
| 17 |
-
rdzv_backend: static
|
| 18 |
-
same_network: true
|
| 19 |
-
tpu_env: []
|
| 20 |
-
tpu_use_cluster: false
|
| 21 |
-
tpu_use_sudo: false
|
| 22 |
-
use_cpu: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|