Views
No views yet
1conda create --name unsloth_env \
2 python=3.11 \
3 pytorch-cuda=12.1 \
4 pytorch cudatoolkit xformers -c pytorch -c nvidia -c xformers \
5 -yconda activate unsloth_env
pip install unsloth1import torch
2from unsloth import FastLanguageModel
3from transformers import AutoTokenizer
4from snac import SNAC
5from IPython.display import display, Audio
6import numpy as np
7import locale
8import scipy.io.wavfile
9
10gpu_stats = torch.cuda.get_device_properties(0)
11start_gpu_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
12max_memory = round(gpu_stats.total_memory / 1024 / 1024 / 1024, 3)
13print(f"GPU = {gpu_stats.name}. Max memory = {max_memory} GB.")
14print(f"{start_gpu_memory} GB of memory reserved.")
15
16from unsloth import FastLanguageModel as FastModel
17from peft import PeftModel
18from IPython.display import Audio
19
20
21# --- Define Constants and Configuration ---
22print("\n⏳ Defining constants...")
23# Model paths
24BASE_MODEL_NAME = "unsloth/orpheus-3b-0.1-ft"
25# 🔴 CRITICAL: UPDATE THIS PATH 🔴
26# This must be the path to the LoRA adapters you saved during training.
27# This should be inside the `output_dir` you set, e.g., "orpheus_training_dir/checkpoint-6000"
28LORA_ADAPTERS_PATH = "training_dir_latest/checkpoint-1688"
29
30
31# --- Load Your Fine-Tuned Orpheus Model ---
32print("\n⏳ Loading models...")
33# Load the base Orpheus model
34model, _ = FastLanguageModel.from_pretrained(
35 model_name = BASE_MODEL_NAME,
36 max_seq_length = 2048,
37 dtype = None,
38 load_in_4bit = False,
39)
40# Load your fine-tuned LoRA adapters on top
41model.load_adapter(LORA_ADAPTERS_PATH)
42print("✅ Loaded fine-tuned LoRA adapters.")
43
44# Load the Orpheus tokenizer
45tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_NAME)
46
47# Load the SNAC model (the "Vocal Cords")
48snac_model = SNAC.from_pretrained("hubertsiuzdak/snac_24khz")1
2# Special token IDs
3tokeniser_length = 128256
4start_of_speech = tokeniser_length + 1
5end_of_speech = tokeniser_length + 2
6start_of_human = tokeniser_length + 3
7end_of_human = tokeniser_length + 4
8start_of_ai = tokeniser_length + 5
9end_of_ai = tokeniser_length + 6
10pad_token = 128263
11start_of_text = 128000
12end_of_text = 128009
13print("✅ Constants defined.")1golden_test_set_prompts = [
2 "Στις 15 Μαΐου του 2024, το προϊόν κόστιζε 19,50€.",
3 "Έκανα post στο Instagram και μετά πήγα για shopping στο mall.",
4 "Ο λογαριασμός της Δ.Ε.Η. πρέπει να πληρωθεί, π.χ. μέσω τραπέζης.", # D.E.H. and p.x.
5 "Η εκστρατεία προσέλκυσε χιλιάδες εθελοντές.",
6 "Η Μαρία Παπαδοπούλου συνάντησε τον Γιάννη Οικονόμου.",
7 "Μια πάπια, μα ποια πάπια Μια πάπια με παπιά.",
8 "Ο παπάς ο παχύς, έφαγε παχιά φακή. Γιατί παπά παχύ, έφαγες παχιά φακή;",
9 "Άσπρη πέτρα ξέξασπρη κι απ' τον ήλιο ξεξασπρότερη.",
10 "Ο μπαμπάς πήγε στην αντάρα για να βρει τα αγκάθια.", # Tests μπ, ντ, γκ
11 "Οι τρεις ιερείς είδαν το υλικό.", # Tests ει, οι, υι (all sound like /i/)
12 "Έφαγα τζατζίκι και τσάι στην πλατεία.", # Tests τσ, τζ
13 "Ο νόμος είναι σαφής.", # NOmos (law)
14 "Ο νομός Αττικής είναι μεγάλος.", # noMOS (prefecture)
15 "Η παγκοσμιοποίηση επηρεάζει την οικονομία." # Tests stress on long words,
16 ]1# --- Configure the Generation ---
2
3def infer(prompts,chosen_voice):
4
5 FastLanguageModel.for_inference(model) # Enable native 2x faster inference
6
7 # Moving snac_model cuda to cpu
8 snac_model.to("cpu")
9
10 prompts_ = [(f"{chosen_voice}: " + p) if chosen_voice else p for p in prompts]
11
12 all_input_ids = []
13
14 for prompt in prompts_:
15 input_ids = tokenizer(prompt, return_tensors="pt").input_ids
16 all_input_ids.append(input_ids)
17
18 start_token = torch.tensor([[ 128259]], dtype=torch.int64) # Start of human
19 end_tokens = torch.tensor([[128009, 128260]], dtype=torch.int64) # End of text, End of human
20
21 all_modified_input_ids = []
22 for input_ids in all_input_ids:
23 modified_input_ids = torch.cat([start_token, input_ids, end_tokens], dim=1) # SOH SOT Text EOT EOH
24 all_modified_input_ids.append(modified_input_ids)
25
26 all_padded_tensors = []
27 all_attention_masks = []
28 max_length = max([modified_input_ids.shape[1] for modified_input_ids in all_modified_input_ids])
29 for modified_input_ids in all_modified_input_ids:
30 padding = max_length - modified_input_ids.shape[1]
31 padded_tensor = torch.cat([torch.full((1, padding), 128263, dtype=torch.int64), modified_input_ids], dim=1)
32 attention_mask = torch.cat([torch.zeros((1, padding), dtype=torch.int64), torch.ones((1, modified_input_ids.shape[1]), dtype=torch.int64)], dim=1)
33 all_padded_tensors.append(padded_tensor)
34 all_attention_masks.append(attention_mask)
35
36 all_padded_tensors = torch.cat(all_padded_tensors, dim=0)
37 all_attention_masks = torch.cat(all_attention_masks, dim=0)
38
39
40 input_ids = all_padded_tensors.to("cuda")
41 attention_mask = all_attention_masks.to("cuda")
42 generated_ids = model.generate(
43 input_ids=input_ids,
44 attention_mask=attention_mask,
45 max_new_tokens=1200,
46 do_sample=True,
47 temperature=0.6,
48 top_p=0.95,
49 repetition_penalty=1.1,
50 num_return_sequences=1,
51 eos_token_id=128258,
52 use_cache = True
53 )
54 token_to_find = 128257
55 token_to_remove = 128258
56
57 token_indices = (generated_ids == token_to_find).nonzero(as_tuple=True)
58
59 if len(token_indices[1]) > 0:
60 last_occurrence_idx = token_indices[1][-1].item()
61 cropped_tensor = generated_ids[:, last_occurrence_idx+1:]
62 else:
63 cropped_tensor = generated_ids
64
65 mask = cropped_tensor != token_to_remove
66
67 processed_rows = []
68
69 for row in cropped_tensor:
70 masked_row = row[row != token_to_remove]
71 processed_rows.append(masked_row)
72
73 code_lists = []
74
75 for row in processed_rows:
76 row_length = row.size(0)
77 new_length = (row_length // 7) * 7
78 trimmed_row = row[:new_length]
79 trimmed_row = [t - 128266 for t in trimmed_row]
80 code_lists.append(trimmed_row)
81
82
83 def redistribute_codes(code_list):
84 layer_1 = []
85 layer_2 = []
86 layer_3 = []
87 for i in range((len(code_list)+1)//7):
88 layer_1.append(code_list[7*i])
89 layer_2.append(code_list[7*i+1]-4096)
90 layer_3.append(code_list[7*i+2]-(2*4096))
91 layer_3.append(code_list[7*i+3]-(3*4096))
92 layer_2.append(code_list[7*i+4]-(4*4096))
93 layer_3.append(code_list[7*i+5]-(5*4096))
94 layer_3.append(code_list[7*i+6]-(6*4096))
95 codes = [torch.tensor(layer_1).unsqueeze(0),
96 torch.tensor(layer_2).unsqueeze(0),
97 torch.tensor(layer_3).unsqueeze(0)]
98
99 # codes = [c.to("cuda") for c in codes]
100 audio_hat = snac_model.decode(codes)
101 return audio_hat
102
103 my_samples = []
104 for code_list in code_lists:
105 samples = redistribute_codes(code_list)
106 my_samples.append(samples)
107 from IPython.display import display, Audio
108 if len(prompts) != len(my_samples):
109 raise Exception("Number of prompts and samples do not match")
110 else:
111 for i in range(len(my_samples)):
112 print(prompts[i])
113 samples = my_samples[i]
114 display(Audio(samples.detach().squeeze().to("cpu").numpy(), rate=24000))
115 # Clean up to save RAM
116 del my_samples,samples
1171# --- Run infrence ---
2for prompt in golden_test_set_prompts:
3 prompts = [prompt,]
4 print(prompts)
5 chosen_voice = None # None for single-speaker
6 infer(prompts,chosen_voice)@misc{moira2025greektts15,
title = {GreekTTS-1.5: A State-of-the-Art System for Greek Text-to-Speech Synthesis},
author = {Moira.AI},
year = {2025},
month = {oct},
day = {12},
url = {https://moira-ai.com/},
note = {Demo report: https://moiraai2024.github.io/GreekTTS-1.5-demo/}
}