Training and inference code for Irodori-TTS, a Flow Matching-based Text-to-Speech model. The architecture and training design largely follow Echo-TTS, using DACVAE continuous latents as the generation target.
For an OpenAI-compatible inference API server, see Irodori-TTS-Server.
Important
main tracks the v4 codebase and is intended for use with the unified Irodori-TTS-v4.1-Small release.
The current code remains backward-compatible with the released v2/v3 base and VoiceDesign checkpoints.
Previous codebase states are available through the v3, v2, and v1 tags.
v1 checkpoints / preprocessing are not compatible with v2/v3/v4.
For model weights and audio samples, please refer to the Irodori-TTS-v4.1-Small model card.
- Flow Matching TTS: Rectified Flow Diffusion Transformer (RF-DiT) over continuous DACVAE latents
- Voice Cloning: Zero-shot voice cloning from reference audio
- Multi-modal Voice Design: v4-Small combines text, reference speech, and caption text for voice identity plus style/emotion control
- Long Reference Audio: One or more reference clips can be concatenated up to the checkpoint's 120-second limit
- Emoji-based Style Control: Emoji annotations in input text can influence delivery and non-verbal vocal expressions in supported checkpoints
- Automatic Duration Prediction: v4-Small estimates output length without manual
--seconds - Automatic Watermarking: Generated audio is watermarked with SilentCipher when available
- Multi-GPU Training: Distributed training via
uv run --no-sync torchrunwith gradient accumulation, mixed precision (bf16), and W&B logging - PEFT LoRA Fine-Tuning: Parameter-efficient adaptation with PEFT/LoRA for released checkpoints
- Speaker Inversion: Learn reusable speaker embedding tokens for a target voice while freezing the base model
- Flexible Inference: CLI, Gradio Web UI, and HuggingFace Hub checkpoint support
The current release, Aratako/Irodori-TTS-v4.1-Small, unifies the previous base and
VoiceDesign families in one checkpoint. It supports 3-branch conditioning from text,
reference speech, and caption text. Released v2/v3 checkpoints remain supported for inference.
Shared building blocks:
- Shared Text/Caption Encoder: A fine-tuned ModernBERT backbone processes both reading text and caption text
- Reference Latent Encoder: Encodes patched reference audio latents for speaker identity conditioning, with up to 120 seconds of combined reference audio in v4-Small
- Condition Projectors: Separate text and caption projectors map the shared encoder states into their conditioning spaces
- Diffusion Transformer: Joint-attention DiT blocks with Low-Rank AdaLN (timestep-conditioned adaptive layer normalization), half-RoPE, and SwiGLU MLPs
- Duration Predictor: Integrated predictor for automatic output length estimation
Audio is represented as continuous latent sequences via the codec configured by the checkpoint. The released v2/v3/v4 checkpoints use the 32-dim Semantic-DACVAE-Japanese-32dim codec for 48kHz waveform reconstruction.
git clone https://github.com/Aratako/Irodori-TTS.git
cd Irodori-TTS
uv sync --extra cu128 # NVIDIA CUDA 12.8 (Linux/Windows)If you want to explicitly select a PyTorch backend, use one of the backend extras below:
# NVIDIA CUDA 12.8 on Linux/Windows
uv sync --extra cu128
# AMD ROCm on Linux/WSL
uv sync --extra rocm
# Intel XPU on Linux/Windows
uv sync --extra xpu
# CPU-only, or macOS CPU/MPS via PyPI
uv sync --extra cpuThe PyTorch backend extras are mutually exclusive. The cu128 extra uses the
PyTorch CUDA 12.8 index, the rocm extra uses the PyTorch ROCm index on
Linux, and the xpu extra uses the PyTorch XPU index on Linux/Windows.
The cpu extra uses the CPU PyTorch index on Linux/Windows and falls
back to the standard PyPI PyTorch wheels on macOS.
After syncing with a backend extra, use uv run --no-sync ... for the commands
below to avoid re-syncing the environment without the selected PyTorch backend
extra.
The rocm extra includes pytorch-triton-rocm because triton-rocm alone does
not provide triton.language for the transformers to torch._dynamo import
path. This was validated with AMD GPU inference.
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--ref-wav path/to/reference.wav \
--output-wav outputs/sample.wavuv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--no-ref \
--output-wav outputs/sample.wavPure VoiceDesign from text + caption:
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--caption "่ฝใก็ใใๅฅณๆงใฎๅฃฐใงใ่ฟใ่ท้ขๆใงใใใใใ่ช็ถใซ่ชญใฟไธใใฆใใ ใใใ" \
--no-ref \
--output-wav outputs/sample_voice_design.wavStyle-controlled voice cloning with text + reference speech + caption:
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใฉใใใฆใใฃใจๆฉใๆใใฆใใใชใใฃใใฎ๏ผ็งใใใฃใจๅพ
ใฃใฆใใฎใซใ" \
--ref-wav path/to/reference.wav \
--caption "ๆทฑใๅทใคใใไปใซใๆณฃใๅบใใใใชๆงๅญใๅฃฐใ้ใใฆใใใๆฒ็ใชใใผใณใงๅผฑใ
ใใ่ฉฑใใ" \
--output-wav outputs/sample_voice_design_clone.wavLong-reference checkpoints can concatenate multiple reference clips in the specified order:
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "่คๆฐใฎๅ็
ง้ณๅฃฐใไฝฟใฃใฆๅๆใใพใใ" \
--caption "่ฝใก็ใใ่ช็ถใชๅฃฐ" \
--ref-wavs ref_01.wav ref_02.wav ref_03.wav \
--output-wav outputs/sample_long_reference.wavEach waveform is encoded independently before its latent is concatenated. The combined
reference is trimmed to the checkpoint's maximum reference duration. Use --ref-latents
in the same way for precomputed latent files.
For v4-Small, prefer multiple clean, shorter clips from the same speaker when using a long reference. The model was trained with randomly concatenated short utterances, and the measured speaker-similarity benefit used the same construction. A combined duration of approximately 30 seconds already captured most of the measured gain. A single uninterrupted long recording is accepted by inference, but that input format has not been evaluated and may behave differently.
Use a learned Speaker Inversion embedding instead of reference audio:
uv run --no-sync python infer.py \
--checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensors \
--ref-embed path/to/my.speaker.safetensors \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--output-wav outputs/sample_speaker_inversion.wavuv run --no-sync python gradio_app.py --server-name 0.0.0.0 --server-port 7860Then access the UI at http://localhost:7860.
The hosted v4-Small demo is available at Aratako/Irodori-TTS-v4.1-Small-Demo.
The reference input area accepts one or more audio files, which can be reordered before
generation and are concatenated in the displayed order. For long-reference cloning, upload
multiple clean, shorter clips from the same speaker; this matches v4-Small training. A single
uninterrupted long recording is accepted but has not been evaluated. The standard UI also
supports a Speaker Inversion embedding through the adjacent tab.
For VoiceDesign checkpoints, use the dedicated UI:
uv run --no-sync python gradio_app_voicedesign.py --server-name 0.0.0.0 --server-port 7861The same hosted v4-Small demo supports VoiceDesign and reference-audio conditioning.
Both UIs default to Aratako/Irodori-TTS-v4.1-Small. gradio_app_voicedesign.py exposes
caption conditioning, while gradio_app.py includes the Speaker Inversion input.
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--ref-wav path/to/reference.wav \
--output-wav outputs/sample.wavLocal checkpoints (.pt or .safetensors) are also supported:
uv run --no-sync python infer.py \
--checkpoint outputs/checkpoint_final.safetensors \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--ref-wav path/to/reference.wav \
--output-wav outputs/sample.wavv4-Small supports caption conditioning. It can run with
caption only by passing --no-ref, or with both reference speech and caption by passing
--ref-wav, --ref-wavs, --ref-latent, --ref-latents, or --ref-embed.
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--caption "่ฝใก็ใใใ่ฟใ่ท้ขๆใฎๅฅณๆง่ฉฑ่
" \
--no-ref \
--output-wav outputs/sample_voice_design.wavuv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใฏใฏใฃ๐คญใใใๆฌๅฝใซ่จใฃใฆใใฎ๏ผโฆ๐ฎโ๐จใพใใๅใใใใใฉใญใ" \
--caption "ไฝ่ฃใฎใใๅคงไบบใฎ็ทๆงใ่ฆชใใ็ธๆใซๅฏพใใฆใใใ ใใ้ฐๅฒๆฐใงๅใใชใใใๆฅฝใใใใซ่ฉฑใใฆใใใ" \
--ref-wav path/to/reference.wav \
--output-wav outputs/sample_voice_design_ref_caption.wavThe older Aratako/Irodori-TTS-500M-v2-VoiceDesign checkpoint is still supported, but it is caption-only and intentionally ignores speaker/reference conditioning.
LoRA adapter directories can be loaded dynamically at inference time without exporting a merged checkpoint:
uv run --no-sync python infer.py \
--checkpoint path/to/base_model.safetensors \
--lora-adapter outputs/irodori_tts_lora/checkpoint_final \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏLoRAๆจ่ซใฎใในใใงใใ" \
--ref-wav path/to/reference.wav \
--output-wav outputs/sample_lora.wavSpeaker Inversion embedding checkpoints can be used with the same base model that
was used for inversion training. Pass the embedding with --ref-embed;
it is mutually exclusive with --ref-wav, --ref-latent, and --no-ref.
uv run --no-sync python infer.py \
--checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensors \
--ref-embed outputs/speaker_inversion/name/checkpoint_final.speaker.safetensors \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏSpeaker Inversionๆจ่ซใฎใในใใงใใ" \
--output-wav outputs/sample_speaker_inversion.wavv4-Small integrates duration prediction into inference.
When --seconds is omitted, the runtime estimates the output length from the input
text and enabled conditions, then generates audio for that estimated duration. Use
--duration-scale to multiply the predicted length (>1 longer, <1 shorter). For
exact control, pass --seconds manually.
Older v2 checkpoints were trained with fixed-length 30-second targets. They remain
supported by the current codebase and still accept manual --seconds, but forcing a
non-default duration can reduce audio quality; prefer v4-Small for automatic
or scaled duration control.
For faster experimental inference, Sway Sampling can be combined with fewer Euler steps:
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small \
--text "ใใใซใกใฏใ็งใฏAIใงใใใใใฏ้ณๅฃฐๅๆใฎใในใใงใใ" \
--ref-wav path/to/reference.wav \
--num-steps 6 \
--t-schedule-mode sway \
--sway-coeff -1.0 \
--output-wav outputs/sample_sway.wavFor tuning guidance and detailed explanations of inference options, see the Parameter Guide.
Generated audio is passed through SilentCipher watermarking automatically when the dependency and model files are available.
This section describes how to train Irodori-TTS-v4.1-Small. For training instructions for previous models, refer to the documentation in the corresponding version tags.
Encodes audio from a Hugging Face dataset into DACVAE latents and produces a JSONL manifest for training.
uv run --no-sync python prepare_manifest.py \
--dataset myorg/my_dataset \
--split train \
--audio-column audio \
--text-column text \
--caption-column caption \
--speaker-column speaker \
--output-manifest data/train_manifest.jsonl \
--latent-dir data/latents \
--device cudav4-Small learns from text, speaker/reference audio, and captions. Include speaker_id and
caption where available so all three conditioning paths can be trained. A Speaker
Inversion manifest does not require speaker_id, because the run learns one shared speaker
embedding from the target-speaker samples.
The manifest caption value may also be a list of strings; training randomly selects one
non-empty caption each time that row is loaded.
This produces a JSONL manifest with entries like:
{"text": "ใใใซใกใฏ", "caption": "่ฝใก็ใใใ่ฟใ่ท้ขๆใฎๅฅณๆง่ฉฑ่
", "latent_path": "data/latents/00001.pt", "speaker_id": "myorg/my_dataset:speaker_001", "num_frames": 750}Single-GPU training:
uv run --no-sync python train.py \
--config configs/train_v4_small.yaml \
--manifest data/train_manifest.jsonl \
--output-dir outputs/irodori_tts \
--init-checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensorsThe v4-Small config trains the RF body, duration predictor, and shared pretrained text/caption
backbone jointly. The duration predictor regresses log1p(num_frames) with Huber loss and
uses the token-sum architecture selected from ablations. See the parameter guide for its
architecture details.
Multi-GPU DDP training:
uv run --no-sync torchrun --nproc_per_node 4 train.py \
--config configs/train_v4_small.yaml \
--manifest data/train_manifest.jsonl \
--output-dir outputs/irodori_tts \
--init-checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensors \
--device cudaTraining supports YAML config files with model and train sections. CLI arguments take precedence over YAML values. See uv run --no-sync python train.py --help for all available options.
For a more detailed explanation of model and training config fields, see Parameter Guide.
Start a new training run from released inference weights (.safetensors). This initializes only the model weights; optimizer / scheduler state starts fresh. The duration predictor is kept as part of the saved adapter by default.
uv run --no-sync python train.py \
--config configs/train_v4_small_lora.yaml \
--manifest data/train_manifest.jsonl \
--output-dir outputs/irodori_tts_lora \
--init-checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensorsThe v4-Small LoRA config targets diffusion attention by default and saves the duration
predictor with the adapter. To adapt the shared ModernBERT backbone, select the
pretrained_backbone_attn or pretrained_backbone_attn_mlp target preset.
LoRA target presets, adapter saving behavior, and resume details are covered in the Parameter Guide.
Speaker Inversion trains only a small set of speaker embedding tokens while keeping the base Irodori-TTS model frozen. It is useful when you want a reusable speaker identity checkpoint instead of providing reference audio at every inference call.
Prepare a manifest from the target speaker's audio, then initialize from v4-Small:
uv run --no-sync python train.py \
--config configs/train_v4_small_speaker_inversion.yaml \
--manifest data/target_speaker_manifest.jsonl \
--init-checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensors \
--output-dir outputs/speaker_inversion/nameThe saved checkpoints are embedding-only .speaker.safetensors files, for example
outputs/speaker_inversion/name/checkpoint_final.speaker.safetensors. Use that file
with the base model during inference:
uv run --no-sync python infer.py \
--checkpoint path/to/Irodori-TTS-v4.1-Small/model.safetensors \
--ref-embed outputs/speaker_inversion/name/checkpoint_final.speaker.safetensors \
--text "ใใใซใกใฏใใใใฏๅญฆ็ฟใใ่ฉฑ่
ๅใ่พผใฟใไฝฟใฃใๆจ่ซใงใใ" \
--output-wav outputs/sample_speaker_inversion.wavTo continue from a saved embedding, set speaker_inversion_init_embedding in the
config or pass --speaker-inversion-init-embedding path/to/checkpoint.speaker.safetensors.
Full trainer --resume is intentionally not used for Speaker Inversion checkpoints.
Enable gradient_checkpointing: true or pass --gradient-checkpointing if GPU memory is tight.
Resume an existing training run from a training checkpoint. Full-model runs use .pt; LoRA runs use checkpoint directories. Both restore optimizer, scheduler, and step state.
uv run --no-sync python train.py \
--config configs/train_v4_small.yaml \
--manifest data/train_manifest.jsonl \
--output-dir outputs/irodori_tts \
--resume outputs/irodori_tts/checkpoint_0010000.ptLoRA resume example:
uv run --no-sync python train.py \
--config configs/train_v4_small_lora.yaml \
--manifest data/train_manifest.jsonl \
--output-dir outputs/irodori_tts_lora \
--resume outputs/irodori_tts_lora/checkpoint_0010000If you move a LoRA checkpoint to another environment and the original base-checkpoint path is no longer valid, pass --init-checkpoint path/to/base_model.safetensors together with --resume to override the saved base-model path.
Convert a training checkpoint to inference-only safetensors format:
uv run --no-sync python convert_checkpoint_to_safetensors.py outputs/checkpoint_final.ptLoRA adapter checkpoints can also be converted directly:
uv run --no-sync python convert_checkpoint_to_safetensors.py outputs/irodori_tts_lora/checkpoint_finalLoRA adapter checkpoints are merged into the base model automatically during conversion, so the exported .safetensors file is directly usable for inference. If you do not want to merge the adapter, pass the adapter directory directly to infer.py --lora-adapter or the matching Gradio field.
For checkpoints with a pretrained text encoder, conversion also writes a tokenizer/
directory beside the safetensors file and embeds the encoder architecture config in the file.
Keep the safetensors file and tokenizer/ directory together when publishing or moving the model.
Quantized variants of Irodori-TTS reduce the memory required by the TTS model during inference. Pre-quantized v4-Small checkpoints are available from Aratako/Irodori-TTS-v4.1-Small-Quantized. Select a variant by appending its subdirectory name to the Hugging Face repository ID:
uv run --no-sync python infer.py \
--hf-checkpoint Aratako/Irodori-TTS-v4.1-Small-Quantized/int8-weight-only \
--model-precision bf16 \
--text "ใใใซใกใฏใ็งใฏAIใงใใ" \
--no-ref \
--output-wav outputs/sample_int8.wavAvailable schemes are int8-weight-only (W8A16), int8-dynamic (W8A8),
int4-weight-only (W4A16, group size 128 by default), float8-weight-only (FP8 weights
and BF16 activations), and float8-dynamic (FP8 weights and activations).
INT4 weight-only uses the CUDA tinygemm kernel and requires compute capability 8.0 or newer.
Only the selected model variant and its tokenizer assets are downloaded.
--model-precision bf16 controls the unquantized layers and floating-point activations;
quantized weights retain their stored quantization format.
To quantize another compatible inference checkpoint locally, use
quantize_checkpoint.py. INT8 weight-only is the default:
uv run --no-sync python quantize_checkpoint.py path/to/model.safetensors \
--quantization int8-weight-only \
--output path/to/quantized/model.safetensorsThe default core profile quantizes the attention and MLP weights in the text,
speaker, and diffusion Transformer blocks. Projectors, AdaLN, duration prediction,
and the codec remain unquantized. --profile all-linear is available for more aggressive
experimentation.
Dynamic --lora-adapter inference is supported with quantized base checkpoints.
Train the adapter against the matching full-precision base model.
Irodori-TTS/
โโโ train.py # Training entry point (DDP support)
โโโ infer.py # CLI inference
โโโ gradio_app.py # Gradio web UI
โโโ gradio_app_voicedesign.py # Gradio web UI for VoiceDesign checkpoints
โโโ prepare_manifest.py # Dataset -> DACVAE latent preprocessing
โโโ convert_checkpoint_to_safetensors.py # Checkpoint converter
โโโ quantize_checkpoint.py # torchao checkpoint quantization
โ
โโโ docs/
โ โโโ parameters.md # Detailed parameter guide
โ
โโโ irodori_tts/ # Core library
โ โโโ model.py # TextToLatentRFDiT architecture
โ โโโ rf.py # Rectified Flow utilities & Euler CFG sampling
โ โโโ codec.py # DACVAE codec wrapper
โ โโโ dataset.py # Dataset and collator
โ โโโ tokenizer.py # Pretrained LLM tokenizer wrapper
โ โโโ config.py # Model and training config dataclasses
โ โโโ inference_runtime.py # Cached, thread-safe inference runtime
โ โโโ lora.py # PEFT LoRA integration helpers
โ โโโ quantization.py # torchao checkpoint serialization/load helpers
โ โโโ speaker_inversion.py # Speaker Inversion embedding save/load helpers
โ โโโ text_normalization.py # Japanese text normalization
โ โโโ optim.py # Muon + AdamW optimizer
โ โโโ progress.py # Training progress tracker
โ
โโโ configs/
โโโ train_v4_small.yaml # Irodori-TTS-v4-Small training config
โโโ train_v4_small_lora.yaml # v4-Small LoRA fine-tuning config
โโโ train_v4_small_speaker_inversion.yaml # v4-Small Speaker Inversion config
โโโ train_500m_v3_phase1_body.yaml # 500M v3 body training config
โโโ train_500m_v3_phase2_duration.yaml # 500M v3 duration-predictor training config
โโโ train_500m_v3_voice_design_phase1_body.yaml # 600M v3 VoiceDesign body config
โโโ train_500m_v3_voice_design_phase2_duration.yaml # 600M v3 VoiceDesign duration config
โโโ train_500m_v3_voice_design_lora.yaml # 600M v3 VoiceDesign RF+duration LoRA config
โโโ train_500m_v3_lora.yaml # 500M v3 LoRA fine-tuning config
โโโ train_500m_v3_speaker_inversion.yaml # 500M v3 Speaker Inversion config
โโโ train_500m_v2.yaml # 500M v2 backward-compatible model config
โโโ train_500m_v2_lora.yaml # 500M v2 LoRA fine-tuning config
โโโ train_500m_v2_voice_design.yaml # 500M v2 VoiceDesign full fine-tuning config
โโโ train_500m_v2_voice_design_lora.yaml # 500M v2 VoiceDesign LoRA fine-tuning config
โโโ train_500m.yaml # 500M v1 model config
โโโ train_2.5b.yaml # 2.5B parameter model config
- Code: MIT License
- Model Weights: Please refer to the Irodori-TTS-v4.1-Small model card for licensing details
This project builds upon the following works:
- Echo-TTS โ Architecture and training design reference
- DACVAE โ Audio VAE
- SilentCipher โ Audio watermarking
@misc{irodori-tts,
author = {Chihiro Arata},
title = {Irodori-TTS: A Flow Matching-based Text-to-Speech Model with Emoji-driven Style Control},
year = {2026},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/Aratako/Irodori-TTS}}
}