import os from suno_utils.audio import Audio import fire import gc from suno_utils.gpt.generation import ( generate, models, load_dummy_model, GPTConfig, ) import torch import torch import contextlib import time import pandas as pd from tqdm import tqdm CFG = 3 # multiply batch size by CFG REP_RATE = 75 def run(n_batch=2, max_duration_s=20, profile=False): prof = ( contextlib.nullcontext() if not profile else torch.profiler.profile(with_flops=True) ) # get max memory allocated # print(f"Running with batch size {n_batch * CFG}") print(f"Current memory allocated: {torch.cuda.memory_allocated() / 1e9:.2f} GB") torch.cuda.reset_max_memory_allocated() torch.cuda.synchronize() t0 = time.time() with prof: y = generate( GenerationConfig( text="hello", text_tags="edm", n_batch=n_batch, max_gen_duration_s=max_duration_s, allow_eos=False, ) ) t1 = time.time() max_mem = torch.cuda.max_memory_allocated() / 1e9 print(f"Max memory allocated: {max_mem:.2f} GB") # if profile: # prof.export_chrome_trace(f"profile_bs_{n_batch}_{max_duration_s}.json") time_elapsed = t1 - t0 cfg = models["main_model"].config tokens_generated = ( cfg.semantic_n_codebooks + (cfg.coarse_n_codebooks - 1) * cfg.coarse_shift_factor + len(y[1]) ) tps = tokens_generated / time_elapsed throughput = tps * n_batch return time_elapsed, tps, throughput, max_mem # min_bandwidth = n_params * tps # Bandwidth to load model weights once per token # return y, time_elapsed, throughput, min_bandwidth, tps tokenizer_path = "/home/victor/data/models/chirp_v2/tokenizer_60k.json" def run_dummy(model_config, n_batch=2, max_duration_s=20): load_dummy_model( GPTConfig( n_head=model_config["n_head"], n_layer=model_config["n_layer"], n_embd=model_config["n_embd"], ), tokenizer_path, ) try: return run(max_duration_s=max_duration_s, n_batch=n_batch) except RuntimeError: print(f"{model_config}, OOM") return None def profile_shapes(gpu: str): data = [] configs = [ (40, 40, 5120), (25, 48, 1600), (32, 48, 2048), (32, 32, 4096), ] for n_head, n_layer, n_embd in tqdm(configs, desc="configs"): for duration in tqdm([30, 60, 80, 100, 120], desc="duration"): for batch_size in [1, 2]: print( f"Running with n_head={n_head}, n_layer={n_layer}, n_embd={n_embd}. Generating...." ) try: # clear cache torch.cuda.empty_cache() load_dummy_model( GPTConfig(n_head=n_head, n_layer=n_layer, n_embd=n_embd), tokenizer_path, ) time_elapsed, tps, throughput, max_mem = run( max_duration_s=duration, n_batch=batch_size ) except: print(f"n_head={n_head}, n_layer={n_layer}, n_embd={n_embd}, OOM") # free up memory del models["main_model"] torch.cuda.empty_cache() break data.append( { "gpu": gpu, "n_head": n_head, "n_layer": n_layer, "n_embd": n_embd, "duration": duration, "batch_size": batch_size, "time_elapsed": time_elapsed, "tps": tps, "throughput": throughput, "max_mem": max_mem, } ) print(data[-1]) # break # break # break df = pd.DataFrame(data) df.to_csv(f"gpt_throughput_{gpu}.csv") print(df) def run_7b(n_batch=2, max_duration_s=20, profile=False): print(f"Current memory allocated: {torch.cuda.memory_allocated() / 1e9:.2f} GB") torch.cuda.reset_max_memory_allocated() torch.cuda.synchronize() t0 = time.time() y = generate_audio( GenerationConfig( text="hello " * 3000, text_tags="edm", text_neg_control_tags="classical", n_batch=n_batch, max_gen_duration_s=max_duration_s, allow_eos=False, ), return_raw_arrays=True, ) t1 = time.time() max_mem = torch.cuda.max_memory_allocated() / 1e9 print(f"Max memory allocated: {max_mem:.2f} GB") time_elapsed = t1 - t0 cfg = models["main_model"]["model"].config tokens_generated = ( cfg.semantic_shift_factor + (cfg.coarse_n_codebooks - 1) * cfg.coarse_shift_factor + y[1][0].shape[0] ) # print(f"tokens generated: {tokens_generated}") tps = tokens_generated / time_elapsed throughput = tps * n_batch return time_elapsed, tps, throughput, max_mem def profile(gpu: str, duration: int, model: str): global generate_audio, GenerationConfig assert model in ["7B", "3B"] if model == "7B": from suno_utils.gpt.chirp_v2_5 import ( preload_models, generate_audio, GenerationConfig, ) preload_models( codec_ckpt_path="s3://suno-data/georg/models/codec/dac_2c_25x12.pt", gpt_ckpt_path="s3://suno-data/georg/checkpoints/chirp_v2_5/7b.pt", ) elif model == "3B": from suno_utils.gpt.chirp_v2 import ( preload_models, generate_audio, GenerationConfig, ) preload_models( codec_ckpt_path="/home/victor/data/models/chirp_v2/dac_2c_25x8.pt", gpt_ckpt_path="/app/suno/checkpoints/2023-10-17_16-01-32/last_ckpt_infer.pt", ) # for batch_size in [2]: for batch_size in [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128]: try: gc.collect() torch.cuda.empty_cache() time_elapsed, tps, throughput, max_mem = run_7b( max_duration_s=duration, n_batch=batch_size ) except Exception as e: print(e) print(f"OOM with batch size {batch_size}, duration {duration}") break j = { "model": model, "gpu": gpu, "duration": duration, "batch_size": batch_size, "time_elapsed": time_elapsed, "tps": tps, "throughput": throughput, "max_mem": max_mem, } print(j) with open(f"7b_throughput.jsonl", "a+") as f: f.write(str(j) + "\n") if __name__ == "__main__": fire.Fire(profile)