Instructions to use hofarah/orpheus-3b-persian-tts-lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use hofarah/orpheus-3b-persian-tts-lora with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("unsloth/orpheus-3b-0.1-ft") model = PeftModel.from_pretrained(base_model, "hofarah/orpheus-3b-persian-tts-lora") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Unsloth Studio
How to use hofarah/orpheus-3b-persian-tts-lora with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for hofarah/orpheus-3b-persian-tts-lora to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for hofarah/orpheus-3b-persian-tts-lora to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for hofarah/orpheus-3b-persian-tts-lora to start chatting
Load model with FastModel
pip install unsloth from unsloth import FastModel model, tokenizer = FastModel.from_pretrained( model_name="hofarah/orpheus-3b-persian-tts-lora", max_seq_length=2048, )
Orpheus-3B Persian TTS (LoRA)
A LoRA adapter that adapts unsloth/orpheus-3b-0.1-ft
— an English speech-LM built on Llama-3.2-3B that emits SNAC
audio codec tokens — to Persian (Farsi) text-to-speech.
The adapter takes Finglish input: Persian romanized into Latin script (salam, hale shoma chetore?),
not Persian script (سلام، ØØ§Ù„ شما چطوره؟). This was the deliberate design choice of the project — it
reuses the base model's existing Latin-script tokenization instead of forcing it to learn an unseen
writing system from ~50 hours of audio. See Input format.
Results
Evaluated against 1,219 held-out sentences (in-domain + challenge sets), transcribed with Whisper for ASR-based error rates. Lower is better for CER/WER/RTF.
| System | CER ↓ | WER ↓ | Persian LID ↑ | Spk. sim ↑ | RTF ↓ |
|---|---|---|---|---|---|
| This model (Orpheus-3B + LoRA, Finglish) | 0.129 | 0.367 | 0.967 | 0.763 | 1.50 |
| SNAC codec reconstruction (quality ceiling) | 0.144 | — | — | 0.722 | — |
facebook/mms-tts-fas (VITS, 36M) |
0.152 | 0.449 | 0.980 | — | 0.01 |
| Qwen3-TTS-1.7B, full fine-tune | 0.230 | 0.610 | 0.576 | — | 0.51 |
| Orpheus-3B base (no adaptation) | 0.421 | 0.816 | 0.030 | 0.284 | 1.09 |
Split by evaluation set, CER is 0.103 in-domain and 0.267 on the challenge set. Failure rate was 0.0% — every one of the 1,219 prompts produced decodable audio.
Two things worth reading carefully:
- The model scores below the SNAC codec reconstruction floor (0.129 vs 0.144). That does not mean it beats ground-truth audio; it means the codec's own reconstruction of the reference is harder for Whisper to transcribe than the model's clean synthetic speech. Treat 0.144 as the practical ceiling of this token protocol, not as a baseline the model surpassed in any meaningful sense.
- RTF 1.50 means it is slower than real-time on an RTX 3090 Ti — roughly 1.5 s of compute per second of
audio.
mms-tts-fasis ~150× faster. This is an autoregressive 3B LM emitting 7 codec tokens per 85 ms frame; it is not suited to low-latency streaming without further work.
Speaker similarity is measured only on the single-speaker in-domain set. Persian LID is the fraction of outputs Whisper identifies as Persian.
Input format
The model was trained on Finglish and expects Finglish. Feeding it Persian script is an out-of-distribution condition that the source project measured as a separate, confounded ablation (see Limitations).
The prompt protocol is inherited from Orpheus — a voice tag, then the text, wrapped in special tokens:
[128259] "female1: <finglish text>" [128009] [128260]
female1 is the only voice in the training corpus; other tags are untrained.
Usage
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
from snac import SNAC
ADAPTER = "hofarah/orpheus-3b-persian-tts-lora"
BASE = "unsloth/orpheus-3b-0.1-ft"
# The adapter repo carries the resized tokenizer (base vocab + audio tokens),
# so load the tokenizer from here, not from the base model.
tok = AutoTokenizer.from_pretrained(ADAPTER)
model = AutoModelForCausalLM.from_pretrained(BASE, torch_dtype=torch.bfloat16, device_map="cuda")
if len(tok) > model.get_input_embeddings().weight.shape[0]:
model.resize_token_embeddings(len(tok))
model = PeftModel.from_pretrained(model, ADAPTER).eval()
snac = SNAC.from_pretrained("hubertsiuzdak/snac_24khz").eval()
START_OF_HUMAN, END_OF_TEXT, END_OF_HUMAN = 128259, 128009, 128260
START_OF_SPEECH, END_OF_SPEECH, AUDIO_BASE = 128257, 128258, 128266
text = "salam, hale shoma chetore?" # Finglish, not Persian script
ids = tok(f"female1: {text}", return_tensors="pt").input_ids
ids = torch.cat([torch.tensor([[START_OF_HUMAN]]), ids,
torch.tensor([[END_OF_TEXT, END_OF_HUMAN]])], dim=1).to(model.device)
with torch.inference_mode():
out = model.generate(input_ids=ids, attention_mask=torch.ones_like(ids),
max_new_tokens=1200, do_sample=True, temperature=0.6,
top_p=0.95, repetition_penalty=1.1,
eos_token_id=END_OF_SPEECH)
# Crop to the generated speech span, then de-interleave 7-token groups into
# SNAC's three codebook layers (L1: slot 0; L2: slots 1,4; L3: slots 2,3,5,6).
row = out[0].cpu()
hits = (row == START_OF_SPEECH).nonzero()
row = row[int(hits[-1]) + 1:] if hits.numel() else row
row = row[row != END_OF_SPEECH]
row = row[row >= AUDIO_BASE] - AUDIO_BASE
row = row[: (row.numel() // 7) * 7]
l1, l2, l3 = [], [], []
for i in range(row.numel() // 7):
g = row[i * 7:(i + 1) * 7].tolist()
if all(0 <= v < 4096 for v in (g[0], g[1] - 4096, g[4] - 4 * 4096,
g[2] - 2 * 4096, g[3] - 3 * 4096,
g[5] - 5 * 4096, g[6] - 6 * 4096)):
l1 += [g[0]]
l2 += [g[1] - 4096, g[4] - 4 * 4096]
l3 += [g[2] - 2 * 4096, g[3] - 3 * 4096, g[5] - 5 * 4096, g[6] - 6 * 4096]
codes = [torch.tensor(x).unsqueeze(0) for x in (l1, l2, l3)]
with torch.inference_mode():
wav = snac.decode(codes).squeeze().float().numpy() # 24 kHz mono
A group containing an out-of-range index is a codec failure — drop it and count it rather than clamping, so the rate stays measurable.
Training
| Base model | unsloth/orpheus-3b-0.1-ft (Llama-3.2-3B backbone, SNAC 24 kHz codec) |
| Method | LoRA, r=64, α=64, dropout 0, bias none |
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Trainable params | ≈60M of 3.2B (~1.9%) |
| Schedule | 1 epoch, 4,865 steps, batch size 1, linear decay from 2e-4 |
| Training loss | 4.88 → 3.95 |
| Precision | bf16 against an unquantized base |
| Data | hofarah/Persian-tts-finglish-orpheus — 19,458 utterances, ≈50.8 h |
Inference was evaluated in bf16 rather than 4-bit, because the LoRA was trained against an unquantized base — bf16 is closer to the training condition.
trainer_state.json (full loss curve) is kept in this repo. Optimizer, scheduler and RNG state were
removed; this repo is for inference, not for resuming training.
Limitations
- Single speaker. One voice (
female1) in the entire corpus. There is no speaker control, and the speaker-similarity number describes consistency with that one voice. - ≈13% of the training text is corrupted. A bare
except:in the corpus's Finglish generation script wrote raw Persian text into the Finglish column whenever the transliteration API call failed. The composition is 86.73% clean Finglish, 10.46% pure Persian script, 2.04% mixed, 0.77% empty/single-char. Consequence: the model saw ~2,400 Persian-script examples, so any apparent Persian-script ability has a direct training-data explanation and is not zero-shot cross-script transfer. - Length cap. Generation stops at 1,200 tokens ≈ 14.6 s. 15.9% of training utterances were longer than this, so long inputs will truncate.
- Slower than real-time (RTF 1.50), see Results.
- Corpus size is ≈50.8 h, verified from the released artifacts. Earlier project notes claiming ~29 h or "over 20 hours" are not reproducible and should not be cited.
- Evaluation reference audio for the in-domain set is SNAC codec reconstruction, not original waveform.
- MOS figures in the source evaluation are predicted MOS, not human listening-test MOS.
License
Not yet set. This is a LoRA adapter over unsloth/orpheus-3b-0.1-ft, which derives from Llama-3.2-3B —
any license here must be compatible with the Llama 3.2 Community License and with the terms of the
underlying speech corpus. Confirm both before citing or redistributing.
Citation
@misc{orpheus_persian_tts_lora,
title = {Orpheus-3B Persian TTS (LoRA)},
author = {hofarah},
year = {2026},
url = {https://huggingface.co/hofarah/orpheus-3b-persian-tts-lora}
}
- Downloads last month
- -
Model tree for hofarah/orpheus-3b-persian-tts-lora
Base model
meta-llama/Llama-3.2-3B-Instruct