bupalinyu commited on
Commit
6aa989f
·
verified ·
1 Parent(s): 3117dd6

Upload Audio8 TTS Preview 0.6B model files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,174 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ language:
4
+ - yue
5
+ - zh
6
+ - nl
7
+ - en
8
+ - fr
9
+ - de
10
+ - it
11
+ - ja
12
+ - ko
13
+ - pl
14
+ - es
15
+ library_name: transformers
16
+ pipeline_tag: text-to-speech
17
+ tags:
18
+ - audio
19
+ - text-to-speech
20
+ - tts
21
+ - voice-cloning
22
+ - zero-shot
23
+ - multilingual
24
  ---
25
+
26
+ <div align="center">
27
+
28
+ # Audio8 TTS Preview 0.6B
29
+
30
+ **A 0.6B-parameter multilingual text-to-speech model with zero-shot voice cloning.**
31
+
32
+ [![GitHub](https://img.shields.io/badge/GitHub-audio8--tts--0.6B-black?style=for-the-badge&logo=github)](https://github.com/AutoArk/audio8-tts-0.6B)
33
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue?style=for-the-badge)](https://github.com/AutoArk/audio8-tts-0.6B/blob/main/LICENSE)
34
+
35
+ </div>
36
+
37
+ Audio8 TTS Preview supports multilingual speech generation and zero-shot voice
38
+ cloning. This repository contains the complete checkpoint, its 44.1 kHz neural
39
+ audio codec, tokenizer, processor, and Hugging Face remote code.
40
+
41
+ > **Preview status:** Language coverage is intentionally limited in this
42
+ > release. For the best results, use one of the 11 recommended languages below.
43
+ > Broader multilingual coverage and Chinese dialect support are planned for
44
+ > future releases.
45
+
46
+ ## Supported Languages
47
+
48
+ | Language | Name |
49
+ |---|---|
50
+ | Cantonese | 粤语 |
51
+ | Chinese | 中文 |
52
+ | Dutch | 荷兰语 |
53
+ | English | 英语 |
54
+ | French | 法语 |
55
+ | German | 德语 |
56
+ | Italian | 意大利语 |
57
+ | Japanese | 日语 |
58
+ | Korean | 韩语 |
59
+ | Polish | 波兰语 |
60
+ | Spanish | 西班牙语 |
61
+
62
+ ## Model Details
63
+
64
+ Audio8 TTS uses a DualAR architecture inspired by
65
+ [Fish Audio S2 Pro](https://github.com/fishaudio/fish-speech). The slow AR
66
+ transformer predicts one semantic token for each audio frame. The fast AR
67
+ transformer predicts the frame's codec codebooks, conditioned on the slow hidden
68
+ state and preceding codebooks.
69
+
70
+ | Component | Configuration |
71
+ |---|---|
72
+ | Main model | 601,159,424 parameters, excluding the codec |
73
+ | Slow AR | 24 layers, width 896, 14 attention heads, 2 KV heads |
74
+ | Fast AR | 4 layers, width 896, 14 attention heads, 2 KV heads |
75
+ | Acoustic tokens | 10 codebooks, 4,096 entries per codebook |
76
+ | Codec | 44.1 kHz, 2,048 samples per model frame (~21.5 frames/s) |
77
+ | Context | Up to 2,048 packed text/audio positions |
78
+
79
+ The bundled codec handles both reference-audio encoding and waveform decoding,
80
+ so no additional codec checkpoint is required.
81
+
82
+ ## Installation
83
+
84
+ Python 3.10 or newer and a CUDA-capable GPU are recommended.
85
+
86
+ ```bash
87
+ pip install "torch>=2.5.0" "torchaudio>=2.5.0" \
88
+ "transformers>=4.57.0,<5" "soundfile>=0.12" "safetensors>=0.4"
89
+ ```
90
+
91
+ ## Usage
92
+
93
+ The model uses custom Transformers code. Review the files in this repository,
94
+ then load it with `trust_remote_code=True`.
95
+
96
+ ### Zero-shot voice cloning
97
+
98
+ The reference transcript must match the spoken content in the reference audio.
99
+
100
+ ```python
101
+ import soundfile as sf
102
+ import torch
103
+ from transformers import AutoModel, AutoProcessor
104
+
105
+ model_id = "AutoArk-AI/Audio8-TTS-Preview-0.6b"
106
+ device = "cuda" if torch.cuda.is_available() else "cpu"
107
+ dtype = torch.bfloat16 if device == "cuda" else torch.float32
108
+
109
+ processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
110
+ model = AutoModel.from_pretrained(
111
+ model_id,
112
+ trust_remote_code=True,
113
+ dtype=dtype,
114
+ ).eval().to(device)
115
+
116
+ inputs = processor(
117
+ text=["Welcome to Audio8 TTS."],
118
+ reference_audio=["reference.wav"],
119
+ reference_text=["The exact transcript of the reference recording."],
120
+ return_tensors="pt",
121
+ )
122
+ inputs = {name: value.to(device) for name, value in inputs.items()}
123
+
124
+ with torch.inference_mode():
125
+ output = model.generate(
126
+ **inputs,
127
+ max_new_tokens=1024,
128
+ temperature=0.8,
129
+ top_p=0.95,
130
+ top_k=50,
131
+ do_sample=True,
132
+ return_dict_in_generate=True,
133
+ )
134
+ waveforms, waveform_lengths = model.decode_audio(output.codes)
135
+
136
+ audio = waveforms[0, : int(waveform_lengths[0])].float().cpu().numpy()
137
+ sf.write("output.wav", audio, model.config.codec_sample_rate)
138
+ ```
139
+
140
+ ### Generation without a reference
141
+
142
+ Omit `reference_audio` and `reference_text` when a cloned voice is not needed:
143
+
144
+ ```python
145
+ inputs = processor(
146
+ text=["This utterance does not use a reference voice."],
147
+ return_tensors="pt",
148
+ )
149
+ ```
150
+
151
+ For command-line inference, batching, and supervised fine-tuning, see the
152
+ [Audio8 TTS repository](https://github.com/AutoArk/audio8-tts-0.6B).
153
+
154
+ ## Limitations and Responsible Use
155
+
156
+ - This is a Preview checkpoint with limited multilingual and dialect coverage.
157
+ - Very long, noisy, or incorrectly transcribed reference clips can reduce
158
+ stability and speaker similarity.
159
+ - Generated speech can be misused for impersonation or misinformation. Obtain
160
+ consent before cloning a voice and clearly disclose synthetic audio where
161
+ appropriate.
162
+ - Evaluate the model for accuracy, safety, and legal compliance before
163
+ deployment.
164
+
165
+ ## License and Acknowledgements
166
+
167
+ The code and model weights are released under the
168
+ [Apache License 2.0](https://github.com/AutoArk/audio8-tts-0.6B/blob/main/LICENSE).
169
+ See the upstream [NOTICE](https://github.com/AutoArk/audio8-tts-0.6B/blob/main/NOTICE)
170
+ for attribution details.
171
+
172
+ We thank the Fish Audio team for publishing the DualAR architecture used in
173
+ Fish Audio S2 Pro.
174
+
codec.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c310505aa11fe2f6cc63b8d3130dc7e77e73227774f5c62575769b1f47a8d048
3
+ size 1349857559
config.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "ArkttsModel"
4
+ ],
5
+ "attention_o_bias": false,
6
+ "attention_qk_norm": false,
7
+ "attention_qkv_bias": true,
8
+ "auto_map": {
9
+ "AutoConfig": "configuration_arktts.ArkttsConfig",
10
+ "AutoModel": "modeling_arktts.ArkttsModel",
11
+ "AutoModelForCausalLM": "modeling_arktts.ArkttsModel"
12
+ },
13
+ "codebook_size": 4096,
14
+ "codec_filename": "codec.pth",
15
+ "codec_frame_size": 2048,
16
+ "codec_post_intermediate_size": 1216,
17
+ "codec_post_n_head": 16,
18
+ "codec_post_n_layer": 8,
19
+ "codec_post_n_local_heads": 8,
20
+ "codec_sample_rate": 44100,
21
+ "dim": 896,
22
+ "dropout": 0.0,
23
+ "dtype": "bfloat16",
24
+ "eos_token_id": 151645,
25
+ "fast_attention_o_bias": false,
26
+ "fast_attention_qk_norm": false,
27
+ "fast_attention_qkv_bias": false,
28
+ "fast_dim": 896,
29
+ "fast_head_dim": 64,
30
+ "fast_intermediate_size": 4864,
31
+ "fast_n_head": 14,
32
+ "fast_n_local_heads": 2,
33
+ "head_dim": 64,
34
+ "initializer_range": 0.02,
35
+ "intermediate_size": 4864,
36
+ "max_seq_len": 2048,
37
+ "model_type": "arktts",
38
+ "n_fast_layer": 4,
39
+ "n_head": 14,
40
+ "n_layer": 24,
41
+ "n_local_heads": 2,
42
+ "norm_eps": 1e-06,
43
+ "norm_fastlayer_input": true,
44
+ "num_codebooks": 10,
45
+ "pad_token_id": 151643,
46
+ "ras_temperature": 1.0,
47
+ "ras_top_p": 0.9,
48
+ "ras_window_size": 10,
49
+ "rope_base": 1000000,
50
+ "semantic_begin_id": 151678,
51
+ "semantic_end_id": 155773,
52
+ "tie_word_embeddings": true,
53
+ "transformers_version": "4.57.5",
54
+ "use_gradient_checkpointing": false,
55
+ "vocab_size": 155776
56
+ }
configuration_arktts.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ class ArkttsConfig(PretrainedConfig):
7
+ model_type = "arktts"
8
+
9
+ def __init__(
10
+ self,
11
+ vocab_size: int = 155776,
12
+ dim: int = 896,
13
+ n_layer: int = 24,
14
+ n_head: int = 14,
15
+ n_local_heads: int = 2,
16
+ head_dim: int = 64,
17
+ intermediate_size: int = 4864,
18
+ max_seq_len: int = 2048,
19
+ rope_base: float = 1_000_000,
20
+ norm_eps: float = 1e-6,
21
+ dropout: float = 0.0,
22
+ attention_qkv_bias: bool = True,
23
+ attention_qk_norm: bool = False,
24
+ attention_o_bias: bool = False,
25
+ tie_word_embeddings: bool = True,
26
+ codebook_size: int = 4096,
27
+ num_codebooks: int = 10,
28
+ semantic_begin_id: int = 151678,
29
+ semantic_end_id: int = 155773,
30
+ n_fast_layer: int = 4,
31
+ fast_dim: int = 896,
32
+ fast_n_head: int = 14,
33
+ fast_n_local_heads: int = 2,
34
+ fast_head_dim: int = 64,
35
+ fast_intermediate_size: int = 4864,
36
+ fast_attention_qkv_bias: bool = False,
37
+ fast_attention_qk_norm: bool = False,
38
+ fast_attention_o_bias: bool = False,
39
+ norm_fastlayer_input: bool = True,
40
+ initializer_range: float = 0.02,
41
+ use_gradient_checkpointing: bool = False,
42
+ codec_filename: str = "codec.pth",
43
+ codec_sample_rate: int = 44100,
44
+ codec_frame_size: int = 2048,
45
+ codec_post_n_layer: int = 8,
46
+ codec_post_n_head: int = 16,
47
+ codec_post_n_local_heads: int = 8,
48
+ codec_post_intermediate_size: int = 1216,
49
+ ras_window_size: int = 10,
50
+ ras_temperature: float = 1.0,
51
+ ras_top_p: float = 0.9,
52
+ eos_token_id: int = 151645,
53
+ pad_token_id: int = 151643,
54
+ **kwargs,
55
+ ):
56
+ kwargs.pop("model_type", None)
57
+ kwargs.pop("audio_embed_dim", None)
58
+ kwargs.pop("is_reward_model", None)
59
+ super().__init__(
60
+ eos_token_id=eos_token_id,
61
+ pad_token_id=pad_token_id,
62
+ tie_word_embeddings=tie_word_embeddings,
63
+ **kwargs,
64
+ )
65
+ self.vocab_size = int(vocab_size)
66
+ self.dim = int(dim)
67
+ self.hidden_size = self.dim
68
+ self.n_layer = int(n_layer)
69
+ self.num_hidden_layers = self.n_layer
70
+ self.n_head = int(n_head)
71
+ self.num_attention_heads = self.n_head
72
+ self.n_local_heads = int(n_local_heads)
73
+ self.num_key_value_heads = self.n_local_heads
74
+ self.head_dim = int(head_dim)
75
+ self.intermediate_size = int(intermediate_size)
76
+ self.max_seq_len = int(max_seq_len)
77
+ self.max_position_embeddings = self.max_seq_len
78
+ self.rope_base = float(rope_base)
79
+ self.rope_theta = self.rope_base
80
+ self.norm_eps = float(norm_eps)
81
+ self.rms_norm_eps = self.norm_eps
82
+ self.dropout = float(dropout)
83
+ self.attention_qkv_bias = bool(attention_qkv_bias)
84
+ self.attention_qk_norm = bool(attention_qk_norm)
85
+ self.attention_o_bias = bool(attention_o_bias)
86
+ self.codebook_size = int(codebook_size)
87
+ self.num_codebooks = int(num_codebooks)
88
+ self.semantic_begin_id = int(semantic_begin_id)
89
+ self.semantic_end_id = int(semantic_end_id)
90
+ self.n_fast_layer = int(n_fast_layer)
91
+ self.fast_dim = int(fast_dim)
92
+ self.fast_n_head = int(fast_n_head)
93
+ self.fast_n_local_heads = int(fast_n_local_heads)
94
+ self.fast_head_dim = int(fast_head_dim)
95
+ self.fast_intermediate_size = int(fast_intermediate_size)
96
+ self.fast_attention_qkv_bias = bool(fast_attention_qkv_bias)
97
+ self.fast_attention_qk_norm = bool(fast_attention_qk_norm)
98
+ self.fast_attention_o_bias = bool(fast_attention_o_bias)
99
+ self.norm_fastlayer_input = bool(norm_fastlayer_input)
100
+ self.initializer_range = float(initializer_range)
101
+ self.use_gradient_checkpointing = bool(use_gradient_checkpointing)
102
+ self.codec_filename = str(codec_filename)
103
+ self.codec_sample_rate = int(codec_sample_rate)
104
+ self.codec_frame_size = int(codec_frame_size)
105
+ self.codec_post_n_layer = int(codec_post_n_layer)
106
+ self.codec_post_n_head = int(codec_post_n_head)
107
+ self.codec_post_n_local_heads = int(codec_post_n_local_heads)
108
+ self.codec_post_intermediate_size = int(codec_post_intermediate_size)
109
+ self.ras_window_size = int(ras_window_size)
110
+ self.ras_temperature = float(ras_temperature)
111
+ self.ras_top_p = float(ras_top_p)
112
+
113
+
114
+ __all__ = ["ArkttsConfig"]
generation_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_sample": true,
3
+ "eos_token_id": 151645,
4
+ "max_new_tokens": 512,
5
+ "pad_token_id": 151643,
6
+ "temperature": 0.7,
7
+ "top_k": 50,
8
+ "top_p": 0.9,
9
+ "transformers_version": "4.57.5"
10
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:62dcff0adf6c2535b3260467a7c1d482b556da57266c96a444518b76e140d2c3
3
+ size 1202342528
modeling_arktts.py ADDED
@@ -0,0 +1,831 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import shutil
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch import Tensor
13
+ from torch.nn.attention import SDPBackend, sdpa_kernel
14
+ from transformers import GenerationConfig, PreTrainedModel
15
+ from transformers.generation import (
16
+ LogitsProcessor,
17
+ LogitsProcessorList,
18
+ StoppingCriteriaList,
19
+ )
20
+ from transformers.modeling_outputs import ModelOutput
21
+ from transformers.utils.hub import cached_file
22
+
23
+ from .configuration_arktts import ArkttsConfig
24
+
25
+
26
+ @dataclass
27
+ class ArkttsModelOutput(ModelOutput):
28
+ logits: Optional[Tensor] = None
29
+ hidden_states: Optional[Tensor] = None
30
+ codebook_logits: Optional[Tensor] = None
31
+
32
+
33
+ @dataclass
34
+ class ArkttsGenerateOutput(ModelOutput):
35
+ codes: Optional[Tensor] = None
36
+ code_lengths: Optional[Tensor] = None
37
+ finished: Optional[Tensor] = None
38
+
39
+
40
+ class ArkttsSemanticLogitsProcessor(LogitsProcessor):
41
+ def __init__(self, semantic_begin_id: int, semantic_end_id: int, eos_token_id: int):
42
+ self.semantic_begin_id = int(semantic_begin_id)
43
+ self.semantic_end_id = int(semantic_end_id)
44
+ self.eos_token_id = int(eos_token_id)
45
+
46
+ def __call__(self, input_ids: Tensor, scores: Tensor) -> Tensor:
47
+ filtered = torch.full_like(scores, float("-inf"))
48
+ filtered[:, self.semantic_begin_id : self.semantic_end_id + 1] = scores[
49
+ :, self.semantic_begin_id : self.semantic_end_id + 1
50
+ ]
51
+ filtered[:, self.eos_token_id] = scores[:, self.eos_token_id]
52
+ return filtered
53
+
54
+
55
+ class ArkttsLegacyTopKTopPLogitsProcessor(LogitsProcessor):
56
+ """Matches the candidate filtering order used by the original inference code."""
57
+
58
+ def __init__(self, top_k: int, top_p: float):
59
+ if top_k <= 0:
60
+ raise ValueError("top_k must be positive")
61
+ if not 0.0 < top_p <= 1.0:
62
+ raise ValueError("top_p must be in (0, 1]")
63
+ self.top_k = int(top_k)
64
+ self.top_p = float(top_p)
65
+
66
+ def __call__(self, input_ids: Tensor, scores: Tensor) -> Tensor:
67
+ sorted_scores, sorted_indices = torch.sort(scores, descending=True, dim=-1)
68
+ cumulative = torch.cumsum(torch.softmax(sorted_scores, dim=-1), dim=-1)
69
+ positions = torch.arange(sorted_scores.shape[-1], device=scores.device)
70
+ threshold = torch.tensor(self.top_p, dtype=cumulative.dtype, device=cumulative.device)
71
+ remove_sorted = (cumulative > threshold) | (positions >= self.top_k)
72
+ remove_sorted[..., 0] = False
73
+ remove = torch.zeros_like(remove_sorted).scatter(1, sorted_indices, remove_sorted)
74
+ return scores.masked_fill(remove, float("-inf"))
75
+
76
+
77
+ class ArkttsKVCache(nn.Module):
78
+ def __init__(
79
+ self,
80
+ batch_size: int,
81
+ max_length: int,
82
+ heads: int,
83
+ head_dim: int,
84
+ dtype,
85
+ return_full: bool = False,
86
+ ):
87
+ super().__init__()
88
+ shape = (batch_size, heads, max_length, head_dim)
89
+ self.register_buffer("keys", torch.zeros(shape, dtype=dtype), persistent=False)
90
+ self.register_buffer("values", torch.zeros(shape, dtype=dtype), persistent=False)
91
+ self.return_full = bool(return_full)
92
+
93
+ def update(self, cache_position: Tensor, keys: Tensor, values: Tensor):
94
+ self.keys[:, :, cache_position] = keys
95
+ self.values[:, :, cache_position] = values
96
+ end = self.keys.shape[2] if self.return_full else int(cache_position[-1].item()) + 1
97
+ return self.keys[:, :, :end], self.values[:, :, :end]
98
+
99
+
100
+ class ArkttsRMSNorm(nn.Module):
101
+ def __init__(self, dim: int, eps: float):
102
+ super().__init__()
103
+ self.eps = float(eps)
104
+ self.weight = nn.Parameter(torch.ones(dim))
105
+
106
+ def forward(self, x: Tensor) -> Tensor:
107
+ normalized = x.float() * torch.rsqrt(x.float().pow(2).mean(-1, keepdim=True) + self.eps)
108
+ return normalized.to(x.dtype) * self.weight
109
+
110
+
111
+ def _precompute_rope(length: int, head_dim: int, base: float) -> Tensor:
112
+ frequencies = 1.0 / (
113
+ base ** (torch.arange(0, head_dim, 2).float()[: head_dim // 2] / head_dim)
114
+ )
115
+ phases = torch.outer(torch.arange(length), frequencies)
116
+ values = torch.polar(torch.ones_like(phases), phases)
117
+ return torch.stack((values.real, values.imag), dim=-1).to(torch.bfloat16)
118
+
119
+
120
+ def _apply_rope(x: Tensor, rope: Tensor) -> Tensor:
121
+ shaped = x.float().reshape(*x.shape[:-1], -1, 2)
122
+ if rope.ndim == 3:
123
+ rope = rope[None, :, None]
124
+ elif rope.ndim == 4:
125
+ rope = rope[:, :, None]
126
+ else:
127
+ raise ValueError(f"Unexpected RoPE shape: {tuple(rope.shape)}")
128
+ output = torch.stack(
129
+ (
130
+ shaped[..., 0] * rope[..., 0] - shaped[..., 1] * rope[..., 1],
131
+ shaped[..., 1] * rope[..., 0] + shaped[..., 0] * rope[..., 1],
132
+ ),
133
+ dim=-1,
134
+ )
135
+ return output.flatten(3).to(x.dtype)
136
+
137
+
138
+ class ArkttsAttention(nn.Module):
139
+ def __init__(
140
+ self,
141
+ dim: int,
142
+ n_head: int,
143
+ n_local_heads: int,
144
+ head_dim: int,
145
+ qkv_bias: bool,
146
+ output_bias: bool,
147
+ qk_norm: bool,
148
+ norm_eps: float,
149
+ dropout: float,
150
+ use_sdpa: bool,
151
+ ):
152
+ super().__init__()
153
+ total = (n_head + 2 * n_local_heads) * head_dim
154
+ self.wqkv = nn.Linear(dim, total, bias=qkv_bias)
155
+ self.wo = nn.Linear(n_head * head_dim, dim, bias=output_bias)
156
+ self.n_head = int(n_head)
157
+ self.n_local_heads = int(n_local_heads)
158
+ self.head_dim = int(head_dim)
159
+ self.dropout = float(dropout)
160
+ self.use_sdpa = bool(use_sdpa)
161
+ self.qk_norm = bool(qk_norm)
162
+ if self.qk_norm:
163
+ self.q_norm = ArkttsRMSNorm(head_dim, norm_eps)
164
+ self.k_norm = ArkttsRMSNorm(head_dim, norm_eps)
165
+ self.kv_cache: Optional[ArkttsKVCache] = None
166
+
167
+ def forward(
168
+ self,
169
+ x: Tensor,
170
+ rope: Tensor,
171
+ attention_mask: Optional[Tensor],
172
+ cache_position: Optional[Tensor] = None,
173
+ ) -> Tensor:
174
+ batch, length, _ = x.shape
175
+ query_size = self.n_head * self.head_dim
176
+ kv_size = self.n_local_heads * self.head_dim
177
+ query, key, value = self.wqkv(x).split((query_size, kv_size, kv_size), dim=-1)
178
+ query = query.view(batch, length, self.n_head, self.head_dim)
179
+ key = key.view(batch, length, self.n_local_heads, self.head_dim)
180
+ value = value.view(batch, length, self.n_local_heads, self.head_dim)
181
+ if self.qk_norm:
182
+ query = self.q_norm(query)
183
+ key = self.k_norm(key)
184
+ query = _apply_rope(query, rope).transpose(1, 2)
185
+ key = _apply_rope(key, rope).transpose(1, 2)
186
+ value = value.transpose(1, 2)
187
+ if self.kv_cache is not None:
188
+ if cache_position is None:
189
+ raise ValueError("cache_position is required when KV cache is enabled")
190
+ key, value = self.kv_cache.update(cache_position, key, value)
191
+ repeats = self.n_head // self.n_local_heads
192
+ key = key.repeat_interleave(repeats, dim=1)
193
+ value = value.repeat_interleave(repeats, dim=1)
194
+ if self.use_sdpa:
195
+ output = F.scaled_dot_product_attention(
196
+ query,
197
+ key,
198
+ value,
199
+ attn_mask=attention_mask,
200
+ dropout_p=self.dropout if self.training else 0.0,
201
+ )
202
+ else:
203
+ scores = query @ key.transpose(-2, -1) / math.sqrt(self.head_dim)
204
+ if attention_mask is not None:
205
+ scores = scores.masked_fill(~attention_mask, float("-inf"))
206
+ probabilities = torch.softmax(scores, dim=-1)
207
+ if self.training and self.dropout:
208
+ probabilities = F.dropout(probabilities, p=self.dropout)
209
+ output = probabilities @ value
210
+ output = output.transpose(1, 2).contiguous().view(batch, length, query_size)
211
+ return self.wo(output)
212
+
213
+
214
+ class ArkttsFeedForward(nn.Module):
215
+ def __init__(self, dim: int, intermediate_size: int):
216
+ super().__init__()
217
+ self.w1 = nn.Linear(dim, intermediate_size, bias=False)
218
+ self.w2 = nn.Linear(intermediate_size, dim, bias=False)
219
+ self.w3 = nn.Linear(dim, intermediate_size, bias=False)
220
+
221
+ def forward(self, x: Tensor) -> Tensor:
222
+ return self.w2(F.silu(self.w1(x)) * self.w3(x))
223
+
224
+
225
+ class ArkttsTransformerBlock(nn.Module):
226
+ def __init__(
227
+ self,
228
+ dim: int,
229
+ intermediate_size: int,
230
+ n_head: int,
231
+ n_local_heads: int,
232
+ head_dim: int,
233
+ qkv_bias: bool,
234
+ output_bias: bool,
235
+ qk_norm: bool,
236
+ norm_eps: float,
237
+ dropout: float,
238
+ use_sdpa: bool,
239
+ ):
240
+ super().__init__()
241
+ self.attention = ArkttsAttention(
242
+ dim, n_head, n_local_heads, head_dim, qkv_bias, output_bias,
243
+ qk_norm, norm_eps, dropout, use_sdpa,
244
+ )
245
+ self.feed_forward = ArkttsFeedForward(dim, intermediate_size)
246
+ self.ffn_norm = ArkttsRMSNorm(dim, norm_eps)
247
+ self.attention_norm = ArkttsRMSNorm(dim, norm_eps)
248
+
249
+ def forward(self, x, rope, attention_mask, cache_position=None):
250
+ hidden = x + self.attention(self.attention_norm(x), rope, attention_mask, cache_position)
251
+ return hidden + self.feed_forward(self.ffn_norm(hidden))
252
+
253
+
254
+ class ArkttsModel(PreTrainedModel):
255
+ config_class = ArkttsConfig
256
+ base_model_prefix = ""
257
+ main_input_name = "input_ids"
258
+ _no_split_modules = ["ArkttsTransformerBlock"]
259
+ _supports_sdpa = True
260
+
261
+ def __init__(self, config: ArkttsConfig):
262
+ super().__init__(config)
263
+ self.embeddings = nn.Embedding(config.vocab_size, config.dim)
264
+ self.codebook_embeddings = nn.Embedding(config.codebook_size * config.num_codebooks, config.dim)
265
+ self.layers = nn.ModuleList([
266
+ ArkttsTransformerBlock(
267
+ config.dim, config.intermediate_size, config.n_head, config.n_local_heads,
268
+ config.head_dim, config.attention_qkv_bias, config.attention_o_bias,
269
+ config.attention_qk_norm, config.norm_eps, config.dropout, True,
270
+ )
271
+ for _ in range(config.n_layer)
272
+ ])
273
+ self.norm = ArkttsRMSNorm(config.dim, config.norm_eps)
274
+ self.fast_project_in = (
275
+ nn.Linear(config.dim, config.fast_dim)
276
+ if config.fast_dim != config.dim else nn.Identity()
277
+ )
278
+ self.fast_embeddings = nn.Embedding(config.codebook_size, config.fast_dim)
279
+ self.fast_layers = nn.ModuleList([
280
+ ArkttsTransformerBlock(
281
+ config.fast_dim, config.fast_intermediate_size, config.fast_n_head,
282
+ config.fast_n_local_heads, config.fast_head_dim,
283
+ config.fast_attention_qkv_bias, config.fast_attention_o_bias,
284
+ config.fast_attention_qk_norm, config.norm_eps, config.dropout, False,
285
+ )
286
+ for _ in range(config.n_fast_layer)
287
+ ])
288
+ self.fast_norm = ArkttsRMSNorm(config.fast_dim, config.norm_eps)
289
+ self.fast_output = nn.Linear(config.fast_dim, config.codebook_size, bias=False)
290
+ self.register_buffer(
291
+ "freqs_cis", _precompute_rope(config.max_seq_len, config.head_dim, config.rope_base),
292
+ persistent=False,
293
+ )
294
+ self.register_buffer(
295
+ "fast_freqs_cis",
296
+ _precompute_rope(config.num_codebooks, config.fast_head_dim, config.rope_base),
297
+ persistent=False,
298
+ )
299
+ self.__dict__["_arktts_codec"] = None
300
+ self.post_init()
301
+
302
+ def _init_weights(self, module):
303
+ if isinstance(module, (nn.Linear, nn.Embedding)):
304
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
305
+ if isinstance(module, nn.Linear) and module.bias is not None:
306
+ module.bias.data.zero_()
307
+
308
+ def get_input_embeddings(self):
309
+ return self.embeddings
310
+
311
+ def set_input_embeddings(self, value):
312
+ self.embeddings = value
313
+
314
+ def get_output_embeddings(self):
315
+ return None
316
+
317
+ def _embed(self, input_ids: Tensor) -> Tensor:
318
+ codebook_embeds = []
319
+ for index in range(self.config.num_codebooks):
320
+ codebook_embeds.append(
321
+ self.codebook_embeddings(input_ids[:, index + 1] + index * self.config.codebook_size)
322
+ )
323
+ codebook_sum = torch.stack(codebook_embeds, dim=1).sum(dim=1)
324
+ semantic = (input_ids[:, 0] >= self.config.semantic_begin_id) & (
325
+ input_ids[:, 0] <= self.config.semantic_end_id
326
+ )
327
+ codebook_sum = torch.where(semantic.unsqueeze(-1), codebook_sum, 0.0)
328
+ return self.embeddings(input_ids[:, 0]) + codebook_sum
329
+
330
+ @staticmethod
331
+ def _causal_mask(attention_mask: Tensor, query_positions: Tensor, key_length: int) -> Tensor:
332
+ if attention_mask.shape[1] < key_length:
333
+ attention_mask = F.pad(
334
+ attention_mask,
335
+ (0, key_length - attention_mask.shape[1]),
336
+ value=0,
337
+ )
338
+ key_positions = torch.arange(key_length, device=attention_mask.device)
339
+ causal = key_positions[None, :] <= query_positions[:, None]
340
+ return causal[None, None] & attention_mask[:, None, None, :key_length].bool()
341
+
342
+ def forward(
343
+ self,
344
+ input_ids: Tensor,
345
+ attention_mask: Optional[Tensor] = None,
346
+ labels: Optional[Tensor] = None,
347
+ output_hidden_states: Optional[bool] = None,
348
+ return_dict: Optional[bool] = None,
349
+ **kwargs,
350
+ ):
351
+ del labels, output_hidden_states, kwargs
352
+ if input_ids.ndim != 3 or input_ids.shape[1] != self.config.num_codebooks + 1:
353
+ raise ValueError(
354
+ f"input_ids must have shape [B, {self.config.num_codebooks + 1}, T]"
355
+ )
356
+ batch, _, length = input_ids.shape
357
+ if attention_mask is None:
358
+ attention_mask = torch.ones((batch, length), dtype=torch.long, device=input_ids.device)
359
+ position_ids = attention_mask.long().cumsum(-1).sub(1).clamp_min(0)
360
+ rope = self.freqs_cis[position_ids]
361
+ mask = self._causal_mask(
362
+ attention_mask,
363
+ torch.arange(length, device=input_ids.device),
364
+ length,
365
+ )
366
+ hidden = self._embed(input_ids)
367
+ for layer in self.layers:
368
+ hidden = layer(hidden, rope, mask)
369
+ normalized = self.norm(hidden)
370
+ logits = F.linear(normalized, self.embeddings.weight)
371
+ output = ArkttsModelOutput(logits=logits, hidden_states=hidden)
372
+ if return_dict is False:
373
+ return (logits, hidden)
374
+ return output
375
+
376
+ def _setup_generation_caches(self, batch_size: int, max_length: int, dtype):
377
+ del max_length
378
+ for layer in self.layers:
379
+ layer.attention.kv_cache = ArkttsKVCache(
380
+ batch_size,
381
+ self.config.max_seq_len,
382
+ self.config.n_local_heads,
383
+ self.config.head_dim,
384
+ dtype,
385
+ return_full=True,
386
+ ).to(self.device)
387
+ for layer in self.fast_layers:
388
+ layer.attention.kv_cache = ArkttsKVCache(
389
+ batch_size, self.config.num_codebooks, self.config.fast_n_local_heads,
390
+ self.config.fast_head_dim, dtype, return_full=True,
391
+ ).to(self.device)
392
+
393
+ def _slow_step(
394
+ self,
395
+ input_ids: Tensor,
396
+ cache_position: Tensor,
397
+ position_ids: Tensor,
398
+ attention_mask: Tensor,
399
+ ) -> tuple[Tensor, Tensor]:
400
+ hidden = self._embed(input_ids)
401
+ rope = self.freqs_cis[position_ids]
402
+ mask = self._causal_mask(
403
+ attention_mask,
404
+ cache_position,
405
+ self.config.max_seq_len,
406
+ )
407
+ for layer in self.layers:
408
+ hidden = layer(hidden, rope, mask, cache_position)
409
+ hidden = hidden[:, -1:]
410
+ normalized = self.norm(hidden)
411
+ logits = F.linear(normalized, self.embeddings.weight)[:, -1]
412
+ fast_hidden = normalized if self.config.norm_fastlayer_input else hidden
413
+ return logits, fast_hidden
414
+
415
+ def _fast_step(self, hidden: Tensor, position: int) -> Tensor:
416
+ cache_position = torch.tensor([position], device=hidden.device, dtype=torch.long)
417
+ rope = self.fast_freqs_cis[cache_position]
418
+ key_mask = torch.ones(
419
+ (hidden.shape[0], self.config.num_codebooks),
420
+ device=hidden.device,
421
+ dtype=torch.bool,
422
+ )
423
+ mask = self._causal_mask(key_mask, cache_position, self.config.num_codebooks)
424
+ for layer in self.fast_layers:
425
+ hidden = layer(hidden, rope, mask, cache_position)
426
+ return self.fast_output(self.fast_norm(hidden))[:, -1]
427
+
428
+ @staticmethod
429
+ def _as_processor_list(value) -> LogitsProcessorList:
430
+ if value is None:
431
+ return LogitsProcessorList()
432
+ if isinstance(value, LogitsProcessorList):
433
+ return value
434
+ return LogitsProcessorList(value)
435
+
436
+ @staticmethod
437
+ def _sample(scores: Tensor, generator=None) -> Tensor:
438
+ probabilities = torch.softmax(scores, dim=-1)
439
+ random = torch.rand(
440
+ probabilities.shape,
441
+ dtype=probabilities.dtype,
442
+ device=probabilities.device,
443
+ generator=generator,
444
+ )
445
+ noise = -torch.log(random)
446
+ return torch.argmax(probabilities / noise, dim=-1)
447
+
448
+ def _processed_scores(
449
+ self,
450
+ input_ids: Tensor,
451
+ scores: Tensor,
452
+ processors: LogitsProcessorList,
453
+ top_k: int,
454
+ top_p: float,
455
+ temperature: float,
456
+ ) -> Tensor:
457
+ scores = processors(input_ids, scores)
458
+ scores = ArkttsLegacyTopKTopPLogitsProcessor(top_k, top_p)(input_ids, scores)
459
+ temperature_value = torch.tensor(
460
+ temperature, dtype=scores.dtype, device=scores.device
461
+ ).clamp_min(1e-5)
462
+ return scores / temperature_value
463
+
464
+ def _sample_semantic(
465
+ self,
466
+ history: Tensor,
467
+ logits: Tensor,
468
+ custom_processors: LogitsProcessorList,
469
+ top_k: int,
470
+ top_p: float,
471
+ temperature: float,
472
+ previous: Optional[Tensor],
473
+ do_sample: bool,
474
+ generator=None,
475
+ ) -> Tensor:
476
+ processors = LogitsProcessorList([
477
+ ArkttsSemanticLogitsProcessor(
478
+ self.config.semantic_begin_id,
479
+ self.config.semantic_end_id,
480
+ self.config.eos_token_id,
481
+ ),
482
+ *custom_processors,
483
+ ])
484
+ regular_scores = self._processed_scores(
485
+ history, logits, processors, top_k, top_p, temperature
486
+ )
487
+ if not do_sample:
488
+ return regular_scores.argmax(dim=-1)
489
+ normal = self._sample(regular_scores, generator=generator)
490
+ high_scores = self._processed_scores(
491
+ history,
492
+ logits,
493
+ processors,
494
+ top_k,
495
+ self.config.ras_top_p,
496
+ self.config.ras_temperature,
497
+ )
498
+ high = self._sample(high_scores, generator=generator)
499
+ if previous is None:
500
+ return normal
501
+ repeated = (previous == normal[:, None]).any(dim=1)
502
+ semantic = (normal >= self.config.semantic_begin_id) & (
503
+ normal <= self.config.semantic_end_id
504
+ )
505
+ return torch.where(repeated & semantic, high, normal)
506
+
507
+ def _generate_codebooks(
508
+ self,
509
+ slow_hidden: Tensor,
510
+ semantic: Tensor,
511
+ processors: LogitsProcessorList,
512
+ top_k: int,
513
+ top_p: float,
514
+ temperature: float,
515
+ do_sample: bool,
516
+ generator=None,
517
+ ) -> Tensor:
518
+ hidden = self.fast_project_in(slow_hidden)
519
+ self._fast_step(hidden, 0)
520
+ current = (semantic - self.config.semantic_begin_id).clamp(0, self.config.codebook_size - 1)
521
+ codebooks = [current]
522
+ fast_history = current[:, None]
523
+ hidden = self.fast_embeddings(current)[:, None]
524
+ for position in range(1, self.config.num_codebooks):
525
+ scores = self._fast_step(hidden, position)
526
+ scores = self._processed_scores(
527
+ fast_history, scores, processors, top_k, top_p, temperature
528
+ )
529
+ current = self._sample(scores, generator=generator) if do_sample else scores.argmax(dim=-1)
530
+ codebooks.append(current)
531
+ fast_history = torch.cat((fast_history, current[:, None]), dim=1)
532
+ hidden = self.fast_embeddings(current)[:, None]
533
+ return torch.stack(codebooks, dim=1)
534
+
535
+ def _prepare_prompt(
536
+ self,
537
+ input_ids=None,
538
+ attention_mask=None,
539
+ prefix_input_ids=None,
540
+ prefix_attention_mask=None,
541
+ suffix_input_ids=None,
542
+ suffix_attention_mask=None,
543
+ reference_codes=None,
544
+ reference_code_lengths=None,
545
+ reference_audio_values=None,
546
+ reference_audio_lengths=None,
547
+ ):
548
+ if input_ids is not None:
549
+ if input_ids.ndim != 3 or input_ids.shape[1] != self.config.num_codebooks + 1:
550
+ raise ValueError("Direct input_ids must have shape [B, num_codebooks + 1, T]")
551
+ if attention_mask is None:
552
+ attention_mask = torch.ones(
553
+ input_ids.shape[0], input_ids.shape[-1], dtype=torch.long, device=input_ids.device
554
+ )
555
+ return input_ids.to(self.device), attention_mask.to(self.device)
556
+ if prefix_input_ids is None or suffix_input_ids is None:
557
+ raise ValueError("Processor output or direct input_ids is required")
558
+ prefix_input_ids = prefix_input_ids.to(self.device)
559
+ suffix_input_ids = suffix_input_ids.to(self.device)
560
+ prefix_attention_mask = prefix_attention_mask.to(self.device)
561
+ suffix_attention_mask = suffix_attention_mask.to(self.device)
562
+ if reference_audio_values is not None:
563
+ if reference_codes is not None:
564
+ raise ValueError("Provide reference audio or reference codes, not both")
565
+ reference_codes, reference_code_lengths = self.encode_audio(
566
+ reference_audio_values.to(self.device), reference_audio_lengths.to(self.device)
567
+ )
568
+ if reference_codes is not None:
569
+ reference_codes = reference_codes.to(self.device)
570
+ reference_code_lengths = reference_code_lengths.to(self.device)
571
+ batch_size = prefix_input_ids.shape[0]
572
+ rows = []
573
+ for batch_index in range(batch_size):
574
+ prefix = prefix_input_ids[batch_index, prefix_attention_mask[batch_index].bool()]
575
+ suffix = suffix_input_ids[batch_index, suffix_attention_mask[batch_index].bool()]
576
+ if reference_codes is None:
577
+ semantic_row = torch.cat((prefix, suffix))
578
+ values = torch.zeros(
579
+ (self.config.num_codebooks + 1, semantic_row.numel()),
580
+ dtype=torch.long,
581
+ device=self.device,
582
+ )
583
+ values[0] = semantic_row
584
+ else:
585
+ length = int(reference_code_lengths[batch_index])
586
+ codes = reference_codes[batch_index, :, :length].long()
587
+ semantic_codes = codes[0] + self.config.semantic_begin_id
588
+ semantic_row = torch.cat((prefix, semantic_codes, suffix))
589
+ values = torch.zeros(
590
+ (self.config.num_codebooks + 1, semantic_row.numel()),
591
+ dtype=torch.long,
592
+ device=self.device,
593
+ )
594
+ values[0] = semantic_row
595
+ values[1:, prefix.numel() : prefix.numel() + length] = codes
596
+ rows.append(values)
597
+ max_length = max(row.shape[1] for row in rows)
598
+ prompt = torch.zeros(
599
+ (batch_size, self.config.num_codebooks + 1, max_length),
600
+ dtype=torch.long,
601
+ device=self.device,
602
+ )
603
+ prompt[:, 0] = self.config.pad_token_id
604
+ prompt_mask = torch.zeros((batch_size, max_length), dtype=torch.long, device=self.device)
605
+ for batch_index, row in enumerate(rows):
606
+ start = max_length - row.shape[1]
607
+ prompt[batch_index, :, start:] = row
608
+ prompt_mask[batch_index, start:] = 1
609
+ return prompt, prompt_mask
610
+
611
+ @torch.inference_mode()
612
+ def generate(
613
+ self,
614
+ input_ids: Optional[Tensor] = None,
615
+ attention_mask: Optional[Tensor] = None,
616
+ prefix_input_ids: Optional[Tensor] = None,
617
+ prefix_attention_mask: Optional[Tensor] = None,
618
+ suffix_input_ids: Optional[Tensor] = None,
619
+ suffix_attention_mask: Optional[Tensor] = None,
620
+ reference_codes: Optional[Tensor] = None,
621
+ reference_code_lengths: Optional[Tensor] = None,
622
+ reference_audio_values: Optional[Tensor] = None,
623
+ reference_audio_lengths: Optional[Tensor] = None,
624
+ generation_config: Optional[GenerationConfig] = None,
625
+ logits_processor=None,
626
+ codebook_logits_processor=None,
627
+ stopping_criteria=None,
628
+ max_new_tokens: Optional[int] = None,
629
+ temperature: Optional[float] = None,
630
+ top_p: Optional[float] = None,
631
+ top_k: Optional[int] = None,
632
+ do_sample: Optional[bool] = None,
633
+ return_dict_in_generate: bool = False,
634
+ generator=None,
635
+ **kwargs,
636
+ ):
637
+ if kwargs:
638
+ raise TypeError(f"Unexpected generation arguments: {sorted(kwargs)}")
639
+ config = generation_config or getattr(self, "generation_config", GenerationConfig())
640
+ config_max_new = getattr(config, "max_new_tokens", None)
641
+ config_temperature = getattr(config, "temperature", None)
642
+ config_top_p = getattr(config, "top_p", None)
643
+ config_top_k = getattr(config, "top_k", None)
644
+ max_new_tokens = int(max_new_tokens if max_new_tokens is not None else (config_max_new or 512))
645
+ temperature = float(temperature if temperature is not None else (config_temperature or 0.7))
646
+ top_p = float(top_p if top_p is not None else (config_top_p or 0.9))
647
+ top_k = int(top_k if top_k is not None else (config_top_k or 50))
648
+ do_sample = bool(do_sample if do_sample is not None else getattr(config, "do_sample", True))
649
+ if max_new_tokens <= 0:
650
+ raise ValueError("max_new_tokens must be positive")
651
+ if temperature <= 0:
652
+ raise ValueError("temperature must be positive")
653
+ prompt, prompt_mask = self._prepare_prompt(
654
+ input_ids, attention_mask, prefix_input_ids, prefix_attention_mask,
655
+ suffix_input_ids, suffix_attention_mask, reference_codes,
656
+ reference_code_lengths, reference_audio_values, reference_audio_lengths,
657
+ )
658
+ batch_size, _, prompt_width = prompt.shape
659
+ if prompt_width >= self.config.max_seq_len:
660
+ raise ValueError(
661
+ f"Prompt length {prompt_width} must be smaller than {self.config.max_seq_len}"
662
+ )
663
+ max_new_tokens = min(max_new_tokens, self.config.max_seq_len - prompt_width)
664
+ self._setup_generation_caches(
665
+ batch_size, prompt_width + max_new_tokens, next(self.parameters()).dtype
666
+ )
667
+ semantic_processors = self._as_processor_list(logits_processor)
668
+ codebook_processors = self._as_processor_list(codebook_logits_processor)
669
+ criteria = stopping_criteria or StoppingCriteriaList()
670
+ if not isinstance(criteria, StoppingCriteriaList):
671
+ criteria = StoppingCriteriaList(criteria)
672
+ cache_position = torch.arange(prompt_width, device=self.device, dtype=torch.long)
673
+ position_ids = prompt_mask.cumsum(-1).sub(1).clamp_min(0)
674
+ logits, slow_hidden = self._slow_step(
675
+ prompt, cache_position, position_ids, prompt_mask
676
+ )
677
+ semantic_history = prompt[:, 0]
678
+ prompt_lengths = prompt_mask.sum(-1)
679
+ previous = None
680
+ finished = torch.zeros(batch_size, dtype=torch.bool, device=self.device)
681
+ code_lengths = torch.zeros(batch_size, dtype=torch.long, device=self.device)
682
+ generated_frames = []
683
+
684
+ for step in range(max_new_tokens):
685
+ active_before = ~finished
686
+ semantic = self._sample_semantic(
687
+ semantic_history, logits, semantic_processors, top_k, top_p,
688
+ temperature, previous, do_sample, generator,
689
+ )
690
+ codebooks = self._generate_codebooks(
691
+ slow_hidden, semantic, codebook_processors, top_k, top_p,
692
+ temperature, do_sample, generator,
693
+ )
694
+ emitted = active_before & (semantic != self.config.eos_token_id)
695
+ frame = torch.where(emitted[:, None], codebooks, -1)
696
+ generated_frames.append(frame)
697
+ code_lengths += emitted.long()
698
+ semantic_history = torch.cat((semantic_history, semantic[:, None]), dim=1)
699
+
700
+ if previous is None:
701
+ previous = torch.zeros(
702
+ (batch_size, self.config.ras_window_size),
703
+ dtype=torch.long,
704
+ device=self.device,
705
+ )
706
+ else:
707
+ previous = previous.roll(-1, dims=1)
708
+ previous[:, -1] = semantic
709
+ finished |= semantic.eq(self.config.eos_token_id)
710
+ if criteria:
711
+ stopped = criteria(semantic_history, logits)
712
+ if not isinstance(stopped, Tensor):
713
+ stopped = torch.full_like(finished, bool(stopped))
714
+ finished |= stopped.to(device=self.device, dtype=torch.bool)
715
+ if finished.all():
716
+ break
717
+
718
+ next_column = torch.cat((semantic[:, None], codebooks), dim=1).unsqueeze(-1)
719
+ new_valid = active_before.long()[:, None]
720
+ prompt_mask = torch.cat((prompt_mask, new_valid), dim=1)
721
+ physical_position = torch.tensor([prompt_width + step], device=self.device)
722
+ token_position = (prompt_lengths + step)[:, None]
723
+ with sdpa_kernel(SDPBackend.MATH):
724
+ logits, slow_hidden = self._slow_step(
725
+ next_column, physical_position, token_position, prompt_mask
726
+ )
727
+
728
+ if generated_frames:
729
+ codes = torch.stack(generated_frames, dim=2)
730
+ max_valid = int(code_lengths.max().item()) if code_lengths.numel() else 0
731
+ codes = codes[:, :, :max_valid]
732
+ else:
733
+ codes = torch.empty(
734
+ (batch_size, self.config.num_codebooks, 0), dtype=torch.long, device=self.device
735
+ )
736
+ result = ArkttsGenerateOutput(codes=codes, code_lengths=code_lengths, finished=finished)
737
+ return result if return_dict_in_generate else codes
738
+
739
+ def _codec_path(self) -> str:
740
+ source = str(getattr(self.config, "_name_or_path", ""))
741
+ local = Path(source)
742
+ if local.is_dir() and (local / self.config.codec_filename).is_file():
743
+ return str(local / self.config.codec_filename)
744
+ resolved = cached_file(source, self.config.codec_filename)
745
+ if resolved is None:
746
+ raise FileNotFoundError(f"Could not resolve {self.config.codec_filename} from {source}")
747
+ return resolved
748
+
749
+ def save_pretrained(self, save_directory, *args, **kwargs):
750
+ result = super().save_pretrained(save_directory, *args, **kwargs)
751
+ source = Path(self._codec_path()).resolve()
752
+ destination = Path(save_directory) / self.config.codec_filename
753
+ destination.parent.mkdir(parents=True, exist_ok=True)
754
+ if source != destination.resolve():
755
+ shutil.copy2(source, destination)
756
+ return result
757
+
758
+ def load_codec(self, device=None, dtype=None):
759
+ codec = self.__dict__.get("_arktts_codec")
760
+ target_device = torch.device(device) if device is not None else self.device
761
+ target_dtype = dtype or self.dtype
762
+ if target_device.type == "cpu":
763
+ target_dtype = torch.float32
764
+ if codec is None:
765
+ from .modeling_arktts_codec import ArkttsCodec
766
+
767
+ codec = ArkttsCodec(self.config)
768
+ state = torch.load(self._codec_path(), map_location="cpu", weights_only=True)
769
+ if "state_dict" in state:
770
+ state = state["state_dict"]
771
+ if any("generator." in key for key in state):
772
+ state = {
773
+ key.replace("generator.", ""): value
774
+ for key, value in state.items() if "generator." in key
775
+ }
776
+ state = {
777
+ key: value
778
+ for key, value in state.items()
779
+ if not key.endswith(("freqs_cis", "causal_mask"))
780
+ }
781
+ codec.load_state_dict(state, strict=True)
782
+ codec.eval()
783
+ self.__dict__["_arktts_codec"] = codec
784
+ codec.to(device=target_device, dtype=target_dtype)
785
+ return codec
786
+
787
+ @torch.inference_mode()
788
+ def encode_audio(self, audio_values: Tensor, audio_lengths: Optional[Tensor] = None):
789
+ codec = self.load_codec(device=audio_values.device)
790
+ audio_values = audio_values.to(dtype=next(codec.parameters()).dtype)
791
+ return codec.encode(audio_values, audio_lengths)
792
+
793
+ @torch.inference_mode()
794
+ def decode_audio(self, codes: Tensor):
795
+ if codes.ndim == 2:
796
+ codes = codes.unsqueeze(0)
797
+ if codes.ndim != 3 or codes.shape[1] != self.config.num_codebooks:
798
+ raise ValueError(f"codes must have shape [B, {self.config.num_codebooks}, T]")
799
+ codec = self.load_codec(device=codes.device)
800
+ waveforms = []
801
+ lengths = []
802
+ for item in codes:
803
+ valid = (item >= 0).all(dim=0)
804
+ length = int(valid.sum().item())
805
+ if length == 0:
806
+ waveform = torch.empty(0, device=codes.device, dtype=torch.float32)
807
+ else:
808
+ waveform = codec.decode(item[:, :length].unsqueeze(0))[0, 0].float()
809
+ waveforms.append(waveform)
810
+ lengths.append(waveform.numel())
811
+ max_length = max(lengths, default=0)
812
+ padded = torch.zeros((len(waveforms), max_length), dtype=torch.float32, device=codes.device)
813
+ for index, waveform in enumerate(waveforms):
814
+ padded[index, : waveform.numel()] = waveform
815
+ return padded, torch.tensor(lengths, dtype=torch.long, device=codes.device)
816
+
817
+ @torch.inference_mode()
818
+ def generate_audio(self, **kwargs):
819
+ codes = self.generate(**kwargs)
820
+ waveforms, lengths = self.decode_audio(codes)
821
+ return waveforms, lengths, codes
822
+
823
+
824
+ __all__ = [
825
+ "ArkttsConfig",
826
+ "ArkttsGenerateOutput",
827
+ "ArkttsLegacyTopKTopPLogitsProcessor",
828
+ "ArkttsModel",
829
+ "ArkttsModelOutput",
830
+ "ArkttsSemanticLogitsProcessor",
831
+ ]
modeling_arktts_codec.py ADDED
@@ -0,0 +1,520 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from dataclasses import dataclass
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+ from torch import Tensor
10
+ from torch.nn.utils import weight_norm as legacy_weight_norm
11
+ from torch.nn.utils.parametrizations import weight_norm
12
+
13
+
14
+ def _rope(length: int, head_dim: int, base: float, device=None) -> Tensor:
15
+ frequencies = 1.0 / (
16
+ base ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim)
17
+ )
18
+ phases = torch.outer(torch.arange(length, device=device), frequencies)
19
+ values = torch.polar(torch.ones_like(phases), phases)
20
+ return torch.stack((values.real, values.imag), dim=-1).to(torch.bfloat16)
21
+
22
+
23
+ def _apply_rope(x: Tensor, values: Tensor) -> Tensor:
24
+ shaped = x.float().reshape(*x.shape[:-1], -1, 2)
25
+ values = values.view(1, shaped.shape[1], 1, shaped.shape[3], 2)
26
+ output = torch.stack(
27
+ (
28
+ shaped[..., 0] * values[..., 0] - shaped[..., 1] * values[..., 1],
29
+ shaped[..., 1] * values[..., 0] + shaped[..., 0] * values[..., 1],
30
+ ),
31
+ dim=-1,
32
+ )
33
+ return output.flatten(3).to(x.dtype)
34
+
35
+
36
+ class ArkttsCodecRMSNorm(nn.Module):
37
+ def __init__(self, dim: int, eps: float = 1e-5):
38
+ super().__init__()
39
+ self.eps = float(eps)
40
+ self.weight = nn.Parameter(torch.ones(dim))
41
+
42
+ def forward(self, x):
43
+ output = x.float() * torch.rsqrt(x.float().pow(2).mean(-1, keepdim=True) + self.eps)
44
+ return output.to(x.dtype) * self.weight
45
+
46
+
47
+ class ArkttsCodecLayerScale(nn.Module):
48
+ def __init__(self, dim: int, init_values: float = 1e-2, inplace: bool = False):
49
+ super().__init__()
50
+ self.inplace = bool(inplace)
51
+ self.gamma = nn.Parameter(init_values * torch.ones(dim))
52
+
53
+ def forward(self, x):
54
+ return x.mul_(self.gamma) if self.inplace else x * self.gamma
55
+
56
+
57
+ @dataclass
58
+ class ArkttsCodecTransformerConfig:
59
+ n_layer: int
60
+ n_head: int
61
+ dim: int
62
+ intermediate_size: int
63
+ n_local_heads: int = -1
64
+ head_dim: int = 64
65
+ rope_base: float = 10000
66
+ norm_eps: float = 1e-5
67
+ dropout_rate: float = 0.1
68
+ attn_dropout_rate: float = 0.1
69
+ channels_first: bool = True
70
+
71
+ def __post_init__(self):
72
+ if self.n_local_heads == -1:
73
+ self.n_local_heads = self.n_head
74
+
75
+
76
+ class ArkttsCodecAttention(nn.Module):
77
+ def __init__(self, config: ArkttsCodecTransformerConfig):
78
+ super().__init__()
79
+ total = (config.n_head + 2 * config.n_local_heads) * config.head_dim
80
+ self.wqkv = nn.Linear(config.dim, total, bias=False)
81
+ self.wo = nn.Linear(config.head_dim * config.n_head, config.dim, bias=False)
82
+ self.n_head = config.n_head
83
+ self.n_local_heads = config.n_local_heads
84
+ self.head_dim = config.head_dim
85
+ self.attn_dropout_rate = config.attn_dropout_rate
86
+
87
+ def forward(self, x, rope_values, mask):
88
+ batch, length, _ = x.shape
89
+ query_size = self.n_head * self.head_dim
90
+ kv_size = self.n_local_heads * self.head_dim
91
+ query, key, value = self.wqkv(x).split((query_size, kv_size, kv_size), dim=-1)
92
+ query = query.view(batch, length, self.n_head, self.head_dim)
93
+ key = key.view(batch, length, self.n_local_heads, self.head_dim)
94
+ value = value.view(batch, length, self.n_local_heads, self.head_dim)
95
+ query = _apply_rope(query, rope_values).transpose(1, 2)
96
+ key = _apply_rope(key, rope_values).transpose(1, 2)
97
+ value = value.transpose(1, 2)
98
+ repeat = self.n_head // self.n_local_heads
99
+ key = key.repeat_interleave(repeat, dim=1)
100
+ value = value.repeat_interleave(repeat, dim=1)
101
+ output = F.scaled_dot_product_attention(
102
+ query,
103
+ key,
104
+ value,
105
+ attn_mask=mask,
106
+ dropout_p=self.attn_dropout_rate if self.training else 0.0,
107
+ )
108
+ output = output.transpose(1, 2).contiguous().view(batch, length, query_size)
109
+ return self.wo(output)
110
+
111
+
112
+ class ArkttsCodecFeedForward(nn.Module):
113
+ def __init__(self, config: ArkttsCodecTransformerConfig):
114
+ super().__init__()
115
+ self.w1 = nn.Linear(config.dim, config.intermediate_size, bias=False)
116
+ self.w3 = nn.Linear(config.dim, config.intermediate_size, bias=False)
117
+ self.w2 = nn.Linear(config.intermediate_size, config.dim, bias=False)
118
+ self.dropout = nn.Dropout(config.dropout_rate)
119
+
120
+ def forward(self, x):
121
+ return self.w2(self.dropout(F.silu(self.w1(x)) * self.w3(x)))
122
+
123
+
124
+ class ArkttsCodecTransformerBlock(nn.Module):
125
+ def __init__(self, config):
126
+ super().__init__()
127
+ self.attention = ArkttsCodecAttention(config)
128
+ self.feed_forward = ArkttsCodecFeedForward(config)
129
+ self.ffn_norm = ArkttsCodecRMSNorm(config.dim, config.norm_eps)
130
+ self.attention_norm = ArkttsCodecRMSNorm(config.dim, config.norm_eps)
131
+ self.attention_layer_scale = ArkttsCodecLayerScale(config.dim, inplace=True)
132
+ self.ffn_layer_scale = ArkttsCodecLayerScale(config.dim, inplace=True)
133
+
134
+ def forward(self, x, rope_values, mask):
135
+ hidden = x + self.attention_layer_scale(
136
+ self.attention(self.attention_norm(x), rope_values, mask)
137
+ )
138
+ return hidden + self.ffn_layer_scale(self.feed_forward(self.ffn_norm(hidden)))
139
+
140
+
141
+ class ArkttsCodecWindowTransformer(nn.Module):
142
+ def __init__(self, config, input_dim: int, window_size: int | None, causal: bool = True):
143
+ super().__init__()
144
+ self.layers = nn.ModuleList([ArkttsCodecTransformerBlock(config) for _ in range(config.n_layer)])
145
+ self.norm = ArkttsCodecRMSNorm(config.dim, config.norm_eps)
146
+ self.window_size = window_size
147
+ self.causal = causal
148
+ self.channels_first = config.channels_first
149
+ self.input_proj = nn.Linear(input_dim, config.dim) if input_dim != config.dim else nn.Identity()
150
+ self.output_proj = nn.Linear(config.dim, input_dim) if input_dim != config.dim else nn.Identity()
151
+ self.look_ahead_conv = nn.Identity()
152
+ self.head_dim = config.head_dim
153
+ self.rope_base = config.rope_base
154
+
155
+ def forward(self, x, x_lens=None):
156
+ del x_lens
157
+ if self.channels_first:
158
+ x = x.transpose(1, 2)
159
+ x = self.look_ahead_conv(self.input_proj(x))
160
+ length = x.shape[1]
161
+ row = torch.arange(length, device=x.device)[:, None]
162
+ column = torch.arange(length, device=x.device)[None, :]
163
+ mask = column <= row
164
+ if self.window_size is not None:
165
+ mask &= column >= (row - self.window_size + 1).clamp_min(0)
166
+ mask = mask[None, None]
167
+ rope_values = _rope(length, self.head_dim, self.rope_base, x.device)
168
+ for layer in self.layers:
169
+ x = layer(x, rope_values, mask)
170
+ x = self.output_proj(self.norm(x))
171
+ return x.transpose(1, 2) if self.channels_first else x
172
+
173
+
174
+ def _extra_padding(x, kernel_size: int, stride: int, padding_total: int = 0) -> int:
175
+ length = x.shape[-1]
176
+ frames = (length - kernel_size + padding_total) / stride + 1
177
+ ideal = (math.ceil(frames) - 1) * stride + kernel_size - padding_total
178
+ return ideal - length
179
+
180
+
181
+ class ArkttsCausalConv1d(nn.Module):
182
+ def __init__(self, in_channels, out_channels, kernel_size, dilation=1, stride=1, groups=1):
183
+ super().__init__()
184
+ self.conv = nn.Conv1d(
185
+ in_channels, out_channels, kernel_size, stride=stride, dilation=dilation, groups=groups
186
+ )
187
+ self.stride = stride
188
+ self.kernel_size = (kernel_size - 1) * dilation + 1
189
+ self.padding = self.kernel_size - self.stride
190
+
191
+ def forward(self, x):
192
+ right = _extra_padding(x, self.kernel_size, self.stride, self.padding)
193
+ return self.conv(F.pad(x, (self.padding, right))).contiguous()
194
+
195
+ def apply_weight_norm(self):
196
+ self.conv = weight_norm(self.conv)
197
+ return self
198
+
199
+
200
+ class ArkttsCausalConvTranspose1d(nn.Module):
201
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1):
202
+ super().__init__()
203
+ self.conv = nn.ConvTranspose1d(
204
+ in_channels, out_channels, kernel_size, stride=stride, dilation=dilation
205
+ )
206
+ self.stride = stride
207
+ self.kernel_size = kernel_size
208
+
209
+ def forward(self, x):
210
+ x = self.conv(x)
211
+ crop = self.kernel_size - self.stride
212
+ return x[..., : x.shape[-1] - crop].contiguous() if crop else x.contiguous()
213
+
214
+ def apply_weight_norm(self):
215
+ self.conv = weight_norm(self.conv)
216
+ return self
217
+
218
+
219
+ def _causal_wn_conv(*args, **kwargs):
220
+ return ArkttsCausalConv1d(*args, **kwargs).apply_weight_norm()
221
+
222
+
223
+ def _causal_wn_transpose(*args, **kwargs):
224
+ return ArkttsCausalConvTranspose1d(*args, **kwargs).apply_weight_norm()
225
+
226
+
227
+ @torch.jit.script
228
+ def _arktts_snake(x: Tensor, alpha: Tensor) -> Tensor:
229
+ shape = x.shape
230
+ x = x.reshape(shape[0], shape[1], -1)
231
+ x = x + (alpha + 1e-9).reciprocal() * torch.sin(alpha * x).pow(2)
232
+ return x.reshape(shape)
233
+
234
+
235
+ class ArkttsSnake1d(nn.Module):
236
+ def __init__(self, channels):
237
+ super().__init__()
238
+ self.alpha = nn.Parameter(torch.ones(1, channels, 1))
239
+
240
+ def forward(self, x):
241
+ return _arktts_snake(x, self.alpha)
242
+
243
+
244
+ class ArkttsResidualUnit(nn.Module):
245
+ def __init__(self, dim: int, dilation: int):
246
+ super().__init__()
247
+ self.block = nn.Sequential(
248
+ ArkttsSnake1d(dim),
249
+ _causal_wn_conv(dim, dim, kernel_size=7, dilation=dilation),
250
+ ArkttsSnake1d(dim),
251
+ _causal_wn_conv(dim, dim, kernel_size=1),
252
+ )
253
+
254
+ def forward(self, x):
255
+ output = self.block(x)
256
+ difference = x.shape[-1] - output.shape[-1]
257
+ if difference > 0:
258
+ x = x[..., :-difference]
259
+ return x + output
260
+
261
+
262
+ class ArkttsEncoderBlock(nn.Module):
263
+ def __init__(self, dim: int, stride: int, transformer_layers: int):
264
+ super().__init__()
265
+ modules = [
266
+ ArkttsResidualUnit(dim // 2, 1),
267
+ ArkttsResidualUnit(dim // 2, 3),
268
+ ArkttsResidualUnit(dim // 2, 9),
269
+ ArkttsSnake1d(dim // 2),
270
+ _causal_wn_conv(dim // 2, dim, kernel_size=2 * stride, stride=stride),
271
+ ]
272
+ if transformer_layers:
273
+ config = ArkttsCodecTransformerConfig(
274
+ n_layer=transformer_layers,
275
+ n_head=dim // 64,
276
+ dim=dim,
277
+ intermediate_size=dim * 3,
278
+ )
279
+ modules.append(ArkttsCodecWindowTransformer(config, dim, window_size=512))
280
+ else:
281
+ modules.append(nn.Identity())
282
+ self.block = nn.Sequential(*modules)
283
+
284
+ def forward(self, x):
285
+ return self.block(x)
286
+
287
+
288
+ class ArkttsEncoder(nn.Module):
289
+ def __init__(self):
290
+ super().__init__()
291
+ dim = 64
292
+ modules = [_causal_wn_conv(1, dim, kernel_size=7)]
293
+ for stride, transformer_layers in zip((2, 4, 8, 8), (0, 0, 0, 4)):
294
+ dim *= 2
295
+ modules.append(ArkttsEncoderBlock(dim, stride, transformer_layers))
296
+ modules.extend((ArkttsSnake1d(dim), _causal_wn_conv(dim, 1024, kernel_size=3)))
297
+ self.block = nn.Sequential(*modules)
298
+
299
+ def forward(self, x):
300
+ return self.block(x)
301
+
302
+
303
+ class ArkttsDecoderBlock(nn.Module):
304
+ def __init__(self, input_dim: int, output_dim: int, stride: int):
305
+ super().__init__()
306
+ self.block = nn.Sequential(
307
+ ArkttsSnake1d(input_dim),
308
+ _causal_wn_transpose(input_dim, output_dim, kernel_size=2 * stride, stride=stride),
309
+ ArkttsResidualUnit(output_dim, 1),
310
+ ArkttsResidualUnit(output_dim, 3),
311
+ ArkttsResidualUnit(output_dim, 9),
312
+ )
313
+
314
+ def forward(self, x):
315
+ return self.block(x)
316
+
317
+
318
+ class ArkttsDecoder(nn.Module):
319
+ def __init__(self):
320
+ super().__init__()
321
+ channels = 1536
322
+ modules = [_causal_wn_conv(1024, channels, kernel_size=7)]
323
+ for index, stride in enumerate((8, 8, 4, 2)):
324
+ input_dim = channels // (2**index)
325
+ output_dim = channels // (2 ** (index + 1))
326
+ modules.append(ArkttsDecoderBlock(input_dim, output_dim, stride))
327
+ modules.extend((ArkttsSnake1d(output_dim), _causal_wn_conv(output_dim, 1, kernel_size=7), nn.Tanh()))
328
+ self.model = nn.Sequential(*modules)
329
+
330
+ def forward(self, x):
331
+ return self.model(x)
332
+
333
+
334
+ class ArkttsVectorQuantizer(nn.Module):
335
+ def __init__(self, input_dim: int, codebook_size: int, codebook_dim: int):
336
+ super().__init__()
337
+ self.codebook_size = int(codebook_size)
338
+ self.codebook_dim = int(codebook_dim)
339
+ self.in_proj = legacy_weight_norm(nn.Conv1d(input_dim, codebook_dim, kernel_size=1))
340
+ self.out_proj = legacy_weight_norm(nn.Conv1d(codebook_dim, input_dim, kernel_size=1))
341
+ self.codebook = nn.Embedding(codebook_size, codebook_dim)
342
+
343
+ def decode_code(self, indices):
344
+ return F.embedding(indices, self.codebook.weight).transpose(1, 2)
345
+
346
+ def decode_latents(self, latents):
347
+ batch, _, length = latents.shape
348
+ flattened = latents.transpose(1, 2).reshape(batch * length, -1)
349
+ flattened = F.normalize(flattened)
350
+ codebook = F.normalize(self.codebook.weight)
351
+ distances = (
352
+ flattened.pow(2).sum(1, keepdim=True)
353
+ - 2 * flattened @ codebook.t()
354
+ + codebook.pow(2).sum(1, keepdim=True).t()
355
+ )
356
+ indices = (-distances).argmax(1).view(batch, length)
357
+ return self.decode_code(indices), indices
358
+
359
+ def forward(self, z):
360
+ projected = self.in_proj(z)
361
+ quantized, indices = self.decode_latents(projected)
362
+ quantized_st = projected + (quantized - projected).detach()
363
+ return self.out_proj(quantized_st), indices, projected
364
+
365
+
366
+ class ArkttsResidualQuantizer(nn.Module):
367
+ def __init__(self, input_dim: int, n_codebooks: int, codebook_size: int, codebook_dim: int):
368
+ super().__init__()
369
+ self.n_codebooks = int(n_codebooks)
370
+ self.codebook_size = int(codebook_size)
371
+ self.quantizers = nn.ModuleList([
372
+ ArkttsVectorQuantizer(input_dim, codebook_size, codebook_dim)
373
+ for _ in range(n_codebooks)
374
+ ])
375
+
376
+ def forward(self, z):
377
+ quantized_sum = 0.0
378
+ residual = z
379
+ codes = []
380
+ for quantizer in self.quantizers:
381
+ quantized, indices, _ = quantizer(residual)
382
+ quantized_sum = quantized_sum + quantized
383
+ residual = residual - quantized
384
+ codes.append(indices)
385
+ return quantized_sum, torch.stack(codes, dim=1)
386
+
387
+ def from_codes(self, codes):
388
+ output = 0.0
389
+ for index in range(codes.shape[1]):
390
+ projected = self.quantizers[index].decode_code(codes[:, index])
391
+ output = output + self.quantizers[index].out_proj(projected)
392
+ return output
393
+
394
+
395
+ class ArkttsConvNeXtBlock(nn.Module):
396
+ def __init__(self, dim: int):
397
+ super().__init__()
398
+ self.dwconv = ArkttsCausalConv1d(dim, dim, kernel_size=7, groups=dim)
399
+ self.norm = nn.LayerNorm(dim, eps=1e-6)
400
+ self.pwconv1 = nn.Linear(dim, 4 * dim)
401
+ self.act = nn.GELU()
402
+ self.pwconv2 = nn.Linear(4 * dim, dim)
403
+ self.gamma = nn.Parameter(1e-6 * torch.ones(dim))
404
+
405
+ def forward(self, x):
406
+ residual = x
407
+ x = self.dwconv(x).permute(0, 2, 1)
408
+ x = self.pwconv2(self.act(self.pwconv1(self.norm(x))))
409
+ x = (self.gamma * x).permute(0, 2, 1)
410
+ return residual + x
411
+
412
+
413
+ class ArkttsDownsampleQuantizer(nn.Module):
414
+ def __init__(self, config=None):
415
+ super().__init__()
416
+ self.semantic_quantizer = ArkttsResidualQuantizer(1024, 1, 4096, 8)
417
+ self.quantizer = ArkttsResidualQuantizer(1024, 9, 1024, 8)
418
+ self.downsample = nn.Sequential(
419
+ nn.Sequential(
420
+ ArkttsCausalConv1d(1024, 1024, kernel_size=2, stride=2),
421
+ ArkttsConvNeXtBlock(1024),
422
+ ),
423
+ nn.Sequential(
424
+ ArkttsCausalConv1d(1024, 1024, kernel_size=2, stride=2),
425
+ ArkttsConvNeXtBlock(1024),
426
+ ),
427
+ )
428
+ self.upsample = nn.Sequential(
429
+ nn.Sequential(
430
+ ArkttsCausalConvTranspose1d(1024, 1024, kernel_size=2, stride=2),
431
+ ArkttsConvNeXtBlock(1024),
432
+ ),
433
+ nn.Sequential(
434
+ ArkttsCausalConvTranspose1d(1024, 1024, kernel_size=2, stride=2),
435
+ ArkttsConvNeXtBlock(1024),
436
+ ),
437
+ )
438
+ pre_transformer_config = ArkttsCodecTransformerConfig(
439
+ n_layer=8,
440
+ n_head=16,
441
+ dim=1024,
442
+ intermediate_size=3072,
443
+ )
444
+ post_transformer_config = ArkttsCodecTransformerConfig(
445
+ n_layer=int(getattr(config, "codec_post_n_layer", 8)),
446
+ n_head=int(getattr(config, "codec_post_n_head", 16)),
447
+ n_local_heads=int(getattr(config, "codec_post_n_local_heads", 8)),
448
+ dim=1024,
449
+ intermediate_size=int(getattr(config, "codec_post_intermediate_size", 1216)),
450
+ )
451
+ self.pre_module = ArkttsCodecWindowTransformer(
452
+ pre_transformer_config, 1024, window_size=128
453
+ )
454
+ self.post_module = ArkttsCodecWindowTransformer(
455
+ post_transformer_config, 1024, window_size=128
456
+ )
457
+ self.semantic_predictor_module = nn.Identity()
458
+
459
+ def forward(self, z):
460
+ original_length = z.shape[-1]
461
+ z = self.pre_module(self.downsample(z))
462
+ semantic, semantic_codes = self.semantic_quantizer(z)
463
+ residual, residual_codes = self.quantizer(z - semantic)
464
+ z = self.upsample(self.post_module(semantic + residual))
465
+ difference = original_length - z.shape[-1]
466
+ if difference > 0:
467
+ z = F.pad(z, (difference, 0))
468
+ elif difference < 0:
469
+ z = z[..., -difference:]
470
+ return z, torch.cat((semantic_codes, residual_codes), dim=1)
471
+
472
+ def decode(self, indices):
473
+ indices = indices.clone()
474
+ indices[:, 0].clamp_(0, self.semantic_quantizer.codebook_size - 1)
475
+ indices[:, 1:].clamp_(0, self.quantizer.codebook_size - 1)
476
+ semantic = self.semantic_quantizer.from_codes(indices[:, :1])
477
+ residual = self.quantizer.from_codes(indices[:, 1:])
478
+ return self.upsample(self.post_module(semantic + residual))
479
+
480
+
481
+ class ArkttsCodec(nn.Module):
482
+ sample_rate = 44100
483
+ hop_length = 512
484
+ frame_length = 2048
485
+
486
+ def __init__(self, config=None):
487
+ super().__init__()
488
+ self.encoder = ArkttsEncoder()
489
+ self.quantizer = ArkttsDownsampleQuantizer(config)
490
+ self.decoder = ArkttsDecoder()
491
+
492
+ @torch.inference_mode()
493
+ def encode(self, audio, audio_lengths=None):
494
+ if audio.ndim == 2:
495
+ audio = audio[:, None]
496
+ if audio.ndim != 3 or audio.shape[1] != 1:
497
+ raise ValueError("audio must have shape [B, 1, samples]")
498
+ original_length = audio.shape[-1]
499
+ right = math.ceil(original_length / self.frame_length) * self.frame_length - original_length
500
+ if right:
501
+ audio = F.pad(audio, (0, right))
502
+ if audio_lengths is None:
503
+ audio_lengths = torch.full(
504
+ (audio.shape[0],), original_length, device=audio.device, dtype=torch.long
505
+ )
506
+ encoded = self.encoder(audio)
507
+ _, codes = self.quantizer(encoded)
508
+ code_lengths = torch.ceil(audio_lengths.float() / self.frame_length).long()
509
+ max_codes = codes.shape[-1]
510
+ padded = torch.full_like(codes, -1)
511
+ for index, length in enumerate(code_lengths.tolist()):
512
+ padded[index, :, : min(length, max_codes)] = codes[index, :, : min(length, max_codes)]
513
+ return padded, code_lengths.clamp_max(max_codes)
514
+
515
+ @torch.inference_mode()
516
+ def decode(self, codes):
517
+ return self.decoder(self.quantizer.decode(codes.long()))
518
+
519
+
520
+ __all__ = ["ArkttsCodec"]
preprocessor_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "audio_sampling_rate": 44100,
3
+ "auto_map": {
4
+ "AutoProcessor": "processing_arktts.ArkttsProcessor"
5
+ },
6
+ "feature_extractor_type": "ArkttsProcessor",
7
+ "num_codebooks": 10,
8
+ "processor_class": "ArkttsProcessor",
9
+ "semantic_begin_id": 151678
10
+ }
processing_arktts.py ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import json
5
+ import os
6
+ import re
7
+ from pathlib import Path
8
+ from typing import Any, Sequence
9
+
10
+ import numpy as np
11
+ import torch
12
+ from transformers import AutoTokenizer
13
+ from transformers.feature_extraction_utils import BatchFeature
14
+ from transformers.processing_utils import ProcessorMixin
15
+
16
+
17
+ def _clean_text(text: str) -> str:
18
+ return " ".join(str(text).strip().split())
19
+
20
+
21
+ def _as_list(value: Any, batch_size: int, name: str) -> list[Any]:
22
+ if isinstance(value, (str, Path)) or value is None or np.isscalar(value):
23
+ return [value] * batch_size
24
+ if isinstance(value, torch.Tensor) and value.ndim <= 2:
25
+ return [value] if batch_size == 1 else list(value)
26
+ if isinstance(value, np.ndarray) and value.ndim <= 2:
27
+ return [value] if batch_size == 1 else list(value)
28
+ values = list(value)
29
+ if len(values) != batch_size:
30
+ raise ValueError(f"{name} must contain {batch_size} items, got {len(values)}")
31
+ return values
32
+
33
+
34
+ def _pad_1d(rows: list[torch.Tensor], pad_value: int) -> tuple[torch.Tensor, torch.Tensor]:
35
+ max_len = max((row.numel() for row in rows), default=0)
36
+ values = torch.full((len(rows), max_len), pad_value, dtype=torch.long)
37
+ mask = torch.zeros((len(rows), max_len), dtype=torch.long)
38
+ for idx, row in enumerate(rows):
39
+ length = row.numel()
40
+ values[idx, :length] = row
41
+ mask[idx, :length] = 1
42
+ return values, mask
43
+
44
+
45
+ class ArkttsProcessor(ProcessorMixin):
46
+ attributes = ["tokenizer"]
47
+ tokenizer_class = ("PreTrainedTokenizerFast", "PreTrainedTokenizer")
48
+ valid_kwargs = ["num_codebooks", "semantic_begin_id", "audio_sampling_rate"]
49
+
50
+ def __init__(
51
+ self,
52
+ tokenizer,
53
+ num_codebooks: int = 10,
54
+ semantic_begin_id: int = 151678,
55
+ audio_sampling_rate: int = 44100,
56
+ **kwargs,
57
+ ):
58
+ super().__init__(tokenizer)
59
+ self.num_codebooks = int(num_codebooks)
60
+ self.semantic_begin_id = int(semantic_begin_id)
61
+ self.audio_sampling_rate = int(audio_sampling_rate)
62
+
63
+ @classmethod
64
+ def from_pretrained(cls, pretrained_model_name_or_path: str, **kwargs) -> "ArkttsProcessor":
65
+ trust_remote_code = bool(kwargs.pop("trust_remote_code", False))
66
+ shared_names = {
67
+ "cache_dir", "force_download", "local_files_only", "token", "revision", "subfolder"
68
+ }
69
+ shared = {key: kwargs[key] for key in list(kwargs) if key in shared_names}
70
+ config = {}
71
+ local_config = os.path.join(str(pretrained_model_name_or_path), "processor_config.json")
72
+ if os.path.isfile(local_config):
73
+ with open(local_config, "r", encoding="utf-8") as handle:
74
+ config = json.load(handle)
75
+ tokenizer = AutoTokenizer.from_pretrained(
76
+ pretrained_model_name_or_path,
77
+ use_fast=True,
78
+ trust_remote_code=trust_remote_code,
79
+ fix_mistral_regex=False,
80
+ **shared,
81
+ )
82
+ return cls(
83
+ tokenizer=tokenizer,
84
+ num_codebooks=config.get("num_codebooks", 10),
85
+ semantic_begin_id=config.get("semantic_begin_id", 151678),
86
+ audio_sampling_rate=config.get("audio_sampling_rate", 44100),
87
+ )
88
+
89
+ def _encode(self, text: str) -> torch.Tensor:
90
+ encode_kwargs = {"add_special_tokens": False}
91
+ if "allowed_special" in inspect.signature(self.tokenizer.encode).parameters:
92
+ encode_kwargs["allowed_special"] = "all"
93
+ return torch.tensor(self.tokenizer.encode(text, **encode_kwargs), dtype=torch.long)
94
+
95
+ @staticmethod
96
+ def _format_reference_text(text: str) -> str:
97
+ cleaned = _clean_text(text)
98
+ if re.search(r"<\|speaker:\d+\|>", cleaned):
99
+ return cleaned
100
+ return f"<|speaker:0|>{cleaned}"
101
+
102
+ def _prompt_segments(self, text: str, reference_text: str | None, has_reference: bool):
103
+ target = _clean_text(text)
104
+ if not target:
105
+ raise ValueError("text must not be empty")
106
+ def encode_parts(parts: list[str]) -> torch.Tensor:
107
+ return torch.cat([self._encode(part) for part in parts])
108
+
109
+ if not has_reference:
110
+ full = encode_parts([
111
+ "<|im_start|>system\n",
112
+ "convert the provided text to speech",
113
+ "<|im_end|>\n",
114
+ "<|im_start|>user\n",
115
+ target,
116
+ "<|im_end|>\n",
117
+ "<|im_start|>assistant\n<|voice|>",
118
+ ])
119
+ return full, self._encode("")
120
+ if not reference_text:
121
+ raise ValueError("reference_text is required when a reference voice is provided")
122
+ prefix = encode_parts([
123
+ "<|im_start|>system\n",
124
+ "convert the provided text to speech reference to the following:\n\nText:\n",
125
+ self._format_reference_text(reference_text),
126
+ "\n\nSpeech:\n",
127
+ ])
128
+ suffix = encode_parts([
129
+ "<|im_end|>\n",
130
+ "<|im_start|>user\n",
131
+ target,
132
+ "<|im_end|>\n",
133
+ "<|im_start|>assistant\n<|voice|>",
134
+ ])
135
+ return prefix, suffix
136
+
137
+ def _load_audio(self, value: Any, sampling_rate: int | None) -> torch.Tensor:
138
+ source_rate = sampling_rate
139
+ if isinstance(value, (str, Path)):
140
+ try:
141
+ import soundfile as sf
142
+ except ImportError as exc:
143
+ raise ImportError("soundfile is required for reference audio paths") from exc
144
+ array, source_rate = sf.read(str(value), dtype="float32", always_2d=True)
145
+ array = array.mean(axis=1)
146
+ audio = torch.from_numpy(np.asarray(array, dtype=np.float32))
147
+ else:
148
+ if isinstance(value, dict):
149
+ source_rate = value.get("sampling_rate", source_rate)
150
+ value = value.get("array")
151
+ if isinstance(value, (tuple, list)) and len(value) == 2 and np.isscalar(value[1]):
152
+ value, source_rate = value
153
+ audio = torch.as_tensor(value, dtype=torch.float32)
154
+ if audio.ndim == 2:
155
+ audio = audio.mean(dim=0)
156
+ if audio.ndim != 1:
157
+ raise ValueError(f"reference audio must be mono or channels-first, got {tuple(audio.shape)}")
158
+ if audio.numel() == 0:
159
+ raise ValueError("reference audio must not be empty")
160
+ if source_rate is None:
161
+ raise ValueError("sampling_rate is required for reference audio arrays")
162
+ if int(source_rate) != self.audio_sampling_rate:
163
+ try:
164
+ from torchaudio.functional import resample
165
+ except ImportError as exc:
166
+ raise ImportError("torchaudio is required to resample reference audio") from exc
167
+ audio = resample(audio, int(source_rate), self.audio_sampling_rate)
168
+ return audio.contiguous()
169
+
170
+ def __call__(
171
+ self,
172
+ text: str | Sequence[str],
173
+ reference_text: str | Sequence[str] | None = None,
174
+ reference_audio: Any = None,
175
+ reference_codes: Any = None,
176
+ sampling_rate: int | Sequence[int] | None = None,
177
+ return_tensors: str = "pt",
178
+ **kwargs,
179
+ ) -> BatchFeature:
180
+ if kwargs:
181
+ raise TypeError(f"Unexpected processor arguments: {sorted(kwargs)}")
182
+ if return_tensors != "pt":
183
+ raise ValueError("ArkttsProcessor currently supports return_tensors='pt' only")
184
+ texts = [text] if isinstance(text, str) else list(text)
185
+ if not texts:
186
+ raise ValueError("text batch must not be empty")
187
+ batch_size = len(texts)
188
+ ref_texts = _as_list(reference_text, batch_size, "reference_text")
189
+ if reference_audio is not None and reference_codes is not None:
190
+ raise ValueError("Provide reference_audio or reference_codes, not both")
191
+ has_reference = reference_audio is not None or reference_codes is not None
192
+
193
+ prefix_rows, suffix_rows = zip(*[
194
+ self._prompt_segments(item, ref_texts[idx], has_reference)
195
+ for idx, item in enumerate(texts)
196
+ ])
197
+ prefix_ids, prefix_mask = _pad_1d(list(prefix_rows), self.tokenizer.pad_token_id)
198
+ suffix_ids, suffix_mask = _pad_1d(list(suffix_rows), self.tokenizer.pad_token_id)
199
+ data: dict[str, torch.Tensor] = {
200
+ "prefix_input_ids": prefix_ids,
201
+ "prefix_attention_mask": prefix_mask,
202
+ "suffix_input_ids": suffix_ids,
203
+ "suffix_attention_mask": suffix_mask,
204
+ }
205
+
206
+ if reference_codes is not None:
207
+ code_items = _as_list(reference_codes, batch_size, "reference_codes")
208
+ loaded = []
209
+ for item in code_items:
210
+ if isinstance(item, (str, Path)):
211
+ item = np.load(str(item))
212
+ codes = torch.as_tensor(item, dtype=torch.long)
213
+ if codes.ndim != 2 or codes.shape[0] != self.num_codebooks or codes.shape[1] == 0:
214
+ raise ValueError(
215
+ f"reference codes must have shape [{self.num_codebooks}, T>0], got {tuple(codes.shape)}"
216
+ )
217
+ if codes.min() < 0 or codes.max() >= 4096:
218
+ raise ValueError("reference codes must be in [0, 4095]")
219
+ loaded.append(codes)
220
+ max_frames = max(item.shape[1] for item in loaded)
221
+ padded = torch.full((batch_size, self.num_codebooks, max_frames), -1, dtype=torch.long)
222
+ lengths = torch.empty(batch_size, dtype=torch.long)
223
+ for idx, codes in enumerate(loaded):
224
+ lengths[idx] = codes.shape[1]
225
+ padded[idx, :, : codes.shape[1]] = codes
226
+ data["reference_codes"] = padded
227
+ data["reference_code_lengths"] = lengths
228
+
229
+ if reference_audio is not None:
230
+ audio_items = _as_list(reference_audio, batch_size, "reference_audio")
231
+ rate_items = _as_list(sampling_rate, batch_size, "sampling_rate")
232
+ loaded_audio = [self._load_audio(item, rate_items[idx]) for idx, item in enumerate(audio_items)]
233
+ max_samples = max(item.numel() for item in loaded_audio)
234
+ padded_audio = torch.zeros((batch_size, 1, max_samples), dtype=torch.float32)
235
+ lengths = torch.empty(batch_size, dtype=torch.long)
236
+ for idx, audio in enumerate(loaded_audio):
237
+ lengths[idx] = audio.numel()
238
+ padded_audio[idx, 0, : audio.numel()] = audio
239
+ data["reference_audio_values"] = padded_audio
240
+ data["reference_audio_lengths"] = lengths
241
+
242
+ return BatchFeature(data=data)
243
+
244
+ @property
245
+ def model_input_names(self) -> list[str]:
246
+ return [
247
+ "prefix_input_ids", "prefix_attention_mask", "suffix_input_ids",
248
+ "suffix_attention_mask", "reference_codes", "reference_code_lengths",
249
+ "reference_audio_values", "reference_audio_lengths",
250
+ ]
251
+
252
+ def batch_decode(self, *args, **kwargs):
253
+ return self.tokenizer.batch_decode(*args, **kwargs)
254
+
255
+ def decode(self, *args, **kwargs):
256
+ return self.tokenizer.decode(*args, **kwargs)
257
+
258
+
259
+ __all__ = ["ArkttsProcessor"]
processor_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "audio_sampling_rate": 44100,
3
+ "auto_map": {
4
+ "AutoProcessor": "processing_arktts.ArkttsProcessor"
5
+ },
6
+ "num_codebooks": 10,
7
+ "processor_class": "ArkttsProcessor",
8
+ "semantic_begin_id": 151678
9
+ }
special_tokens_map.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f24e08099d45a8adf3f52f5f0b03276e433bb9d689bb15fcbcc48ce58744588b
3
+ size 12217872
tokenizer_config.json ADDED
The diff for this file is too large to render. See raw diff