calculating
commited on
Commit
•
824afbf
1
Parent(s):
35d94d0
committing...
Browse files- app.py +245 -0
- ioblocks.py +333 -0
- model.py +443 -0
- requirements.txt +14 -0
- tokenizer.py +581 -0
- transformer.py +382 -0
- utils/__init__.py +3 -0
- utils/__pycache__/__init__.cpython-310.pyc +0 -0
- utils/__pycache__/blocks.cpython-310.pyc +0 -0
- utils/__pycache__/dist.cpython-310.pyc +0 -0
- utils/__pycache__/interp.cpython-310.pyc +0 -0
- utils/blocks.py +92 -0
- utils/dist.py +99 -0
- utils/interp.py +84 -0
app.py
ADDED
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import torch as T
|
3 |
+
import torch.nn as nn
|
4 |
+
import torch.nn.functional as F
|
5 |
+
import torchaudio
|
6 |
+
import matplotlib.pyplot as plt
|
7 |
+
from utils import load_ckpt, print_colored
|
8 |
+
from tokenizer import make_tokenizer
|
9 |
+
from model import get_hertz_dev_config
|
10 |
+
from typing import Tuple
|
11 |
+
import numpy as np
|
12 |
+
import os
|
13 |
+
|
14 |
+
# Global variables for model and tokenizer
|
15 |
+
global_generator = None
|
16 |
+
global_tokenizer = None
|
17 |
+
default_audio_path = "testingtesting.wav" # Your default audio file
|
18 |
+
|
19 |
+
def init_model(use_pure_audio_ablation: bool = False) -> Tuple[nn.Module, object]:
|
20 |
+
"""Initialize the model and tokenizer"""
|
21 |
+
global global_generator, global_tokenizer
|
22 |
+
|
23 |
+
if global_generator is not None and global_tokenizer is not None:
|
24 |
+
return global_generator, global_tokenizer
|
25 |
+
|
26 |
+
device = 'cuda' if T.cuda.is_available() else 'cpu'
|
27 |
+
T.cuda.set_device(0) if device == 'cuda' else None
|
28 |
+
|
29 |
+
print_colored("Initializing model and tokenizer...", "blue")
|
30 |
+
global_tokenizer = make_tokenizer(device)
|
31 |
+
model_config = get_hertz_dev_config(is_split=False, use_pure_audio_ablation=use_pure_audio_ablation)
|
32 |
+
|
33 |
+
global_generator = model_config()
|
34 |
+
global_generator = global_generator.eval().to(T.bfloat16).to(device)
|
35 |
+
print_colored("Model initialization complete!", "green")
|
36 |
+
|
37 |
+
return global_generator, global_tokenizer
|
38 |
+
|
39 |
+
def process_audio(audio_path: str, sr: int) -> T.Tensor:
|
40 |
+
"""Load and preprocess audio file"""
|
41 |
+
audio_tensor, sr = torchaudio.load(audio_path)
|
42 |
+
|
43 |
+
|
44 |
+
if audio_tensor.shape[0] == 2:
|
45 |
+
audio_tensor = audio_tensor.mean(dim=0).unsqueeze(0)
|
46 |
+
|
47 |
+
if sr != 16000:
|
48 |
+
resampler = torchaudio.transforms.Resample(orig_freq=sr, new_freq=16000)
|
49 |
+
audio_tensor = resampler(audio_tensor)
|
50 |
+
|
51 |
+
max_samples = 16000 * 60 * 5 # 5 minutes
|
52 |
+
if audio_tensor.shape[1] > max_samples:
|
53 |
+
audio_tensor = audio_tensor[:, :max_samples]
|
54 |
+
|
55 |
+
return audio_tensor.unsqueeze(0)
|
56 |
+
|
57 |
+
def generate_completion(
|
58 |
+
audio_file,
|
59 |
+
prompt_len_seconds: float = 3.0,
|
60 |
+
num_completions: int = 5,
|
61 |
+
generation_seconds: float = 20.0,
|
62 |
+
token_temp: float = 0.8,
|
63 |
+
categorical_temp: float = 0.5,
|
64 |
+
gaussian_temp: float = 0.1,
|
65 |
+
progress=gr.Progress(track_tqdm=True)
|
66 |
+
) -> list:
|
67 |
+
"""Generate audio completions from the input audio"""
|
68 |
+
device = 'cuda' if T.cuda.is_available() else 'cpu'
|
69 |
+
|
70 |
+
# Use existing model and tokenizer
|
71 |
+
generator, audio_tokenizer = global_generator, global_tokenizer
|
72 |
+
|
73 |
+
progress(0, desc="Processing input audio...")
|
74 |
+
# Process input audio
|
75 |
+
prompt_audio = process_audio(audio_file, sr=16000)
|
76 |
+
prompt_len = int(prompt_len_seconds * 8)
|
77 |
+
|
78 |
+
progress(0.2, desc="Encoding prompt...")
|
79 |
+
# Encode prompt
|
80 |
+
with T.autocast(device_type='cuda', dtype=T.bfloat16):
|
81 |
+
encoded_prompt_audio = audio_tokenizer.latent_from_data(prompt_audio.to(device))
|
82 |
+
|
83 |
+
completions = []
|
84 |
+
for i in range(num_completions):
|
85 |
+
progress((i + 1) / num_completions, desc=f"Generating completion {i+1}/{num_completions}")
|
86 |
+
|
87 |
+
# Generate completion
|
88 |
+
encoded_prompt = encoded_prompt_audio[:, :prompt_len]
|
89 |
+
with T.autocast(device_type='cuda', dtype=T.bfloat16):
|
90 |
+
completed_audio_batch = generator.completion(
|
91 |
+
encoded_prompt,
|
92 |
+
temps=(token_temp, (categorical_temp, gaussian_temp)),
|
93 |
+
use_cache=True,
|
94 |
+
gen_len=int(generation_seconds * 8)
|
95 |
+
)
|
96 |
+
|
97 |
+
decoded_completion = audio_tokenizer.data_from_latent(completed_audio_batch.bfloat16())
|
98 |
+
|
99 |
+
# Process audio for output
|
100 |
+
audio_tensor = decoded_completion.cpu().squeeze()
|
101 |
+
if audio_tensor.ndim == 1:
|
102 |
+
audio_tensor = audio_tensor.unsqueeze(0)
|
103 |
+
audio_tensor = audio_tensor.float()
|
104 |
+
|
105 |
+
if audio_tensor.abs().max() > 1:
|
106 |
+
audio_tensor = audio_tensor / audio_tensor.abs().max()
|
107 |
+
|
108 |
+
# Trim to include only the generated portion
|
109 |
+
output_audio = audio_tensor[:, max(prompt_len*2000 - 16000, 0):]
|
110 |
+
completions.append((16000, output_audio.numpy().T))
|
111 |
+
|
112 |
+
progress(1.0, desc="Generation complete!")
|
113 |
+
return completions
|
114 |
+
|
115 |
+
def create_interface():
|
116 |
+
# Initialize model at startup
|
117 |
+
init_model()
|
118 |
+
|
119 |
+
with gr.Blocks(title="Audio Completion Generator") as app:
|
120 |
+
gr.Markdown("""
|
121 |
+
# Audio Completion Generator
|
122 |
+
Upload an audio file (or use the default) and generate AI completions based on the prompt.
|
123 |
+
""")
|
124 |
+
|
125 |
+
with gr.Row():
|
126 |
+
with gr.Column():
|
127 |
+
# Load the default audio if it exists
|
128 |
+
default_value = default_audio_path if os.path.exists(default_audio_path) else None
|
129 |
+
|
130 |
+
audio_input = gr.Audio(
|
131 |
+
label="Input Audio",
|
132 |
+
type="filepath",
|
133 |
+
sources=["microphone", "upload"],
|
134 |
+
value=default_value
|
135 |
+
)
|
136 |
+
|
137 |
+
with gr.Row():
|
138 |
+
prompt_len = gr.Slider(
|
139 |
+
minimum=1,
|
140 |
+
maximum=10,
|
141 |
+
value=3,
|
142 |
+
step=0.5,
|
143 |
+
label="Prompt Length (seconds)"
|
144 |
+
)
|
145 |
+
default_num_completions = 5
|
146 |
+
num_completions = gr.Slider(
|
147 |
+
minimum=1,
|
148 |
+
maximum=10,
|
149 |
+
value=default_num_completions,
|
150 |
+
step=1,
|
151 |
+
label="Number of Completions"
|
152 |
+
)
|
153 |
+
gen_length = gr.Slider(
|
154 |
+
minimum=5,
|
155 |
+
maximum=60,
|
156 |
+
value=20,
|
157 |
+
step=5,
|
158 |
+
label="Generation Length (seconds)"
|
159 |
+
)
|
160 |
+
|
161 |
+
with gr.Row():
|
162 |
+
token_temp = gr.Slider(
|
163 |
+
minimum=0.1,
|
164 |
+
maximum=1.0,
|
165 |
+
value=0.8,
|
166 |
+
step=0.1,
|
167 |
+
label="Token Temperature"
|
168 |
+
)
|
169 |
+
cat_temp = gr.Slider(
|
170 |
+
minimum=0.1,
|
171 |
+
maximum=1.0,
|
172 |
+
value=0.5,
|
173 |
+
step=0.1,
|
174 |
+
label="Categorical Temperature"
|
175 |
+
)
|
176 |
+
gauss_temp = gr.Slider(
|
177 |
+
minimum=0.1,
|
178 |
+
maximum=1.0,
|
179 |
+
value=0.1,
|
180 |
+
step=0.1,
|
181 |
+
label="Gaussian Temperature"
|
182 |
+
)
|
183 |
+
|
184 |
+
generate_btn = gr.Button("Generate Completions")
|
185 |
+
status_text = gr.Markdown("Ready")
|
186 |
+
|
187 |
+
with gr.Column():
|
188 |
+
output_audios = []
|
189 |
+
for i in range(10): # Create 10 audio components
|
190 |
+
output_audios.append(gr.Audio(
|
191 |
+
label=f"Generated Completion {i+1}",
|
192 |
+
type="numpy",
|
193 |
+
visible=False
|
194 |
+
))
|
195 |
+
|
196 |
+
def update_visibility(num):
|
197 |
+
return [gr.update(visible=(i < num)) for i in range(10)]
|
198 |
+
|
199 |
+
def generate_with_status(*args):
|
200 |
+
status_text.value = "Processing input audio..."
|
201 |
+
completions = generate_completion(*args)
|
202 |
+
status_text.value = "Generation complete!"
|
203 |
+
|
204 |
+
# Prepare outputs for all audio components
|
205 |
+
outputs = []
|
206 |
+
for i in range(10):
|
207 |
+
if i < len(completions):
|
208 |
+
outputs.append(completions[i])
|
209 |
+
else:
|
210 |
+
outputs.append(None)
|
211 |
+
return outputs
|
212 |
+
|
213 |
+
# Set initial visibility on load
|
214 |
+
app.load(
|
215 |
+
fn=update_visibility,
|
216 |
+
inputs=[num_completions],
|
217 |
+
outputs=output_audios
|
218 |
+
)
|
219 |
+
|
220 |
+
# Update visibility when slider changes
|
221 |
+
num_completions.change(
|
222 |
+
fn=update_visibility,
|
223 |
+
inputs=[num_completions],
|
224 |
+
outputs=output_audios
|
225 |
+
)
|
226 |
+
|
227 |
+
generate_btn.click(
|
228 |
+
fn=generate_with_status,
|
229 |
+
inputs=[
|
230 |
+
audio_input,
|
231 |
+
prompt_len,
|
232 |
+
num_completions,
|
233 |
+
gen_length,
|
234 |
+
token_temp,
|
235 |
+
cat_temp,
|
236 |
+
gauss_temp
|
237 |
+
],
|
238 |
+
outputs=output_audios
|
239 |
+
)
|
240 |
+
|
241 |
+
return app
|
242 |
+
|
243 |
+
if __name__ == "__main__":
|
244 |
+
app = create_interface()
|
245 |
+
app.launch(share=True)
|
ioblocks.py
ADDED
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
from functools import partial
|
3 |
+
from contextlib import nullcontext
|
4 |
+
from typing import List, Tuple
|
5 |
+
from math import ceil
|
6 |
+
|
7 |
+
import torch as T
|
8 |
+
import torch.nn as nn
|
9 |
+
import torch.nn.functional as F
|
10 |
+
import torch.distributed as dist
|
11 |
+
from torch import Tensor, int32
|
12 |
+
from torch.amp import autocast
|
13 |
+
|
14 |
+
from einops import rearrange, pack, unpack
|
15 |
+
|
16 |
+
|
17 |
+
from utils import si_module, exists, default, maybe
|
18 |
+
|
19 |
+
|
20 |
+
@si_module
|
21 |
+
class GaussianMixtureIOLayer(nn.Module):
|
22 |
+
class Config:
|
23 |
+
latent_dim: int
|
24 |
+
dim: int
|
25 |
+
num_components: int
|
26 |
+
|
27 |
+
def __init__(self, c: Config):
|
28 |
+
super().__init__()
|
29 |
+
self.latent_dim = c.latent_dim
|
30 |
+
self.num_components = c.num_components
|
31 |
+
self.input_projection = nn.Linear(c.latent_dim, c.dim)
|
32 |
+
|
33 |
+
self.fc_loc = nn.Linear(c.dim, c.num_components * c.latent_dim)
|
34 |
+
self.fc_scale = nn.Linear(c.dim, c.num_components * c.latent_dim)
|
35 |
+
self.fc_weight = nn.Linear(c.dim, c.num_components)
|
36 |
+
|
37 |
+
def _square_plus(self, x):
|
38 |
+
return (x + T.sqrt(T.square(x) + 4)) / 2
|
39 |
+
|
40 |
+
def input(self, sampled_latents: T.Tensor) -> T.Tensor:
|
41 |
+
"""Pre-sampled latents T.Tensor (B, L, Z) -> float tensor (B, L, D)"""
|
42 |
+
hidden = self.input_projection(sampled_latents)
|
43 |
+
return hidden
|
44 |
+
|
45 |
+
def output(self, h: T.Tensor) -> Tuple[T.Tensor, T.Tensor, T.Tensor]:
|
46 |
+
"""float tensor (B, L, D) -> Tuple of locs, scales, and weights"""
|
47 |
+
batch_size, seq_len, _ = h.shape
|
48 |
+
|
49 |
+
locs = self.fc_loc(h).view(batch_size, seq_len, self.num_components, self.latent_dim)
|
50 |
+
scales = T.clamp(self._square_plus(self.fc_scale(h)), min=1e-6).view(batch_size, seq_len, self.num_components, self.latent_dim)
|
51 |
+
weights = self.fc_weight(h).view(batch_size, seq_len, self.num_components)
|
52 |
+
|
53 |
+
return (locs, scales, weights)
|
54 |
+
|
55 |
+
def loss(self, data, dataHat):
|
56 |
+
locs, scales, weights = dataHat
|
57 |
+
log_probs = -0.5 * T.sum(
|
58 |
+
(data.unsqueeze(-2) - locs).pow(2) / scales.pow(2) +
|
59 |
+
2 * T.log(scales) +
|
60 |
+
T.log(T.tensor(2 * T.pi)),
|
61 |
+
dim=-1
|
62 |
+
)
|
63 |
+
log_weights = F.log_softmax(weights, dim=-1)
|
64 |
+
return -T.logsumexp(log_weights + log_probs, dim=-1)
|
65 |
+
|
66 |
+
|
67 |
+
def temp_sample(self, orig_pdist, temp):
|
68 |
+
locs, scales, weights = orig_pdist
|
69 |
+
if temp is None:
|
70 |
+
component_samples = locs + scales * T.randn_like(scales)
|
71 |
+
mixture_samples = F.gumbel_softmax(weights, hard=True)
|
72 |
+
sampled = (component_samples * mixture_samples.unsqueeze(-1)).sum(dim=-2)
|
73 |
+
elif isinstance(temp, tuple):
|
74 |
+
assert len(temp) == 2
|
75 |
+
categorical_temp, gaussian_temp = temp
|
76 |
+
component_samples = locs + scales * gaussian_temp * T.randn_like(scales)
|
77 |
+
mixture_samples = F.gumbel_softmax(weights / categorical_temp, hard=True)
|
78 |
+
sampled = (component_samples * mixture_samples.unsqueeze(-1)).sum(dim=-2)
|
79 |
+
else:
|
80 |
+
component_samples = locs + scales * temp * T.randn_like(scales)
|
81 |
+
mixture_samples = F.gumbel_softmax(weights / temp, hard=True)
|
82 |
+
sampled = (component_samples * mixture_samples.unsqueeze(-1)).sum(dim=-2)
|
83 |
+
return sampled
|
84 |
+
|
85 |
+
|
86 |
+
class GPTOutput(nn.Module):
|
87 |
+
def __init__(self, dim, vocab_size):
|
88 |
+
super().__init__()
|
89 |
+
self.output = nn.Linear(dim, vocab_size, bias=False)
|
90 |
+
|
91 |
+
def forward(self, x):
|
92 |
+
return self.output(x)
|
93 |
+
|
94 |
+
|
95 |
+
# helper functions
|
96 |
+
|
97 |
+
def pack_one(t, pattern):
|
98 |
+
return pack([t], pattern)
|
99 |
+
|
100 |
+
def unpack_one(t, ps, pattern):
|
101 |
+
return unpack(t, ps, pattern)[0]
|
102 |
+
|
103 |
+
def first(l):
|
104 |
+
return l[0]
|
105 |
+
|
106 |
+
def round_up_multiple(num, mult):
|
107 |
+
return ceil(num / mult) * mult
|
108 |
+
|
109 |
+
def get_code_utilization(codes, codebook_size, get_global=False):
|
110 |
+
if get_global and dist.is_initialized():
|
111 |
+
world_size = dist.get_world_size()
|
112 |
+
else:
|
113 |
+
world_size = 1
|
114 |
+
|
115 |
+
if world_size > 1:
|
116 |
+
gathered_tokens = [T.zeros_like(codes) for _ in range(world_size)]
|
117 |
+
dist.all_gather(gathered_tokens, codes)
|
118 |
+
gathered_tokens = T.cat(gathered_tokens, dim=0)
|
119 |
+
else:
|
120 |
+
gathered_tokens = codes
|
121 |
+
unique_tokens = len(T.unique(gathered_tokens))
|
122 |
+
code_utilization = unique_tokens / min(gathered_tokens.numel(), codebook_size)
|
123 |
+
return code_utilization
|
124 |
+
|
125 |
+
# tensor helpers
|
126 |
+
|
127 |
+
def round_ste(z: Tensor) -> Tensor:
|
128 |
+
"""Round with straight through gradients."""
|
129 |
+
zhat = z.round()
|
130 |
+
return z + (zhat - z).detach()
|
131 |
+
|
132 |
+
# main class
|
133 |
+
# lucidrains fsq
|
134 |
+
@si_module
|
135 |
+
class FSQ(nn.Module):
|
136 |
+
@property
|
137 |
+
def needs_float32_params(self):
|
138 |
+
return True
|
139 |
+
|
140 |
+
class Config:
|
141 |
+
levels: List[int]
|
142 |
+
dim: int | None = None
|
143 |
+
num_codebooks: int = 1
|
144 |
+
keep_num_codebooks_dim: bool | None = None
|
145 |
+
scale: float | None = None
|
146 |
+
allowed_dtypes: Tuple[str, ...] = ('float32', 'float64')
|
147 |
+
channel_first: bool = False
|
148 |
+
projection_has_bias: bool = True
|
149 |
+
return_indices: bool = True
|
150 |
+
force_quantization_f32: bool = True
|
151 |
+
use_rms: bool = False
|
152 |
+
|
153 |
+
def __init__(self, c: Config):
|
154 |
+
super().__init__()
|
155 |
+
_levels = T.tensor(c.levels, dtype=int32)
|
156 |
+
self.register_buffer("_levels", _levels, persistent = False)
|
157 |
+
|
158 |
+
_basis = T.cumprod(T.tensor([1] + c.levels[:-1]), dim=0, dtype=int32)
|
159 |
+
self.register_buffer("_basis", _basis, persistent = False)
|
160 |
+
|
161 |
+
self.scale = c.scale
|
162 |
+
|
163 |
+
codebook_dim = len(c.levels)
|
164 |
+
self.codebook_dim = codebook_dim
|
165 |
+
|
166 |
+
effective_codebook_dim = codebook_dim * c.num_codebooks
|
167 |
+
self.num_codebooks = c.num_codebooks
|
168 |
+
|
169 |
+
self.allowed_dtypes = []
|
170 |
+
for dtype_str in c.allowed_dtypes:
|
171 |
+
if hasattr(T, dtype_str):
|
172 |
+
self.allowed_dtypes.append(getattr(T, dtype_str))
|
173 |
+
else:
|
174 |
+
raise ValueError(f"Invalid dtype string: {dtype_str}")
|
175 |
+
|
176 |
+
self.effective_codebook_dim = effective_codebook_dim
|
177 |
+
|
178 |
+
keep_num_codebooks_dim = default(c.keep_num_codebooks_dim, c.num_codebooks > 1)
|
179 |
+
assert not (c.num_codebooks > 1 and not keep_num_codebooks_dim)
|
180 |
+
self.keep_num_codebooks_dim = keep_num_codebooks_dim
|
181 |
+
|
182 |
+
self.dim = default(c.dim, len(_levels) * c.num_codebooks)
|
183 |
+
|
184 |
+
self.channel_first = c.channel_first
|
185 |
+
|
186 |
+
has_projections = self.dim != effective_codebook_dim
|
187 |
+
self.project_in = nn.Linear(self.dim, effective_codebook_dim, bias = c.projection_has_bias) if has_projections else nn.Identity()
|
188 |
+
self.project_out = nn.Linear(effective_codebook_dim, self.dim, bias = c.projection_has_bias) if has_projections else nn.Identity()
|
189 |
+
|
190 |
+
self.has_projections = has_projections
|
191 |
+
|
192 |
+
self.return_indices = c.return_indices
|
193 |
+
if c.return_indices:
|
194 |
+
self.codebook_size = self._levels.prod().item()
|
195 |
+
implicit_codebook = self._indices_to_codes(T.arange(self.codebook_size))
|
196 |
+
self.register_buffer("implicit_codebook", implicit_codebook, persistent = False)
|
197 |
+
|
198 |
+
self.allowed_dtypes = c.allowed_dtypes
|
199 |
+
self.force_quantization_f32 = c.force_quantization_f32
|
200 |
+
|
201 |
+
self.latent_loss = None
|
202 |
+
|
203 |
+
def latent_metric(self, codes, get_global=False):
|
204 |
+
return {'code_util_estimate': get_code_utilization(codes, self.codebook_size, get_global)}
|
205 |
+
|
206 |
+
def repr_from_latent(self, latent):
|
207 |
+
return self.indices_to_codes(latent)
|
208 |
+
|
209 |
+
def bound(self, z, eps: float = 1e-3):
|
210 |
+
""" Bound `z`, an array of shape (..., d). """
|
211 |
+
half_l = (self._levels - 1) * (1 + eps) / 2
|
212 |
+
offset = T.where(self._levels % 2 == 0, 0.5, 0.0)
|
213 |
+
shift = (offset / half_l).atanh()
|
214 |
+
return (z + shift).tanh() * half_l - offset
|
215 |
+
|
216 |
+
def quantize(self, z):
|
217 |
+
""" Quantizes z, returns quantized zhat, same shape as z. """
|
218 |
+
quantized = round_ste(self.bound(z))
|
219 |
+
half_width = self._levels // 2 # Renormalize to [-1, 1].
|
220 |
+
return quantized / half_width
|
221 |
+
|
222 |
+
def _scale_and_shift(self, zhat_normalized):
|
223 |
+
half_width = self._levels // 2
|
224 |
+
return (zhat_normalized * half_width) + half_width
|
225 |
+
|
226 |
+
def _scale_and_shift_inverse(self, zhat):
|
227 |
+
half_width = self._levels // 2
|
228 |
+
return (zhat - half_width) / half_width
|
229 |
+
|
230 |
+
def _indices_to_codes(self, indices):
|
231 |
+
level_indices = self.indices_to_level_indices(indices)
|
232 |
+
codes = self._scale_and_shift_inverse(level_indices)
|
233 |
+
return codes
|
234 |
+
|
235 |
+
def codes_to_indices(self, zhat):
|
236 |
+
""" Converts a `code` to an index in the codebook. """
|
237 |
+
assert zhat.shape[-1] == self.codebook_dim
|
238 |
+
zhat = self._scale_and_shift(zhat)
|
239 |
+
return (zhat * self._basis).sum(dim=-1).to(int32)
|
240 |
+
|
241 |
+
def indices_to_level_indices(self, indices):
|
242 |
+
""" Converts indices to indices at each level, perhaps needed for a transformer with factorized embeddings """
|
243 |
+
indices = rearrange(indices, '... -> ... 1')
|
244 |
+
codes_non_centered = (indices // self._basis) % self._levels
|
245 |
+
return codes_non_centered
|
246 |
+
|
247 |
+
def indices_to_codes(self, indices):
|
248 |
+
""" Inverse of `codes_to_indices`. """
|
249 |
+
assert exists(indices)
|
250 |
+
|
251 |
+
is_img_or_video = indices.ndim >= (3 + int(self.keep_num_codebooks_dim))
|
252 |
+
|
253 |
+
codes = self._indices_to_codes(indices)
|
254 |
+
|
255 |
+
if self.keep_num_codebooks_dim:
|
256 |
+
codes = rearrange(codes, '... c d -> ... (c d)')
|
257 |
+
|
258 |
+
codes = self.project_out(codes)
|
259 |
+
|
260 |
+
if is_img_or_video or self.channel_first:
|
261 |
+
codes = rearrange(codes, 'b ... d -> b d ...')
|
262 |
+
|
263 |
+
return codes
|
264 |
+
|
265 |
+
# @autocast(device_type='cuda', enabled = False)
|
266 |
+
def forward(self, z, return_codes=False):
|
267 |
+
"""
|
268 |
+
einstein notation
|
269 |
+
b - batch
|
270 |
+
n - sequence (or flattened spatial dimensions)
|
271 |
+
d - feature dimension
|
272 |
+
c - number of codebook dim
|
273 |
+
"""
|
274 |
+
|
275 |
+
is_img_or_video = z.ndim >= 4
|
276 |
+
need_move_channel_last = is_img_or_video or self.channel_first
|
277 |
+
|
278 |
+
# standardize image or video into (batch, seq, dimension)
|
279 |
+
|
280 |
+
if need_move_channel_last:
|
281 |
+
z = rearrange(z, 'b d ... -> b ... d')
|
282 |
+
z, ps = pack_one(z, 'b * d')
|
283 |
+
|
284 |
+
assert z.shape[-1] == self.dim, f'expected dimension of {self.dim} but found dimension of {z.shape[-1]}'
|
285 |
+
|
286 |
+
z = self.project_in(z)
|
287 |
+
|
288 |
+
z = rearrange(z, 'b n (c d) -> b n c d', c = self.num_codebooks)
|
289 |
+
|
290 |
+
# whether to force quantization step to be full precision or not
|
291 |
+
|
292 |
+
force_f32 = self.force_quantization_f32
|
293 |
+
quantization_context = partial(autocast, device_type='cuda', enabled = False) if force_f32 else nullcontext
|
294 |
+
|
295 |
+
with quantization_context():
|
296 |
+
orig_dtype = z.dtype
|
297 |
+
|
298 |
+
if force_f32 and orig_dtype not in self.allowed_dtypes:
|
299 |
+
z = z.float()
|
300 |
+
|
301 |
+
codes = self.quantize(z)
|
302 |
+
|
303 |
+
# returning indices could be optional
|
304 |
+
|
305 |
+
indices = None
|
306 |
+
|
307 |
+
if self.return_indices:
|
308 |
+
indices = self.codes_to_indices(codes)
|
309 |
+
|
310 |
+
codes = rearrange(codes, 'b n c d -> b n (c d)')
|
311 |
+
|
312 |
+
codes = codes.type(orig_dtype)
|
313 |
+
|
314 |
+
# project out
|
315 |
+
if return_codes:
|
316 |
+
return codes, indices
|
317 |
+
|
318 |
+
out = self.project_out(codes)
|
319 |
+
|
320 |
+
# reconstitute image or video dimensions
|
321 |
+
|
322 |
+
if need_move_channel_last:
|
323 |
+
out = unpack_one(out, ps, 'b * d')
|
324 |
+
out = rearrange(out, 'b ... d -> b d ...')
|
325 |
+
|
326 |
+
indices = maybe(unpack_one)(indices, ps, 'b * c')
|
327 |
+
|
328 |
+
if not self.keep_num_codebooks_dim and self.return_indices:
|
329 |
+
indices = maybe(rearrange)(indices, '... 1 -> ...')
|
330 |
+
|
331 |
+
# return quantized output and indices
|
332 |
+
|
333 |
+
return out, indices
|
model.py
ADDED
@@ -0,0 +1,443 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Optional, Tuple
|
2 |
+
|
3 |
+
import torch as T
|
4 |
+
import torch.nn as nn
|
5 |
+
import torch.nn.functional as F
|
6 |
+
|
7 |
+
from ioblocks import GaussianMixtureIOLayer, FSQ
|
8 |
+
|
9 |
+
from transformer import Stack, ShapeRotator, Block as PerfBlock, GPTOutput, CACHE_FILL_VALUE, FFNN, Norm
|
10 |
+
from tokenizer import make_tokenizer
|
11 |
+
|
12 |
+
|
13 |
+
from utils import si_module, exists, isnt, tqdm0, print0, default, print0_colored
|
14 |
+
from utils import load_ckpt
|
15 |
+
|
16 |
+
|
17 |
+
@si_module
|
18 |
+
class LatentQuantizer(nn.Module):
|
19 |
+
class Config:
|
20 |
+
compressor_config: Optional[FSQ.Config] = None
|
21 |
+
|
22 |
+
dim: Optional[int] = None
|
23 |
+
ff_dim: Optional[int] = None
|
24 |
+
input_dim: int = None
|
25 |
+
|
26 |
+
from_pretrained: Optional[Tuple[str, str]] = None
|
27 |
+
|
28 |
+
def __init__(self, c: Config):
|
29 |
+
super().__init__()
|
30 |
+
|
31 |
+
if exists(c.from_pretrained):
|
32 |
+
checkpoint = load_ckpt(*c.from_pretrained)
|
33 |
+
else:
|
34 |
+
assert exists(c.compressor_config), f'hmm {c}'
|
35 |
+
|
36 |
+
self.compressor = c.compressor_config()
|
37 |
+
self.ffnn = FFNN(c.dim, c.ff_dim)
|
38 |
+
self.input = nn.Linear(c.input_dim, c.dim) if exists(c.input_dim) else nn.Identity()
|
39 |
+
|
40 |
+
if exists(c.from_pretrained):
|
41 |
+
self.load_state_dict(checkpoint)
|
42 |
+
|
43 |
+
@T.no_grad()
|
44 |
+
def forward(self, x, return_latent=False, known_latent=None):
|
45 |
+
"""
|
46 |
+
x: (B, S, D)
|
47 |
+
"""
|
48 |
+
if exists(known_latent):
|
49 |
+
return self.compressor.indices_to_codes(known_latent)
|
50 |
+
|
51 |
+
x = self.input(x)
|
52 |
+
x = self.ffnn(x)
|
53 |
+
x, tokens = self.compressor(x)
|
54 |
+
|
55 |
+
if return_latent:
|
56 |
+
return x, tokens
|
57 |
+
return x
|
58 |
+
|
59 |
+
|
60 |
+
@si_module
|
61 |
+
class TransformerVAE(nn.Module):
|
62 |
+
class Config:
|
63 |
+
io_config: Optional[GaussianMixtureIOLayer.Config] = None
|
64 |
+
stack_config: Optional[Stack.Config] = None
|
65 |
+
quantizer_config: Optional[LatentQuantizer.Config] = None
|
66 |
+
|
67 |
+
plex_layer: int = None
|
68 |
+
plex_roll: int = 1
|
69 |
+
split: bool = True
|
70 |
+
|
71 |
+
from_pretrained: Optional[Tuple[str, str]] = None
|
72 |
+
|
73 |
+
def __init__(self, c: Config):
|
74 |
+
super().__init__()
|
75 |
+
|
76 |
+
if exists(c.from_pretrained):
|
77 |
+
checkpoint = load_ckpt(*c.from_pretrained)
|
78 |
+
else:
|
79 |
+
assert (exists(c.io_config) and exists(c.stack_config) and exists(c.quantizer_config)), f'hmm {c}'
|
80 |
+
|
81 |
+
self.io = c.io_config()
|
82 |
+
self.stack = c.stack_config()
|
83 |
+
|
84 |
+
self.plex_layer = c.stack_config.layers//2
|
85 |
+
self.plex_roll = c.plex_roll
|
86 |
+
self.plex_dim = c.quantizer_config.dim
|
87 |
+
|
88 |
+
assert self.plex_dim is not None and c.stack_config.dim is not None, f'One of the following are None: self.plex_dim: {self.plex_dim}, c.stack_config.dim: {c.stack_config.dim}'
|
89 |
+
self.plex_projection = nn.Linear(self.plex_dim, c.stack_config.dim)
|
90 |
+
self.out_norm = Norm(c.stack_config.dim)
|
91 |
+
|
92 |
+
if c.split:
|
93 |
+
self.io2 = c.io_config()
|
94 |
+
self.plex_projection2 = nn.Linear(self.plex_dim, c.stack_config.dim)
|
95 |
+
|
96 |
+
self.io2.fc_loc = None
|
97 |
+
self.io2.fc_scale = None
|
98 |
+
self.io2.fc_weight = None
|
99 |
+
|
100 |
+
kv_heads = c.stack_config.kv_heads or c.stack_config.n_head
|
101 |
+
head_dim = c.stack_config.dim // c.stack_config.n_head
|
102 |
+
self.cache_num_layers = c.stack_config.layers + ((c.stack_config.layers - self.plex_layer) if c.split else 0)
|
103 |
+
cache_shape = [self.cache_num_layers, c.stack_config.seq_len, 2, kv_heads, head_dim]
|
104 |
+
self.cache_shape = cache_shape
|
105 |
+
self.cache = [None] * self.cache_num_layers
|
106 |
+
|
107 |
+
if exists(c.from_pretrained):
|
108 |
+
result = self.load_state_dict(checkpoint, strict=False)
|
109 |
+
print0_colored(result, 'yellow')
|
110 |
+
|
111 |
+
self.quantizer = c.quantizer_config().eval()
|
112 |
+
self.quantizer.requires_grad = False
|
113 |
+
|
114 |
+
@T.no_grad()
|
115 |
+
def quantize(self, x):
|
116 |
+
if self.c.split:
|
117 |
+
x1, x2 = x.chunk(2, dim=-1)
|
118 |
+
with T.autocast(device_type='cuda', dtype=T.bfloat16):
|
119 |
+
quantized1 = self.quantizer(x1)
|
120 |
+
quantized2 = self.quantizer(x2)
|
121 |
+
return quantized1, quantized2
|
122 |
+
else:
|
123 |
+
with T.autocast(device_type='cuda', dtype=T.bfloat16):
|
124 |
+
return self.quantizer(x)
|
125 |
+
|
126 |
+
@T.no_grad()
|
127 |
+
def untokenize(self, token_data):
|
128 |
+
return self.quantizer(None, known_latent=token_data)
|
129 |
+
|
130 |
+
def init_cache(self, bsize, device, dtype, length:int=None):
|
131 |
+
cache_shape = self.cache_shape.copy()
|
132 |
+
cache_shape[1] = length or cache_shape[1]
|
133 |
+
self.cache = T.full((bsize, *cache_shape), CACHE_FILL_VALUE, device=device, dtype=dtype).transpose(0, 1)
|
134 |
+
|
135 |
+
def deinit_cache(self):
|
136 |
+
self.cache = [None] * self.cache_num_layers
|
137 |
+
|
138 |
+
@T.no_grad()
|
139 |
+
def forward(self, data, next_tokens: Optional[Tuple[T.Tensor, T.Tensor]] = None, temps: Optional[Tuple[float, Tuple[float, float]]] = None):
|
140 |
+
if self.c.split:
|
141 |
+
x1, x2 = data.chunk(2, dim=-1)
|
142 |
+
x = self.io.input(x1) + self.io2.input(x2)
|
143 |
+
else:
|
144 |
+
x = self.io.input(data)
|
145 |
+
|
146 |
+
cache_idx = 0
|
147 |
+
for l, layer in enumerate(self.stack.layers):
|
148 |
+
if l == self.plex_layer:
|
149 |
+
if self.c.split:
|
150 |
+
plex1, plex2 = self.quantize(data)
|
151 |
+
plex1 = T.roll(plex1, -self.c.plex_roll, dims=1)
|
152 |
+
plex2 = T.roll(plex2, -self.c.plex_roll, dims=1)
|
153 |
+
if exists(next_tokens):
|
154 |
+
plex1[:, -1:] = self.untokenize(next_tokens[0])
|
155 |
+
plex2[:, -1:] = self.untokenize(next_tokens[1])
|
156 |
+
x1 = x + self.plex_projection(plex1)
|
157 |
+
x2 = x + self.plex_projection2(plex2)
|
158 |
+
else:
|
159 |
+
plex = self.quantize(data)
|
160 |
+
plex = T.roll(plex, -self.c.plex_roll, dims=1)
|
161 |
+
if exists(next_tokens):
|
162 |
+
plex[:, -1:] = self.untokenize(next_tokens)
|
163 |
+
x = x + self.plex_projection(plex)
|
164 |
+
|
165 |
+
if l < self.plex_layer:
|
166 |
+
x = layer(x, kv=self.cache[l])
|
167 |
+
else:
|
168 |
+
if self.c.split:
|
169 |
+
x1 = layer(x1, kv=self.cache[self.plex_layer + cache_idx])
|
170 |
+
cache_idx += 1
|
171 |
+
x2 = layer(x2, kv=self.cache[self.plex_layer + cache_idx])
|
172 |
+
cache_idx += 1
|
173 |
+
else:
|
174 |
+
x = layer(x, kv=self.cache[l])
|
175 |
+
|
176 |
+
with T.autocast(device_type='cuda', dtype=T.bfloat16):
|
177 |
+
if self.c.split:
|
178 |
+
x1, x2 = self.out_norm(x1), self.out_norm(x2)
|
179 |
+
out1, out2 = self.io.output(x1), self.io.output(x2)
|
180 |
+
else:
|
181 |
+
x = self.out_norm(x)
|
182 |
+
out = self.io.output(x)
|
183 |
+
|
184 |
+
if isnt(temps):
|
185 |
+
if self.c.split:
|
186 |
+
return out1, out2
|
187 |
+
else:
|
188 |
+
return out
|
189 |
+
else:
|
190 |
+
if self.c.split:
|
191 |
+
next_data1 = self.io.temp_sample(out1, temps)[:, -1:, :]
|
192 |
+
next_data2 = self.io2.temp_sample(out2, temps)[:, -1:, :]
|
193 |
+
next_data = T.cat([next_data1, next_data2], dim=-1)
|
194 |
+
return next_data
|
195 |
+
else:
|
196 |
+
next_data = self.io.temp_sample(out, temps)[:, -1:, :]
|
197 |
+
return next_data
|
198 |
+
|
199 |
+
@si_module
|
200 |
+
class HertzDevModel(nn.Module):
|
201 |
+
class Config:
|
202 |
+
dim: int
|
203 |
+
vocab_size: int
|
204 |
+
stack_config: Optional[Stack.Config] = None
|
205 |
+
latent_size: int = 32
|
206 |
+
|
207 |
+
split: bool = True
|
208 |
+
|
209 |
+
quantizer_config: Optional[LatentQuantizer.Config] = None
|
210 |
+
resynthesizer_config: Optional[TransformerVAE.Config] = None
|
211 |
+
|
212 |
+
from_pretrained: Optional[Tuple[str, str]] = None
|
213 |
+
|
214 |
+
def __init__(self, c: Config):
|
215 |
+
super().__init__()
|
216 |
+
|
217 |
+
if exists(c.from_pretrained):
|
218 |
+
checkpoint = load_ckpt(*c.from_pretrained)
|
219 |
+
else:
|
220 |
+
assert (exists(c.stack_config)), f'hmm {c}'
|
221 |
+
|
222 |
+
self.input = nn.Linear(c.latent_size, c.dim)
|
223 |
+
if self.c.split:
|
224 |
+
self.input2 = nn.Linear(c.latent_size, c.dim)
|
225 |
+
|
226 |
+
self.shape_rotator = ShapeRotator(c.stack_config.dim//c.stack_config.n_head, c.stack_config.seq_len, theta=c.stack_config.theta)
|
227 |
+
|
228 |
+
self.layers = nn.ModuleList([
|
229 |
+
PerfBlock(
|
230 |
+
dim=c.stack_config.dim,
|
231 |
+
layer_id=l,
|
232 |
+
n_head=c.stack_config.n_head,
|
233 |
+
kv_heads=c.stack_config.kv_heads,
|
234 |
+
ff_dim=c.stack_config.ff_dim,
|
235 |
+
eps=c.stack_config.eps,
|
236 |
+
shape_rotator=self.shape_rotator,
|
237 |
+
) for l in range(c.stack_config.layers)
|
238 |
+
])
|
239 |
+
|
240 |
+
self.output = GPTOutput(c.dim, c.vocab_size)
|
241 |
+
if self.c.split:
|
242 |
+
self.output2 = GPTOutput(c.dim, c.vocab_size)
|
243 |
+
|
244 |
+
self.cache = [None] * c.stack_config.layers
|
245 |
+
self.kv_heads = c.stack_config.kv_heads or c.stack_config.n_head
|
246 |
+
self.head_dim = c.stack_config.dim // c.stack_config.n_head
|
247 |
+
|
248 |
+
if exists(c.from_pretrained):
|
249 |
+
result = self.load_state_dict(checkpoint, strict=False)
|
250 |
+
print0_colored(result, 'yellow')
|
251 |
+
|
252 |
+
self.resynthesizer = c.resynthesizer_config().eval()
|
253 |
+
self.resynthesizer.requires_grad = False
|
254 |
+
|
255 |
+
self.audio_tokenizer = make_tokenizer(device='cpu')
|
256 |
+
self.audio_cache = None
|
257 |
+
self.audio_latent_cache = None
|
258 |
+
self.use_audio_cache = False
|
259 |
+
|
260 |
+
@T.no_grad()
|
261 |
+
def tokenize(self, audio_data):
|
262 |
+
orig_audio_shape = audio_data.shape
|
263 |
+
if exists(self.audio_cache):
|
264 |
+
audio_data = T.cat([self.audio_cache, audio_data], dim=-1)
|
265 |
+
self.audio_cache = audio_data[..., -(6*16_000):]
|
266 |
+
elif self.use_audio_cache:
|
267 |
+
self.audio_cache = audio_data[..., -(6*16_000):]
|
268 |
+
|
269 |
+
if audio_data.shape[1] == 2:
|
270 |
+
enc_ch1 = self.audio_tokenizer.latent_from_data(audio_data[:, 0:1])
|
271 |
+
enc_ch2 = self.audio_tokenizer.latent_from_data(audio_data[:, 1:2])
|
272 |
+
return T.cat([enc_ch1, enc_ch2], dim=-1)[:, -(orig_audio_shape[-1]//2000):]
|
273 |
+
else:
|
274 |
+
return self.audio_tokenizer.latent_from_data(audio_data)[:, -(orig_audio_shape[-1]//2000):]
|
275 |
+
|
276 |
+
@T.no_grad()
|
277 |
+
def untokenize(self, token_data):
|
278 |
+
if exists(self.audio_latent_cache):
|
279 |
+
token_data = T.cat([self.audio_latent_cache, token_data], dim=1)
|
280 |
+
self.audio_latent_cache = token_data[:, -(6*8):]
|
281 |
+
elif self.use_audio_cache:
|
282 |
+
self.audio_latent_cache = token_data[:, -(6*8):]
|
283 |
+
|
284 |
+
if token_data.shape[-1] == 2*self.c.latent_size:
|
285 |
+
dec_ch1 = self.audio_tokenizer.data_from_latent(token_data[:, :self.c.latent_size])
|
286 |
+
dec_ch2 = self.audio_tokenizer.data_from_latent(token_data[:, self.c.latent_size:])
|
287 |
+
return T.cat([dec_ch1, dec_ch2], dim=1)[..., -(token_data.shape[1]*2000):]
|
288 |
+
else:
|
289 |
+
return self.audio_tokenizer.data_from_latent(token_data)[..., -(token_data.shape[1]*2000):]
|
290 |
+
|
291 |
+
def init_cache(self, bsize, device, dtype, length:int=None):
|
292 |
+
cache_shape = [self.c.stack_config.layers, length or self.c.stack_config.seq_len, 2, self.kv_heads, self.head_dim]
|
293 |
+
self.cache = T.full((bsize, *cache_shape), CACHE_FILL_VALUE, device=device, dtype=dtype).transpose(0, 1)
|
294 |
+
self.resynthesizer.init_cache(bsize, device, dtype, length)
|
295 |
+
self.use_audio_cache = True
|
296 |
+
|
297 |
+
def deinit_cache(self):
|
298 |
+
self.cache = [None] * len(self.layers)
|
299 |
+
self.resynthesizer.deinit_cache()
|
300 |
+
self.audio_cache = None
|
301 |
+
self.audio_latent_cache = None
|
302 |
+
self.use_audio_cache = False
|
303 |
+
|
304 |
+
@T.no_grad()
|
305 |
+
def forward(self, data):
|
306 |
+
if self.c.split:
|
307 |
+
x1, x2 = data.chunk(2, dim=-1)
|
308 |
+
x = self.input(x1) + self.input2(x2)
|
309 |
+
else:
|
310 |
+
x = self.input(data)
|
311 |
+
|
312 |
+
for l, layer in enumerate(self.layers):
|
313 |
+
x = layer(x, kv=self.cache[l])
|
314 |
+
|
315 |
+
if self.c.split:
|
316 |
+
return self.output(x), self.output2(x)
|
317 |
+
else:
|
318 |
+
return self.output(x)
|
319 |
+
|
320 |
+
@T.no_grad()
|
321 |
+
def next_audio_from_audio(self, audio_data: T.Tensor, temps=(0.8, (0.5, 0.1))):
|
322 |
+
latents_in = self.tokenize(audio_data)
|
323 |
+
next_latents = self.next_latent(latents_in, temps)
|
324 |
+
next_model_latent = next_latents[..., self.c.latent_size:]
|
325 |
+
audio_decoded = self.untokenize(next_model_latent)[..., -2000:]
|
326 |
+
return audio_decoded
|
327 |
+
|
328 |
+
|
329 |
+
@T.no_grad()
|
330 |
+
def next_latent(self, model_input: T.Tensor, temps=(0.8, (0.5, 0.1))):
|
331 |
+
|
332 |
+
if self.c.split:
|
333 |
+
logits1, logits2 = self.forward(model_input)
|
334 |
+
next_logits1 = logits1[:, -1]
|
335 |
+
next_logits2 = logits2[:, -1]
|
336 |
+
next_token1 = F.softmax(next_logits1 / temps[0], dim=-1).multinomial(1)
|
337 |
+
next_token2 = F.softmax(next_logits2 / temps[0], dim=-1).multinomial(1)
|
338 |
+
|
339 |
+
next_input = self.resynthesizer(model_input, next_tokens=(next_token1, next_token2), temps=temps[1])
|
340 |
+
else:
|
341 |
+
logits = self.forward(model_input)
|
342 |
+
next_logits = logits[:, -1]
|
343 |
+
next_token = F.softmax(next_logits / temps[0], dim=-1).multinomial(1)
|
344 |
+
|
345 |
+
next_input = self.resynthesizer(model_input, next_tokens=next_token, temps=temps[1])
|
346 |
+
|
347 |
+
return next_input
|
348 |
+
|
349 |
+
|
350 |
+
@T.no_grad()
|
351 |
+
def completion(self, data: T.Tensor, temps=(0.8, (0.5, 0.1)), gen_len=None, use_cache=True) -> T.Tensor:
|
352 |
+
"""
|
353 |
+
only accepts latent-space data.
|
354 |
+
"""
|
355 |
+
if use_cache:
|
356 |
+
self.init_cache(data.shape[0], data.device, T.bfloat16)
|
357 |
+
|
358 |
+
next_input = generated = data
|
359 |
+
|
360 |
+
target_len = min(data.shape[1] + default(gen_len, data.shape[1]), self.c.stack_config.seq_len)
|
361 |
+
|
362 |
+
for _ in tqdm0(range(data.shape[1], target_len)):
|
363 |
+
model_input = next_input if use_cache else generated
|
364 |
+
|
365 |
+
next_input = self.next_latent(model_input, temps)
|
366 |
+
|
367 |
+
generated = T.cat([generated, next_input], dim=1)
|
368 |
+
|
369 |
+
if use_cache:
|
370 |
+
self.deinit_cache()
|
371 |
+
return generated
|
372 |
+
|
373 |
+
|
374 |
+
|
375 |
+
def get_hertz_dev_config(is_split=True, use_pure_audio_ablation=False):
|
376 |
+
if is_split:
|
377 |
+
checkpoints = [('inference_care_50000', 'e4ff4fe5c7e9f066410d2a5673b7a935'), ('inference_scion_54000', 'cb8bc484423922747b277ebc2933af5d')]
|
378 |
+
elif not use_pure_audio_ablation:
|
379 |
+
checkpoints = [('inference_whip_72000', '5e7cee7316900737d55fc5d44cc7a8f7'), ('inference_caraway_112000', 'fcb8368ef8ebf7712f3e31e6856da580')]
|
380 |
+
else:
|
381 |
+
checkpoints = [('inference_whip_72000', '5e7cee7316900737d55fc5d44cc7a8f7'), ('inference_syrup_110000', '353c48f553f1706824c11f3bb6a049e9')]
|
382 |
+
|
383 |
+
quantizer_config=LatentQuantizer.Config(
|
384 |
+
from_pretrained=('inference_volcano_3', 'd42bf674022c5f84b051d5d7794f6169'),
|
385 |
+
compressor_config=FSQ.Config(
|
386 |
+
levels=[8,8,8,8,8],
|
387 |
+
dim=2048,
|
388 |
+
num_codebooks=1,
|
389 |
+
keep_num_codebooks_dim=None,
|
390 |
+
scale=None,
|
391 |
+
allowed_dtypes=['float32', 'float64', 'bfloat16'],
|
392 |
+
channel_first=False,
|
393 |
+
projection_has_bias=True,
|
394 |
+
return_indices=True,
|
395 |
+
force_quantization_f32=True,
|
396 |
+
use_rms=False
|
397 |
+
),
|
398 |
+
dim=2048,
|
399 |
+
ff_dim=8192,
|
400 |
+
input_dim=32
|
401 |
+
)
|
402 |
+
|
403 |
+
resynthesizer_config=TransformerVAE.Config(
|
404 |
+
io_config=GaussianMixtureIOLayer.Config(
|
405 |
+
latent_dim=32,
|
406 |
+
dim=4096,
|
407 |
+
num_components=8,
|
408 |
+
),
|
409 |
+
stack_config=Stack.Config(
|
410 |
+
layers=8,
|
411 |
+
dim=4096,
|
412 |
+
seq_len=8192,
|
413 |
+
n_head=16,
|
414 |
+
ff_dim=11008,
|
415 |
+
kv_heads=16,
|
416 |
+
eps=1e-5,
|
417 |
+
theta=10_000
|
418 |
+
),
|
419 |
+
quantizer_config=quantizer_config,
|
420 |
+
plex_layer=None,
|
421 |
+
plex_roll=1,
|
422 |
+
split=is_split,
|
423 |
+
from_pretrained=checkpoints[0],
|
424 |
+
)
|
425 |
+
|
426 |
+
return HertzDevModel.Config(
|
427 |
+
dim=4096,
|
428 |
+
vocab_size=32_768,
|
429 |
+
stack_config=Stack.Config(
|
430 |
+
layers=32,
|
431 |
+
dim=4096,
|
432 |
+
seq_len=2048,
|
433 |
+
n_head=32,
|
434 |
+
ff_dim=None,
|
435 |
+
kv_heads=None,
|
436 |
+
eps=1e-5,
|
437 |
+
theta=10_000,
|
438 |
+
),
|
439 |
+
quantizer_config=quantizer_config,
|
440 |
+
resynthesizer_config=resynthesizer_config,
|
441 |
+
split=is_split,
|
442 |
+
from_pretrained=checkpoints[1],
|
443 |
+
)
|
requirements.txt
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
torch==2.5.1
|
2 |
+
torchaudio==2.5.1
|
3 |
+
einops==0.8.0
|
4 |
+
tqdm==4.66.6
|
5 |
+
ipython==8.29.0
|
6 |
+
numpy==1.26.3
|
7 |
+
soundfile==0.12.1
|
8 |
+
websockets==13.1
|
9 |
+
requests==2.32.3
|
10 |
+
sounddevice==0.5.1
|
11 |
+
matplotlib==3.9.2
|
12 |
+
fastapi==0.115.4
|
13 |
+
uvicorn==0.32.0
|
14 |
+
gradio==5.5.0
|
tokenizer.py
ADDED
@@ -0,0 +1,581 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
from dataclasses import dataclass
|
3 |
+
from typing import Union, Tuple, Literal
|
4 |
+
|
5 |
+
import torch as T
|
6 |
+
import torch.nn as nn
|
7 |
+
from torch.nn.utils.parametrizations import weight_norm
|
8 |
+
|
9 |
+
from utils import load_ckpt
|
10 |
+
from utils.interp import print_colored
|
11 |
+
from utils import si_module, get_activation
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# Adapted from https://github.com/facebookresearch/AudioDec
|
16 |
+
|
17 |
+
def Conv1d1x1(in_channels, out_channels, bias=True):
|
18 |
+
return nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=bias)
|
19 |
+
|
20 |
+
|
21 |
+
class NonCausalConv1d(nn.Module):
|
22 |
+
"""1D noncausal convolution w/ 2-sides padding."""
|
23 |
+
|
24 |
+
def __init__(
|
25 |
+
self,
|
26 |
+
in_channels,
|
27 |
+
out_channels,
|
28 |
+
kernel_size,
|
29 |
+
stride=1,
|
30 |
+
padding=-1,
|
31 |
+
dilation=1,
|
32 |
+
groups=1,
|
33 |
+
bias=True):
|
34 |
+
super().__init__()
|
35 |
+
self.in_channels = in_channels
|
36 |
+
self.out_channels = out_channels
|
37 |
+
self.kernel_size = kernel_size
|
38 |
+
if padding < 0:
|
39 |
+
padding = (kernel_size - 1) // 2 * dilation
|
40 |
+
self.dilation = dilation
|
41 |
+
self.conv = nn.Conv1d(
|
42 |
+
in_channels=in_channels,
|
43 |
+
out_channels=out_channels,
|
44 |
+
kernel_size=kernel_size,
|
45 |
+
stride=stride,
|
46 |
+
padding=padding,
|
47 |
+
dilation=dilation,
|
48 |
+
groups=groups,
|
49 |
+
bias=bias,
|
50 |
+
)
|
51 |
+
|
52 |
+
def forward(self, x):
|
53 |
+
"""
|
54 |
+
Args:
|
55 |
+
x (Tensor): Float tensor variable with the shape (B, C, T).
|
56 |
+
Returns:
|
57 |
+
Tensor: Float tensor variable with the shape (B, C, T).
|
58 |
+
"""
|
59 |
+
x = self.conv(x)
|
60 |
+
return x
|
61 |
+
|
62 |
+
|
63 |
+
class NonCausalConvTranspose1d(nn.Module):
|
64 |
+
"""1D noncausal transpose convolution."""
|
65 |
+
|
66 |
+
def __init__(
|
67 |
+
self,
|
68 |
+
in_channels,
|
69 |
+
out_channels,
|
70 |
+
kernel_size,
|
71 |
+
stride,
|
72 |
+
padding=-1,
|
73 |
+
output_padding=-1,
|
74 |
+
groups=1,
|
75 |
+
bias=True,
|
76 |
+
):
|
77 |
+
super().__init__()
|
78 |
+
if padding < 0:
|
79 |
+
padding = (stride+1) // 2
|
80 |
+
if output_padding < 0:
|
81 |
+
output_padding = 1 if stride % 2 else 0
|
82 |
+
self.deconv = nn.ConvTranspose1d(
|
83 |
+
in_channels=in_channels,
|
84 |
+
out_channels=out_channels,
|
85 |
+
kernel_size=kernel_size,
|
86 |
+
stride=stride,
|
87 |
+
padding=padding,
|
88 |
+
output_padding=output_padding,
|
89 |
+
groups=groups,
|
90 |
+
bias=bias,
|
91 |
+
)
|
92 |
+
|
93 |
+
def forward(self, x):
|
94 |
+
"""
|
95 |
+
Args:
|
96 |
+
x (Tensor): Float tensor variable with the shape (B, C, T).
|
97 |
+
Returns:
|
98 |
+
Tensor: Float tensor variable with the shape (B, C', T').
|
99 |
+
"""
|
100 |
+
x = self.deconv(x)
|
101 |
+
return x
|
102 |
+
|
103 |
+
|
104 |
+
class CausalConv1d(NonCausalConv1d):
|
105 |
+
def __init__(
|
106 |
+
self,
|
107 |
+
in_channels,
|
108 |
+
out_channels,
|
109 |
+
kernel_size,
|
110 |
+
stride=1,
|
111 |
+
dilation=1,
|
112 |
+
groups=1,
|
113 |
+
bias=True
|
114 |
+
):
|
115 |
+
super(CausalConv1d, self).__init__(
|
116 |
+
in_channels=in_channels,
|
117 |
+
out_channels=out_channels,
|
118 |
+
kernel_size=kernel_size,
|
119 |
+
stride=stride,
|
120 |
+
padding=0,
|
121 |
+
dilation=dilation,
|
122 |
+
groups=groups,
|
123 |
+
bias=bias,
|
124 |
+
)
|
125 |
+
self.stride = stride
|
126 |
+
self.pad_length = (kernel_size - 1) * dilation
|
127 |
+
def forward(self, x):
|
128 |
+
pad = nn.ConstantPad1d((self.pad_length, 0), 0.0)
|
129 |
+
x = pad(x)
|
130 |
+
return self.conv(x)
|
131 |
+
|
132 |
+
|
133 |
+
class CausalConvTranspose1d(NonCausalConvTranspose1d):
|
134 |
+
def __init__(
|
135 |
+
self,
|
136 |
+
in_channels,
|
137 |
+
out_channels,
|
138 |
+
kernel_size,
|
139 |
+
stride,
|
140 |
+
bias=True,
|
141 |
+
pad_buffer=None,
|
142 |
+
):
|
143 |
+
super(CausalConvTranspose1d, self).__init__(
|
144 |
+
in_channels=in_channels,
|
145 |
+
out_channels=out_channels,
|
146 |
+
kernel_size=kernel_size,
|
147 |
+
stride=stride,
|
148 |
+
padding=0,
|
149 |
+
output_padding=0,
|
150 |
+
bias=bias,
|
151 |
+
)
|
152 |
+
self.stride = stride
|
153 |
+
self.pad_length = (math.ceil(kernel_size/stride) - 1)
|
154 |
+
if pad_buffer is None:
|
155 |
+
pad_buffer = T.zeros(1, in_channels, self.pad_length)
|
156 |
+
self.register_buffer("pad_buffer", pad_buffer)
|
157 |
+
|
158 |
+
def forward(self, x):
|
159 |
+
pad = nn.ReplicationPad1d((self.pad_length, 0))
|
160 |
+
x = pad(x)
|
161 |
+
return self.deconv(x)[:, :, self.stride : -self.stride]
|
162 |
+
|
163 |
+
def inference(self, x):
|
164 |
+
x = T.cat((self.pad_buffer, x), -1)
|
165 |
+
self.pad_buffer = x[:, :, -self.pad_length:]
|
166 |
+
return self.deconv(x)[:, :, self.stride : -self.stride]
|
167 |
+
|
168 |
+
def reset_buffer(self):
|
169 |
+
self.pad_buffer.zero_()
|
170 |
+
|
171 |
+
|
172 |
+
class NonCausalResUnit(nn.Module):
|
173 |
+
def __init__(
|
174 |
+
self,
|
175 |
+
in_channels,
|
176 |
+
out_channels,
|
177 |
+
kernel_size=7,
|
178 |
+
dilation=1,
|
179 |
+
bias=False,
|
180 |
+
):
|
181 |
+
super().__init__()
|
182 |
+
self.activation = nn.ELU()
|
183 |
+
self.conv1 = NonCausalConv1d(
|
184 |
+
in_channels=in_channels,
|
185 |
+
out_channels=out_channels,
|
186 |
+
kernel_size=kernel_size,
|
187 |
+
stride=1,
|
188 |
+
dilation=dilation,
|
189 |
+
bias=bias,
|
190 |
+
)
|
191 |
+
self.conv2 = Conv1d1x1(out_channels, out_channels, bias)
|
192 |
+
|
193 |
+
def forward(self, x):
|
194 |
+
y = self.conv1(self.activation(x))
|
195 |
+
y = self.conv2(self.activation(y))
|
196 |
+
return x + y
|
197 |
+
|
198 |
+
|
199 |
+
class CausalResUnit(NonCausalResUnit):
|
200 |
+
def __init__(
|
201 |
+
self,
|
202 |
+
in_channels,
|
203 |
+
out_channels,
|
204 |
+
kernel_size=7,
|
205 |
+
dilation=1,
|
206 |
+
bias=False,
|
207 |
+
):
|
208 |
+
super(CausalResUnit, self).__init__(
|
209 |
+
in_channels=in_channels,
|
210 |
+
out_channels=out_channels,
|
211 |
+
kernel_size=kernel_size,
|
212 |
+
dilation=dilation,
|
213 |
+
bias=bias,
|
214 |
+
)
|
215 |
+
self.conv1 = CausalConv1d(
|
216 |
+
in_channels=in_channels,
|
217 |
+
out_channels=out_channels,
|
218 |
+
kernel_size=kernel_size,
|
219 |
+
stride=1,
|
220 |
+
dilation=dilation,
|
221 |
+
bias=bias,
|
222 |
+
)
|
223 |
+
|
224 |
+
def inference(self, x):
|
225 |
+
y = self.conv1.inference(self.activation(x))
|
226 |
+
y = self.conv2(self.activation(y))
|
227 |
+
return x + y
|
228 |
+
|
229 |
+
|
230 |
+
class ResNetBlock(nn.Module):
|
231 |
+
def __init__(self,
|
232 |
+
in_channels,
|
233 |
+
out_channels,
|
234 |
+
stride,
|
235 |
+
kernel_size=7,
|
236 |
+
dilations=(1, 3, 9),
|
237 |
+
bias=True,
|
238 |
+
mode='encoder',
|
239 |
+
):
|
240 |
+
super().__init__()
|
241 |
+
assert mode in ('encoder', 'decoder'), f"Mode ({mode}) is not supported!"
|
242 |
+
|
243 |
+
self.mode = mode
|
244 |
+
self.stride = stride
|
245 |
+
|
246 |
+
ConvUnit = CausalConv1d if mode == 'encoder' else CausalConvTranspose1d
|
247 |
+
|
248 |
+
res_channels = in_channels if mode == 'encoder' else out_channels
|
249 |
+
|
250 |
+
res_units = [CausalResUnit(
|
251 |
+
res_channels,
|
252 |
+
res_channels,
|
253 |
+
kernel_size=kernel_size,
|
254 |
+
dilation=dilation,
|
255 |
+
) for dilation in dilations]
|
256 |
+
|
257 |
+
if in_channels == out_channels:
|
258 |
+
if mode == 'encoder':
|
259 |
+
self.pool = nn.AvgPool1d(kernel_size=stride, stride=stride)
|
260 |
+
if mode == 'decoder':
|
261 |
+
self.upsample = nn.Upsample(scale_factor=stride, mode='nearest')
|
262 |
+
conv_unit = nn.Conv1d(
|
263 |
+
in_channels=in_channels,
|
264 |
+
out_channels=out_channels,
|
265 |
+
kernel_size=1,
|
266 |
+
bias=bias,
|
267 |
+
) if in_channels != out_channels else nn.Identity()
|
268 |
+
else:
|
269 |
+
conv_unit = ConvUnit(
|
270 |
+
in_channels=in_channels,
|
271 |
+
out_channels=out_channels,
|
272 |
+
kernel_size=(2 * stride),
|
273 |
+
stride=stride,
|
274 |
+
bias=bias,
|
275 |
+
)
|
276 |
+
|
277 |
+
if mode == 'encoder':
|
278 |
+
if in_channels == out_channels:
|
279 |
+
self.res_block = nn.Sequential(*res_units, self.pool, conv_unit)
|
280 |
+
else:
|
281 |
+
self.res_block = nn.Sequential(*res_units, conv_unit)
|
282 |
+
elif mode == 'decoder':
|
283 |
+
if in_channels == out_channels:
|
284 |
+
self.res_block = nn.Sequential(self.upsample, conv_unit, *res_units)
|
285 |
+
else:
|
286 |
+
self.res_block = nn.Sequential(conv_unit, *res_units)
|
287 |
+
|
288 |
+
def forward(self, x):
|
289 |
+
out = x
|
290 |
+
for unit in self.res_block:
|
291 |
+
out = unit(out)
|
292 |
+
return out
|
293 |
+
|
294 |
+
def inference(self, x):
|
295 |
+
for unit in self.res_block:
|
296 |
+
x = unit.inference(x)
|
297 |
+
return x
|
298 |
+
|
299 |
+
|
300 |
+
|
301 |
+
|
302 |
+
@si_module
|
303 |
+
class ResNetStack(nn.Module):
|
304 |
+
"""
|
305 |
+
ResNet encoder or decoder stack. Channel ratios
|
306 |
+
and strides take the default order of from
|
307 |
+
data/io-layer, to the middle of the model.
|
308 |
+
"""
|
309 |
+
class Config:
|
310 |
+
input_channels: int = 1
|
311 |
+
output_channels: int = 1
|
312 |
+
encode_channels: int = 32
|
313 |
+
decode_channel_multiplier: int = 1
|
314 |
+
latent_dim: int = None
|
315 |
+
kernel_size: int = 7
|
316 |
+
bias: bool = True
|
317 |
+
channel_ratios: Tuple[int, ...] = (2, 4, 8, 16)
|
318 |
+
strides: Tuple[int, ...] = (3, 4, 5, 5)
|
319 |
+
mode: Literal['encoder', 'decoder'] = 'encoder'
|
320 |
+
|
321 |
+
def __init__(self, c: Config):
|
322 |
+
super().__init__()
|
323 |
+
assert c.mode in ('encoder', 'decoder'), f"Mode ({c.mode}) is not supported!"
|
324 |
+
|
325 |
+
self.mode = c.mode
|
326 |
+
|
327 |
+
assert len(c.channel_ratios) == len(c.strides)
|
328 |
+
channel_ratios = (1,) + c.channel_ratios
|
329 |
+
strides = c.strides
|
330 |
+
self.middle_channels = c.encode_channels * channel_ratios[-1]
|
331 |
+
if c.mode == 'decoder':
|
332 |
+
channel_ratios = tuple(reversed(channel_ratios))
|
333 |
+
strides = tuple(reversed(strides))
|
334 |
+
|
335 |
+
self.multiplier = c.decode_channel_multiplier if c.mode == 'decoder' else 1
|
336 |
+
res_blocks = [ResNetBlock(
|
337 |
+
c.encode_channels * channel_ratios[s_idx] * self.multiplier,
|
338 |
+
c.encode_channels * channel_ratios[s_idx+1] * self.multiplier,
|
339 |
+
stride,
|
340 |
+
kernel_size=c.kernel_size,
|
341 |
+
bias=c.bias,
|
342 |
+
mode=c.mode,
|
343 |
+
) for s_idx, stride in enumerate(strides)]
|
344 |
+
|
345 |
+
data_conv = CausalConv1d(
|
346 |
+
in_channels=c.input_channels if c.mode == 'encoder' else c.encode_channels * self.multiplier,
|
347 |
+
out_channels=c.encode_channels if c.mode == 'encoder' else c.output_channels,
|
348 |
+
kernel_size=c.kernel_size,
|
349 |
+
stride=1,
|
350 |
+
bias=False,
|
351 |
+
)
|
352 |
+
|
353 |
+
if c.mode == 'encoder':
|
354 |
+
self.res_stack = nn.Sequential(data_conv, *res_blocks)
|
355 |
+
elif c.mode == 'decoder':
|
356 |
+
self.res_stack = nn.Sequential(*res_blocks, data_conv)
|
357 |
+
|
358 |
+
if c.latent_dim is not None:
|
359 |
+
self.latent_proj = Conv1d1x1(self.middle_channels, c.latent_dim, bias=c.bias) if c.mode == 'encoder' else Conv1d1x1(c.latent_dim, self.middle_channels, bias=c.bias)
|
360 |
+
if self.multiplier != 1:
|
361 |
+
self.multiplier_proj = Conv1d1x1(self.middle_channels, self.middle_channels * self.multiplier, bias=c.bias)
|
362 |
+
|
363 |
+
def forward(self, x, return_feats=False):
|
364 |
+
if self.c.latent_dim is not None and self.mode == 'decoder':
|
365 |
+
x = self.latent_proj(x)
|
366 |
+
if self.multiplier != 1:
|
367 |
+
x = self.multiplier_proj(x)
|
368 |
+
|
369 |
+
feats = []
|
370 |
+
for block in self.res_stack:
|
371 |
+
x = block(x)
|
372 |
+
if return_feats:
|
373 |
+
feats.append(x)
|
374 |
+
if self.c.latent_dim is not None and self.mode == 'encoder':
|
375 |
+
x = self.latent_proj(x)
|
376 |
+
if return_feats:
|
377 |
+
feats.append(x)
|
378 |
+
if return_feats:
|
379 |
+
return feats
|
380 |
+
return x
|
381 |
+
|
382 |
+
def inference(self, x):
|
383 |
+
for block in self.res_stack:
|
384 |
+
x = block.inference(x)
|
385 |
+
return x
|
386 |
+
|
387 |
+
def reset_buffer(self):
|
388 |
+
def _reset_buffer(m):
|
389 |
+
if isinstance(m, CausalConv1d) or isinstance(m, CausalConvTranspose1d):
|
390 |
+
m.reset_buffer()
|
391 |
+
self.apply(_reset_buffer)
|
392 |
+
|
393 |
+
def reset_parameters(self):
|
394 |
+
def _reset_parameters(m):
|
395 |
+
if isinstance(m, (nn.Conv1d, nn.ConvTranspose1d)):
|
396 |
+
m.weight.data.normal_(0.0, 0.01)
|
397 |
+
|
398 |
+
self.apply(_reset_parameters)
|
399 |
+
|
400 |
+
|
401 |
+
def apply_weight_norm(self):
|
402 |
+
def _apply_weight_norm(m):
|
403 |
+
if isinstance(m, nn.Conv1d) or isinstance(
|
404 |
+
m, nn.ConvTranspose1d
|
405 |
+
):
|
406 |
+
nn.utils.parametrizations.weight_norm(m)
|
407 |
+
|
408 |
+
self.apply(_apply_weight_norm)
|
409 |
+
|
410 |
+
|
411 |
+
def remove_weight_norm(self):
|
412 |
+
def _remove_weight_norm(m):
|
413 |
+
try:
|
414 |
+
print(m)
|
415 |
+
nn.utils.remove_weight_norm(m)
|
416 |
+
except ValueError: # this module didn't have weight norm
|
417 |
+
return
|
418 |
+
|
419 |
+
self.apply(_remove_weight_norm)
|
420 |
+
|
421 |
+
|
422 |
+
|
423 |
+
@si_module
|
424 |
+
class GaussianZ(nn.Module):
|
425 |
+
class Config:
|
426 |
+
dim: int
|
427 |
+
latent_dim: int
|
428 |
+
bias: bool = False
|
429 |
+
use_weight_norm: bool = False
|
430 |
+
|
431 |
+
def __init__(self, c: Config):
|
432 |
+
super().__init__()
|
433 |
+
|
434 |
+
self.proj_in = nn.Linear(c.dim, c.latent_dim * 2, bias=c.bias)
|
435 |
+
self.proj_out = nn.Linear(c.latent_dim, c.dim, bias=c.bias)
|
436 |
+
|
437 |
+
if c.use_weight_norm:
|
438 |
+
self.proj_in = weight_norm(self.proj_in)
|
439 |
+
self.proj_out = weight_norm(self.proj_out)
|
440 |
+
|
441 |
+
def reparam(self, mu, logvar):
|
442 |
+
std = T.exp(logvar / 2)
|
443 |
+
eps = T.randn_like(std)
|
444 |
+
return mu + eps * std
|
445 |
+
|
446 |
+
def kl_divergence(self, mu, logvar):
|
447 |
+
return T.mean(-0.5 * T.sum(
|
448 |
+
1 + logvar - mu.pow(2) - logvar.exp(),
|
449 |
+
dim=(1, 2))
|
450 |
+
)
|
451 |
+
|
452 |
+
def repr_from_latent(self, latent: Union[dict, T.Tensor]):
|
453 |
+
if isinstance(latent, T.Tensor):
|
454 |
+
z = latent
|
455 |
+
else:
|
456 |
+
z = self.reparam(latent['mu'], latent['logvar'])
|
457 |
+
l = self.proj_out(z)
|
458 |
+
return l
|
459 |
+
|
460 |
+
def forward(self, x: T.Tensor) -> Tuple[T.Tensor, dict]:
|
461 |
+
mu, logvar = self.proj_in(x).chunk(2, dim=-1)
|
462 |
+
kl_div = self.kl_divergence(mu, logvar)
|
463 |
+
z = self.reparam(mu, logvar)
|
464 |
+
xhat = self.proj_out(z)
|
465 |
+
latent = {'mu': mu, 'logvar': logvar, 'z': z, 'kl_divergence': kl_div}
|
466 |
+
return xhat, latent
|
467 |
+
|
468 |
+
|
469 |
+
|
470 |
+
@si_module
|
471 |
+
class WaveCodec(nn.Module):
|
472 |
+
class Config:
|
473 |
+
resnet_config: ResNetStack.Config = None
|
474 |
+
sample_rate: int = 16_000
|
475 |
+
use_weight_norm: bool = False
|
476 |
+
|
477 |
+
compressor_config: dataclass = None
|
478 |
+
|
479 |
+
norm_stddev: float = 1.0
|
480 |
+
|
481 |
+
def __init__(self, c: Config):
|
482 |
+
super().__init__()
|
483 |
+
self.norm_stddev = c.norm_stddev
|
484 |
+
self.encoder = c.resnet_config(mode='encoder')
|
485 |
+
self.sample_rate = c.sample_rate
|
486 |
+
|
487 |
+
self.total_stride = 1
|
488 |
+
for stride in c.resnet_config.strides:
|
489 |
+
self.total_stride *= stride
|
490 |
+
self.tokens_per_second = self.sample_rate / self.total_stride
|
491 |
+
|
492 |
+
self.compressor = c.compressor_config(dim=self.encoder.middle_channels)
|
493 |
+
|
494 |
+
self.decoder = c.resnet_config(mode='decoder')
|
495 |
+
|
496 |
+
if c.use_weight_norm:
|
497 |
+
self.encoder.apply_weight_norm()
|
498 |
+
self.decoder.apply_weight_norm()
|
499 |
+
self.encoder.reset_parameters()
|
500 |
+
self.decoder.reset_parameters()
|
501 |
+
|
502 |
+
def encode(self, data):
|
503 |
+
return self.encoder(data/self.norm_stddev)
|
504 |
+
|
505 |
+
def decode(self, latent):
|
506 |
+
return self.decoder(latent.transpose(1, 2))*self.norm_stddev
|
507 |
+
|
508 |
+
@T.no_grad()
|
509 |
+
def latent_from_data(self, data, get_parameters=False):
|
510 |
+
x = self.encode(data)
|
511 |
+
l_in = x.transpose(1, 2)
|
512 |
+
l, latent = self.compressor(l_in)
|
513 |
+
return latent['z'] if not get_parameters else {
|
514 |
+
'mu': latent['mu'],
|
515 |
+
'logvar': latent['logvar'],
|
516 |
+
'z': latent['z'],
|
517 |
+
}
|
518 |
+
|
519 |
+
@T.no_grad()
|
520 |
+
def data_from_latent(self, latent):
|
521 |
+
l = self.compressor.repr_from_latent(latent)
|
522 |
+
x = self.decode(l)
|
523 |
+
return x
|
524 |
+
|
525 |
+
def process(self, x):
|
526 |
+
return self.latent_from_data(x)
|
527 |
+
|
528 |
+
def unprocess(self, latent):
|
529 |
+
return self.data_from_latent(latent)
|
530 |
+
|
531 |
+
def forward(self, audio_input):
|
532 |
+
x = self.encode(audio_input)
|
533 |
+
|
534 |
+
l_in = x.transpose(1, 2)
|
535 |
+
l, latent = self.compressor(l_in)
|
536 |
+
|
537 |
+
xhat = self.decode(l)
|
538 |
+
return xhat, latent
|
539 |
+
|
540 |
+
|
541 |
+
|
542 |
+
def make_tokenizer(device='cuda'):
|
543 |
+
generator_config = WaveCodec.Config(
|
544 |
+
resnet_config=ResNetStack.Config(
|
545 |
+
input_channels=1,
|
546 |
+
output_channels=1,
|
547 |
+
encode_channels=16,
|
548 |
+
decode_channel_multiplier=4,
|
549 |
+
kernel_size=7,
|
550 |
+
bias=True,
|
551 |
+
channel_ratios=(4, 8, 16, 16, 16, 16),
|
552 |
+
strides=(2, 2, 4, 5, 5, 5),
|
553 |
+
mode=None,
|
554 |
+
),
|
555 |
+
use_weight_norm=True,
|
556 |
+
|
557 |
+
compressor_config=GaussianZ.Config(
|
558 |
+
dim=None,
|
559 |
+
latent_dim=32,
|
560 |
+
|
561 |
+
bias=True,
|
562 |
+
use_weight_norm=True
|
563 |
+
),
|
564 |
+
|
565 |
+
norm_stddev=0.05,
|
566 |
+
)
|
567 |
+
checkpoint = load_ckpt("inference_apatosaurus_95000", expected_hash="ba876edb97b988e9196e449dd176ca97")
|
568 |
+
|
569 |
+
tokenizer = generator_config()
|
570 |
+
|
571 |
+
load_result = tokenizer.load_state_dict(checkpoint, strict=False)
|
572 |
+
print_colored(f"Loaded tokenizer state dict: {load_result}", "grey")
|
573 |
+
|
574 |
+
tokenizer = tokenizer.eval()
|
575 |
+
# Only convert to bfloat16 if using CUDA
|
576 |
+
if device == 'cuda':
|
577 |
+
tokenizer = tokenizer.bfloat16()
|
578 |
+
tokenizer = tokenizer.to(device)
|
579 |
+
tokenizer.requires_grad_ = False
|
580 |
+
return tokenizer
|
581 |
+
|
transformer.py
ADDED
@@ -0,0 +1,382 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Optional, Tuple, MutableMapping
|
2 |
+
from typing import Union
|
3 |
+
import math
|
4 |
+
from contextlib import nullcontext
|
5 |
+
|
6 |
+
import torch
|
7 |
+
import torch as T
|
8 |
+
import torch.nn as nn
|
9 |
+
import torch.nn.functional as F
|
10 |
+
from torch import Tensor
|
11 |
+
from torch.nn.attention import SDPBackend
|
12 |
+
|
13 |
+
from einops import rearrange
|
14 |
+
|
15 |
+
from utils import si_module, default, exists, load_ckpt
|
16 |
+
|
17 |
+
CACHE_FILL_VALUE = -1
|
18 |
+
|
19 |
+
def get_cache_len(cache: Optional[Tensor]) -> int:
|
20 |
+
"""
|
21 |
+
cache: (batch, seq_len, 2, kv_heads, head_dim)
|
22 |
+
"""
|
23 |
+
if cache is None:
|
24 |
+
return 0
|
25 |
+
nonzeros = T.any(cache.flatten(2) != CACHE_FILL_VALUE, dim=-1)
|
26 |
+
length = nonzeros.sum(dim=-1).int()
|
27 |
+
assert T.all(length == length[0])
|
28 |
+
return length[0]
|
29 |
+
|
30 |
+
|
31 |
+
def rotate_half(x):
|
32 |
+
x1, x2 = x.chunk(2, dim=-1)
|
33 |
+
return torch.cat((-x2, x1), dim=-1)
|
34 |
+
|
35 |
+
|
36 |
+
def apply_rotary_pos_emb(x, cos, sin, offset: int = 0):
|
37 |
+
assert (
|
38 |
+
cos.shape[1] >= offset + x.shape[1]
|
39 |
+
), f"Offset and/or input sequence is too large,\
|
40 |
+
\n offset: {offset}, seq_len: {x.shape[1]}, max: {cos.shape[1]}"
|
41 |
+
|
42 |
+
cos_out = cos[:, offset : offset + x.shape[1], :, :]
|
43 |
+
sin_out = sin[:, offset : offset + x.shape[1], :, :]
|
44 |
+
|
45 |
+
return (x * cos_out) + (rotate_half(x) * sin_out)
|
46 |
+
|
47 |
+
|
48 |
+
# Adapted from https://github.com/foundation-model-stack/foundation-model-stack
|
49 |
+
class ShapeRotator:
|
50 |
+
def __init__(
|
51 |
+
self,
|
52 |
+
dim: int,
|
53 |
+
end: int,
|
54 |
+
theta: float = 10_000,
|
55 |
+
):
|
56 |
+
super().__init__()
|
57 |
+
self.dim = dim
|
58 |
+
self.ratio = theta
|
59 |
+
self.cached_freqs: MutableMapping[int, MutableMapping[int, torch.Tensor]] = {}
|
60 |
+
self.max_seq_len_cached: MutableMapping[int, int] = {}
|
61 |
+
self.ntk_scaling = False
|
62 |
+
self.max_seq_len = end
|
63 |
+
|
64 |
+
def compute_freqs_cis(self, device, max_seq_len=None):
|
65 |
+
alpha = 1
|
66 |
+
dev_idx = device.index
|
67 |
+
max_seq_len = default(max_seq_len, self.max_seq_len)
|
68 |
+
|
69 |
+
if dev_idx not in self.cached_freqs:
|
70 |
+
self.cached_freqs[dev_idx] = {}
|
71 |
+
if dev_idx not in self.max_seq_len_cached:
|
72 |
+
self.max_seq_len_cached[dev_idx] = 0
|
73 |
+
|
74 |
+
|
75 |
+
if self.max_seq_len_cached[dev_idx] > 0:
|
76 |
+
return 1
|
77 |
+
max_seq_len = max(max_seq_len, self.max_seq_len)
|
78 |
+
|
79 |
+
if (
|
80 |
+
1 in self.cached_freqs[dev_idx]
|
81 |
+
and max_seq_len <= self.max_seq_len_cached[dev_idx]
|
82 |
+
):
|
83 |
+
return 1
|
84 |
+
|
85 |
+
ratio = self.ratio
|
86 |
+
dim = self.dim
|
87 |
+
|
88 |
+
freqs = 1.0 / (ratio ** (torch.arange(0, dim, 2, device=device).float() / dim))
|
89 |
+
|
90 |
+
t = torch.arange(max_seq_len, device=device, dtype=freqs.dtype)
|
91 |
+
freqs = torch.einsum("i,j->ij", t, freqs)
|
92 |
+
emb = torch.cat((freqs, freqs), dim=-1).to(device)
|
93 |
+
|
94 |
+
cos_to_cache = emb.cos()[None, :, None, :]
|
95 |
+
sin_to_cache = emb.sin()[None, :, None, :]
|
96 |
+
|
97 |
+
self.max_seq_len_cached[dev_idx] = max_seq_len
|
98 |
+
|
99 |
+
self.cached_freqs[dev_idx][alpha] = torch.stack(
|
100 |
+
[
|
101 |
+
cos_to_cache,
|
102 |
+
sin_to_cache,
|
103 |
+
],
|
104 |
+
dim=-1,
|
105 |
+
)
|
106 |
+
|
107 |
+
return alpha
|
108 |
+
|
109 |
+
def rotate(
|
110 |
+
self,
|
111 |
+
q: Tensor,
|
112 |
+
k: Tensor,
|
113 |
+
offset: int = 0,
|
114 |
+
) -> Tuple[Tensor, Tensor]:
|
115 |
+
"""
|
116 |
+
Args
|
117 |
+
----
|
118 |
+
q : torch.Tensor
|
119 |
+
Embedded query tensor, expected size is B x S x H x Eh
|
120 |
+
k : torch.Tensor
|
121 |
+
Embedded query tensor, expected size is B x S x H x Eh
|
122 |
+
"""
|
123 |
+
assert len(q.size()) == 4
|
124 |
+
assert len(k.size()) == 4
|
125 |
+
|
126 |
+
seq_len = self.max_seq_len
|
127 |
+
alpha = self.compute_freqs_cis(q.device, seq_len)
|
128 |
+
freqs = self.cached_freqs[q.device.index][alpha]
|
129 |
+
|
130 |
+
freqs = freqs.float() # 1 L D/2 2 2
|
131 |
+
q_out = apply_rotary_pos_emb(q, freqs[..., 0], freqs[..., 1], offset=offset).type_as(q)
|
132 |
+
k_out = apply_rotary_pos_emb(k, freqs[..., 0], freqs[..., 1], offset=offset).type_as(k)
|
133 |
+
|
134 |
+
return q_out.view_as(q), k_out.view_as(k)
|
135 |
+
|
136 |
+
class Linear(nn.Linear):
|
137 |
+
def __init__(self, *args, **kwargs):
|
138 |
+
super().__init__(*args, **kwargs, bias=False)
|
139 |
+
|
140 |
+
class Norm(nn.Module):
|
141 |
+
def __init__(self,
|
142 |
+
dim: int,
|
143 |
+
eps: float = 1e-5,) -> None:
|
144 |
+
super().__init__()
|
145 |
+
self.eps = eps
|
146 |
+
self.weight = nn.Parameter(T.ones((dim,)))
|
147 |
+
|
148 |
+
def forward(self, input: Tensor) -> Tensor:
|
149 |
+
return F.layer_norm(input, (self.weight.shape[0],), weight=self.weight, bias=None, eps=self.eps)
|
150 |
+
|
151 |
+
|
152 |
+
class FFNN(nn.Module):
|
153 |
+
def __init__(self,
|
154 |
+
dim: int,
|
155 |
+
expand_dim: int = None,):
|
156 |
+
super().__init__()
|
157 |
+
expand_dim = default(expand_dim, 256 * ((int(2 * 4 * dim / 3) + 256 - 1) // 256))
|
158 |
+
self.dim = dim
|
159 |
+
self.expand_dim = expand_dim
|
160 |
+
|
161 |
+
self.gateup_proj = Linear(dim, 2*expand_dim)
|
162 |
+
self.down_proj = Linear(expand_dim, dim)
|
163 |
+
|
164 |
+
def forward(self, x):
|
165 |
+
gate, up = self.gateup_proj(x).chunk(2, dim=-1)
|
166 |
+
return self.down_proj(up * F.silu(gate))
|
167 |
+
|
168 |
+
class GQA(nn.Module):
|
169 |
+
def __init__(self,
|
170 |
+
dim: int,
|
171 |
+
n_head: int,
|
172 |
+
shape_rotator: ShapeRotator,
|
173 |
+
kv_heads: Optional[int] = None,
|
174 |
+
eps: float = 1e-5,
|
175 |
+
causal: bool = True,):
|
176 |
+
super().__init__()
|
177 |
+
self.n_heads = n_head
|
178 |
+
self.kv_heads = default(kv_heads, n_head)
|
179 |
+
self.head_dim = dim // n_head
|
180 |
+
self.causal = causal
|
181 |
+
|
182 |
+
self.proj_qkv = Linear(dim, self.head_dim*(n_head+2*self.kv_heads))
|
183 |
+
|
184 |
+
self.norm_q = Norm(self.head_dim*n_head, eps=eps)
|
185 |
+
self.norm_k = Norm(self.head_dim*self.kv_heads, eps=eps)
|
186 |
+
|
187 |
+
self.attn_out = Linear(dim, dim)
|
188 |
+
|
189 |
+
self.shape_rotator = shape_rotator
|
190 |
+
|
191 |
+
def _sdpa(self, q: Tensor, k: Tensor, v: Tensor) -> Tensor:
|
192 |
+
k = k.repeat_interleave(self.n_heads // self.kv_heads, dim=2)
|
193 |
+
v = v.repeat_interleave(self.n_heads // self.kv_heads, dim=2)
|
194 |
+
with nn.attention.sdpa_kernel(SDPBackend.FLASH_ATTENTION) if k.device.type == 'cuda' else nullcontext():
|
195 |
+
x = F.scaled_dot_product_attention(
|
196 |
+
q.transpose(1, 2),
|
197 |
+
k.transpose(1, 2),
|
198 |
+
v.transpose(1, 2),
|
199 |
+
is_causal=False if (q.size(1) != k.size(1)) else self.causal,
|
200 |
+
)
|
201 |
+
x = x.transpose(1, 2).contiguous()
|
202 |
+
return x
|
203 |
+
|
204 |
+
def _attend(self, q: Tensor, k: Tensor, v: Tensor, kv_cache: Optional[Tensor] = None,):
|
205 |
+
cache_len = get_cache_len(kv_cache)
|
206 |
+
q, k = self.shape_rotator.rotate(q, k, offset=cache_len)
|
207 |
+
if exists(kv_cache):
|
208 |
+
k = T.cat([kv_cache[:, :cache_len, 0], k], dim=1)
|
209 |
+
v = T.cat([kv_cache[:, :cache_len, 1], v], dim=1)
|
210 |
+
kv_cache[:, :k.size(1), 0] = k
|
211 |
+
kv_cache[:, :v.size(1), 1] = v
|
212 |
+
x = self._sdpa(q, k, v)
|
213 |
+
return self.attn_out(rearrange(x, 'b s h d -> b s (h d)'))
|
214 |
+
|
215 |
+
def _project(self, x):
|
216 |
+
full_q, full_k, full_v = self.proj_qkv(x).chunk(3, dim=-1)
|
217 |
+
normed_full_q = self.norm_q(full_q).to(full_q.dtype)
|
218 |
+
normed_full_k = self.norm_k(full_k).to(full_k.dtype)
|
219 |
+
|
220 |
+
q = rearrange(normed_full_q, 'b s (h d) -> b s h d', h=self.n_heads)
|
221 |
+
k = rearrange(normed_full_k, 'b s (h d) -> b s h d', h=self.kv_heads)
|
222 |
+
v = rearrange(full_v, 'b s (h d) -> b s h d', h=self.kv_heads)
|
223 |
+
return q, k, v
|
224 |
+
|
225 |
+
def forward(self,
|
226 |
+
x: Tensor,
|
227 |
+
kv: Optional[Tensor] = None,):
|
228 |
+
"""
|
229 |
+
x: (B, S, D)
|
230 |
+
kv: (B, S, H, D)
|
231 |
+
"""
|
232 |
+
q, k, v = self._project(x)
|
233 |
+
return self._attend(q, k, v, kv_cache=kv)
|
234 |
+
|
235 |
+
|
236 |
+
class PreNormAttn(nn.Module):
|
237 |
+
def __init__(self,
|
238 |
+
dim: int,
|
239 |
+
n_head: int,
|
240 |
+
shape_rotator: ShapeRotator,
|
241 |
+
kv_heads: Optional[int] = None,
|
242 |
+
eps: float = 1e-5,
|
243 |
+
causal: bool = True,):
|
244 |
+
super().__init__()
|
245 |
+
self.attn_norm = Norm(dim, eps=eps)
|
246 |
+
self.attn = GQA(dim, n_head, shape_rotator, kv_heads, eps=eps, causal=causal)
|
247 |
+
|
248 |
+
def forward(self, x: Tensor, kv: Optional[Tensor] = None) -> Tensor:
|
249 |
+
"""
|
250 |
+
x: (B, S, D)
|
251 |
+
kv: (B, S, H, D)
|
252 |
+
"""
|
253 |
+
return x + self.attn(self.attn_norm(x), kv)
|
254 |
+
|
255 |
+
class PreNormFFNN(nn.Module):
|
256 |
+
def __init__(self,
|
257 |
+
dim: int,
|
258 |
+
ff_dim: int,
|
259 |
+
eps: float = 1e-5,):
|
260 |
+
super().__init__()
|
261 |
+
self.ffnn_norm = Norm(dim, eps=eps)
|
262 |
+
self.ffnn = FFNN(dim, ff_dim)
|
263 |
+
|
264 |
+
def forward(self, x: Tensor) -> Tensor:
|
265 |
+
return x + self.ffnn(self.ffnn_norm(x))
|
266 |
+
|
267 |
+
class Block(nn.Module):
|
268 |
+
def __init__(self,
|
269 |
+
dim: int,
|
270 |
+
layer_id: int = 0,
|
271 |
+
n_head: int = 16,
|
272 |
+
kv_heads: Optional[int] = None,
|
273 |
+
ff_dim: Optional[int] = None,
|
274 |
+
eps: float = 1e-5,
|
275 |
+
causal: bool = True,
|
276 |
+
shape_rotator: ShapeRotator = None):
|
277 |
+
super().__init__()
|
278 |
+
self.attn = PreNormAttn(dim, n_head, shape_rotator, kv_heads, eps=eps, causal=causal)
|
279 |
+
self.ffnn = PreNormFFNN(dim, ff_dim, eps=eps)
|
280 |
+
self.dim = dim
|
281 |
+
self.layer_id = layer_id
|
282 |
+
self.head_dim = dim // n_head
|
283 |
+
self.expand_dim = self.ffnn.ffnn.expand_dim
|
284 |
+
|
285 |
+
self.reset_parameters()
|
286 |
+
|
287 |
+
def reset_parameters(self):
|
288 |
+
std = 1.0 / math.sqrt(self.dim)
|
289 |
+
nn.init.trunc_normal_(self.ffnn.ffnn.gateup_proj.weight, std=std, a=-3 * std, b=3 * std)
|
290 |
+
nn.init.trunc_normal_(self.attn.attn.proj_qkv.weight, std=std, a=-3 * std, b=3 * std)
|
291 |
+
nn.init.trunc_normal_(self.attn.attn.attn_out.weight, std=std, a=-3 * std, b=3 * std)
|
292 |
+
|
293 |
+
xstd = 1.0 / math.sqrt(self.expand_dim)
|
294 |
+
nn.init.trunc_normal_(self.ffnn.ffnn.down_proj.weight, std=xstd, a=-3 * xstd, b=3 * xstd)
|
295 |
+
|
296 |
+
def forward(self, x: Tensor, kv: Optional[Tensor] = None) -> Tensor:
|
297 |
+
"""
|
298 |
+
x: (B, S, D)
|
299 |
+
kv: (B, S, H, D)
|
300 |
+
"""
|
301 |
+
h = self.attn(x, kv)
|
302 |
+
out = self.ffnn(h)
|
303 |
+
return out
|
304 |
+
|
305 |
+
|
306 |
+
|
307 |
+
class GPTOutput(nn.Module):
|
308 |
+
def __init__(self, dim, vocab_size):
|
309 |
+
super().__init__()
|
310 |
+
self.dim = dim
|
311 |
+
self.norm = Norm(dim)
|
312 |
+
self.output = Linear(dim, vocab_size)
|
313 |
+
|
314 |
+
self.reset_parameters()
|
315 |
+
|
316 |
+
def reset_parameters(self):
|
317 |
+
std = 1.0 / math.sqrt(self.dim**2)
|
318 |
+
nn.init.trunc_normal_(self.output.weight, std=std, a=-3 * std, b=3 * std)
|
319 |
+
|
320 |
+
def forward(self, x):
|
321 |
+
return self.output(self.norm(x))
|
322 |
+
|
323 |
+
@si_module
|
324 |
+
class Stack(nn.Module):
|
325 |
+
class Config:
|
326 |
+
layers: int
|
327 |
+
dim: int
|
328 |
+
seq_len: int
|
329 |
+
n_head: int = 32
|
330 |
+
ff_dim: int = None
|
331 |
+
kv_heads: int = None
|
332 |
+
eps: float = 1e-5
|
333 |
+
theta: Union[int, float] = 10_000
|
334 |
+
causal: bool = True
|
335 |
+
|
336 |
+
from_pretrained: Optional[Tuple[str, int]] = None
|
337 |
+
|
338 |
+
def __init__(self, c: Config):
|
339 |
+
super().__init__()
|
340 |
+
|
341 |
+
from_pretrained = c.from_pretrained
|
342 |
+
if exists(from_pretrained):
|
343 |
+
checkpoint = load_ckpt(c.from_pretrained)
|
344 |
+
|
345 |
+
self.shape_rotator = ShapeRotator(c.dim//c.n_head, c.seq_len, theta=c.theta)
|
346 |
+
|
347 |
+
self.layers = nn.ModuleList([
|
348 |
+
Block(
|
349 |
+
dim=c.dim,
|
350 |
+
layer_id=l,
|
351 |
+
n_head=c.n_head,
|
352 |
+
kv_heads=c.kv_heads,
|
353 |
+
ff_dim=c.ff_dim,
|
354 |
+
eps=c.eps,
|
355 |
+
causal=c.causal,
|
356 |
+
shape_rotator=self.shape_rotator,
|
357 |
+
) for l in range(c.layers)
|
358 |
+
])
|
359 |
+
|
360 |
+
kv_heads = c.kv_heads or c.n_head
|
361 |
+
head_dim = c.dim // c.n_head
|
362 |
+
cache_shape = [c.layers, c.seq_len, 2, kv_heads, head_dim]
|
363 |
+
self.cache_shape = cache_shape
|
364 |
+
self.cache = [None] * c.layers
|
365 |
+
|
366 |
+
if exists(from_pretrained):
|
367 |
+
self.load_state_dict(checkpoint)
|
368 |
+
|
369 |
+
def init_cache(self, bsize, device, dtype, length:int=None):
|
370 |
+
if self.cache_shape is None:
|
371 |
+
return
|
372 |
+
cache_shape = self.cache_shape.copy()
|
373 |
+
cache_shape[1] = length or cache_shape[1]
|
374 |
+
self.cache = T.full((bsize, *cache_shape), CACHE_FILL_VALUE, device=device, dtype=dtype).transpose(0, 1)
|
375 |
+
|
376 |
+
def deinit_cache(self):
|
377 |
+
self.cache = [None] * len(self.cache)
|
378 |
+
|
379 |
+
def forward(self, x: Tensor) -> Tensor:
|
380 |
+
for l, layer in enumerate(self.layers):
|
381 |
+
x = layer(x, kv=self.cache[l])
|
382 |
+
return x
|
utils/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .blocks import *
|
2 |
+
from .dist import *
|
3 |
+
from .interp import *
|
utils/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (211 Bytes). View file
|
|
utils/__pycache__/blocks.cpython-310.pyc
ADDED
Binary file (3.73 kB). View file
|
|
utils/__pycache__/dist.cpython-310.pyc
ADDED
Binary file (3.65 kB). View file
|
|
utils/__pycache__/interp.cpython-310.pyc
ADDED
Binary file (3.82 kB). View file
|
|
utils/blocks.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from dataclasses import dataclass
|
2 |
+
from typing import TypeVar, Generic, Type, Optional
|
3 |
+
from functools import wraps
|
4 |
+
import time
|
5 |
+
import random
|
6 |
+
|
7 |
+
import torch as T
|
8 |
+
import torch.nn as nn
|
9 |
+
|
10 |
+
# @TODO: remove si_module from codebase
|
11 |
+
# we use this in our research codebase to make modules from callable configs
|
12 |
+
si_module_TpV = TypeVar('si_module_TpV')
|
13 |
+
def si_module(cls: Type[si_module_TpV]) -> Type[si_module_TpV]:
|
14 |
+
if not hasattr(cls, 'Config') or not isinstance(cls.Config, type):
|
15 |
+
class Config:
|
16 |
+
pass
|
17 |
+
cls.Config = Config
|
18 |
+
|
19 |
+
cls.Config = dataclass(cls.Config)
|
20 |
+
|
21 |
+
class ConfigWrapper(cls.Config, Generic[si_module_TpV]):
|
22 |
+
def __call__(self, *args, **kwargs) -> si_module_TpV:
|
23 |
+
if len(kwargs) > 0:
|
24 |
+
config_dict = {field.name: getattr(self, field.name) for field in self.__dataclass_fields__.values()}
|
25 |
+
config_dict.update(kwargs)
|
26 |
+
new_config = type(self)(**config_dict)
|
27 |
+
return cls(new_config)
|
28 |
+
else:
|
29 |
+
return cls(self, *args)
|
30 |
+
|
31 |
+
ConfigWrapper.__module__ = cls.__module__
|
32 |
+
ConfigWrapper.__name__ = f"{cls.__name__}Config"
|
33 |
+
ConfigWrapper.__qualname__ = f"{cls.__qualname__}.Config"
|
34 |
+
|
35 |
+
cls.Config = ConfigWrapper
|
36 |
+
|
37 |
+
original_init = cls.__init__
|
38 |
+
def new_init(self, *args, **kwargs):
|
39 |
+
self.c = next((arg for arg in args if isinstance(arg, cls.Config)), None) or next((arg for arg in kwargs.values() if isinstance(arg, cls.Config)), None)
|
40 |
+
original_init(self, *args, **kwargs)
|
41 |
+
self.register_buffer('_device_tracker', T.Tensor(), persistent=False)
|
42 |
+
|
43 |
+
cls.__init__ = new_init
|
44 |
+
|
45 |
+
@property
|
46 |
+
def device(self):
|
47 |
+
return self._device_tracker.device
|
48 |
+
|
49 |
+
@property
|
50 |
+
def dtype(self):
|
51 |
+
return self._device_tracker.dtype
|
52 |
+
|
53 |
+
cls.device = device
|
54 |
+
cls.dtype = dtype
|
55 |
+
|
56 |
+
return cls
|
57 |
+
|
58 |
+
|
59 |
+
def get_activation(nonlinear_activation, nonlinear_activation_params={}):
|
60 |
+
if hasattr(nn, nonlinear_activation):
|
61 |
+
return getattr(nn, nonlinear_activation)(**nonlinear_activation_params)
|
62 |
+
else:
|
63 |
+
raise NotImplementedError(f"Activation {nonlinear_activation} not found in torch.nn")
|
64 |
+
|
65 |
+
|
66 |
+
def exists(v):
|
67 |
+
return v is not None
|
68 |
+
|
69 |
+
def isnt(v):
|
70 |
+
return not exists(v)
|
71 |
+
|
72 |
+
def truthyexists(v):
|
73 |
+
return exists(v) and v is not False
|
74 |
+
|
75 |
+
def truthyattr(obj, attr):
|
76 |
+
return hasattr(obj, attr) and truthyexists(getattr(obj, attr))
|
77 |
+
|
78 |
+
defaultT = TypeVar('defaultT')
|
79 |
+
|
80 |
+
def default(*args: Optional[defaultT]) -> Optional[defaultT]:
|
81 |
+
for arg in args:
|
82 |
+
if exists(arg):
|
83 |
+
return arg
|
84 |
+
return None
|
85 |
+
|
86 |
+
def maybe(fn):
|
87 |
+
@wraps(fn)
|
88 |
+
def inner(x, *args, **kwargs):
|
89 |
+
if not exists(x):
|
90 |
+
return x
|
91 |
+
return fn(x, *args, **kwargs)
|
92 |
+
return inner
|
utils/dist.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import torch as T
|
3 |
+
import re
|
4 |
+
from tqdm import tqdm
|
5 |
+
from datetime import timedelta
|
6 |
+
|
7 |
+
import requests
|
8 |
+
import hashlib
|
9 |
+
|
10 |
+
from io import BytesIO
|
11 |
+
|
12 |
+
def rank0():
|
13 |
+
rank = os.environ.get('RANK')
|
14 |
+
if rank is None or rank == '0':
|
15 |
+
return True
|
16 |
+
else:
|
17 |
+
return False
|
18 |
+
|
19 |
+
def local0():
|
20 |
+
local_rank = os.environ.get('LOCAL_RANK')
|
21 |
+
if local_rank is None or local_rank == '0':
|
22 |
+
return True
|
23 |
+
else:
|
24 |
+
return False
|
25 |
+
class tqdm0(tqdm):
|
26 |
+
def __init__(self, *args, **kwargs):
|
27 |
+
total = kwargs.get('total', None)
|
28 |
+
if total is None and len(args) > 0:
|
29 |
+
try:
|
30 |
+
total = len(args[0])
|
31 |
+
except TypeError:
|
32 |
+
pass
|
33 |
+
if total is not None:
|
34 |
+
kwargs['miniters'] = max(1, total // 20)
|
35 |
+
super().__init__(*args, **kwargs, disable=not rank0(), bar_format='{bar}| {n_fmt}/{total_fmt} [{rate_fmt}{postfix}]')
|
36 |
+
|
37 |
+
def print0(*args, **kwargs):
|
38 |
+
if rank0():
|
39 |
+
print(*args, **kwargs)
|
40 |
+
|
41 |
+
_PRINTED_IDS = set()
|
42 |
+
|
43 |
+
def printonce(*args, id=None, **kwargs):
|
44 |
+
if id is None:
|
45 |
+
id = ' '.join(map(str, args))
|
46 |
+
|
47 |
+
if id not in _PRINTED_IDS:
|
48 |
+
print(*args, **kwargs)
|
49 |
+
_PRINTED_IDS.add(id)
|
50 |
+
|
51 |
+
def print0once(*args, **kwargs):
|
52 |
+
if rank0():
|
53 |
+
printonce(*args, **kwargs)
|
54 |
+
|
55 |
+
def init_dist():
|
56 |
+
if T.distributed.is_initialized():
|
57 |
+
print0('Distributed already initialized')
|
58 |
+
rank = T.distributed.get_rank()
|
59 |
+
local_rank = int(os.environ.get('LOCAL_RANK', 0))
|
60 |
+
world_size = T.distributed.get_world_size()
|
61 |
+
else:
|
62 |
+
try:
|
63 |
+
rank = int(os.environ['RANK'])
|
64 |
+
local_rank = int(os.environ['LOCAL_RANK'])
|
65 |
+
world_size = int(os.environ['WORLD_SIZE'])
|
66 |
+
device = f'cuda:{local_rank}'
|
67 |
+
T.cuda.set_device(device)
|
68 |
+
T.distributed.init_process_group(backend='nccl', timeout=timedelta(minutes=30), rank=rank, world_size=world_size, device_id=T.device(device))
|
69 |
+
print(f'Rank {rank} of {world_size}.')
|
70 |
+
except Exception as e:
|
71 |
+
print0once(f'Not initializing distributed env: {e}')
|
72 |
+
rank = 0
|
73 |
+
local_rank = 0
|
74 |
+
world_size = 1
|
75 |
+
return rank, local_rank, world_size
|
76 |
+
|
77 |
+
def load_ckpt(load_from_location, expected_hash=None):
|
78 |
+
if local0():
|
79 |
+
os.makedirs('ckpt', exist_ok=True)
|
80 |
+
url = f"https://ckpt.si.inc/hertz-dev/{load_from_location}.pt"
|
81 |
+
save_path = f"ckpt/{load_from_location}.pt"
|
82 |
+
if not os.path.exists(save_path):
|
83 |
+
response = requests.get(url, stream=True)
|
84 |
+
total_size = int(response.headers.get('content-length', 0))
|
85 |
+
with open(save_path, 'wb') as f, tqdm(total=total_size, desc=f'Downloading {load_from_location}.pt', unit='GB', unit_scale=1/(1024*1024*1024)) as pbar:
|
86 |
+
for chunk in response.iter_content(chunk_size=8192):
|
87 |
+
f.write(chunk)
|
88 |
+
pbar.update(len(chunk))
|
89 |
+
if expected_hash is not None:
|
90 |
+
with open(save_path, 'rb') as f:
|
91 |
+
file_hash = hashlib.md5(f.read()).hexdigest()
|
92 |
+
if file_hash != expected_hash:
|
93 |
+
print(f'Hash mismatch for {save_path}. Expected {expected_hash} but got {file_hash}. Deleting checkpoint and trying again.')
|
94 |
+
os.remove(save_path)
|
95 |
+
return load_ckpt(load_from_location, expected_hash)
|
96 |
+
if T.distributed.is_initialized():
|
97 |
+
T.distributed.barrier() # so that ranks don't try to load checkpoint before it's finished downloading
|
98 |
+
loaded = T.load(f"ckpt/{load_from_location}.pt", weights_only=False, map_location='cpu')
|
99 |
+
return loaded
|
utils/interp.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch as T
|
2 |
+
import os
|
3 |
+
|
4 |
+
def rank0():
|
5 |
+
rank = os.environ.get('RANK')
|
6 |
+
if rank is None or rank == '0':
|
7 |
+
return True
|
8 |
+
else:
|
9 |
+
return False
|
10 |
+
|
11 |
+
def print_colored(message, color='reset', bold=False, **kwargs):
|
12 |
+
color_dict = {
|
13 |
+
'bold': '\033[1m',
|
14 |
+
'green': '\033[92m',
|
15 |
+
'yellow': '\033[93m',
|
16 |
+
'red': '\033[91m',
|
17 |
+
'blue': '\033[94m',
|
18 |
+
'grey': '\033[90m',
|
19 |
+
'white': '\033[97m',
|
20 |
+
'reset': '\033[0m'
|
21 |
+
}
|
22 |
+
|
23 |
+
color_code = color_dict.get(color.lower(), color_dict['reset'])
|
24 |
+
prefix = color_dict['bold'] if bold else ''
|
25 |
+
print(f"{prefix}{color_code}{message}{color_dict['reset']}", **kwargs)
|
26 |
+
|
27 |
+
def print0_colored(*args, **kwargs):
|
28 |
+
if rank0():
|
29 |
+
print_colored(*args, **kwargs)
|
30 |
+
|
31 |
+
def param_count(module):
|
32 |
+
def count_parameters(model):
|
33 |
+
return sum(p.numel() for p in model.parameters() if p.requires_grad)
|
34 |
+
|
35 |
+
total_params = count_parameters(module)
|
36 |
+
output = [f'Total model parameters: {total_params:,}', '---------------------------']
|
37 |
+
|
38 |
+
for name, child in module.named_children():
|
39 |
+
params = count_parameters(child)
|
40 |
+
output.append(f'{name} parameters: {params:,}')
|
41 |
+
|
42 |
+
return '\n'.join(output)
|
43 |
+
|
44 |
+
def model_size_estimation(module):
|
45 |
+
def estimate_size(model):
|
46 |
+
param_size = sum(p.nelement() * p.element_size() for p in model.parameters())
|
47 |
+
buffer_size = sum(b.nelement() * b.element_size() for b in model.buffers())
|
48 |
+
return param_size + buffer_size
|
49 |
+
|
50 |
+
total_size = estimate_size(module)
|
51 |
+
output = [f'Total model size: {total_size / 1024**2:.2f} MB', '---------------------------']
|
52 |
+
|
53 |
+
for name, child in module.named_children():
|
54 |
+
child_size = estimate_size(child)
|
55 |
+
output.append(f'{name} size: {child_size / 1024**2:.2f} MB')
|
56 |
+
|
57 |
+
return '\n'.join(output)
|
58 |
+
|
59 |
+
def layer_param_distribution(module):
|
60 |
+
def count_parameters(model):
|
61 |
+
return sum(p.numel() for p in model.parameters() if p.requires_grad)
|
62 |
+
|
63 |
+
def get_layer_types(model):
|
64 |
+
layer_types = {}
|
65 |
+
for name, module in model.named_modules():
|
66 |
+
layer_type = module.__class__.__name__
|
67 |
+
params = sum(p.numel() for p in module.parameters(recurse=False) if p.requires_grad)
|
68 |
+
if params > 0:
|
69 |
+
if layer_type not in layer_types:
|
70 |
+
layer_types[layer_type] = 0
|
71 |
+
layer_types[layer_type] += params
|
72 |
+
return layer_types
|
73 |
+
|
74 |
+
total_params = count_parameters(module)
|
75 |
+
layer_types = get_layer_types(module)
|
76 |
+
|
77 |
+
output = [f'Total trainable parameters: {total_params:,}', '---------------------------']
|
78 |
+
|
79 |
+
for layer_type, count in sorted(layer_types.items(), key=lambda x: x[1], reverse=True):
|
80 |
+
percentage = (count / total_params) * 100
|
81 |
+
output.append(f'{layer_type}: {count:,} ({percentage:.2f}%)')
|
82 |
+
|
83 |
+
return '\n'.join(output)
|
84 |
+
|