User Tools

Site Tools


informatica:inteligencia_artificial:tts

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
informatica:inteligencia_artificial:tts [2026/06/25 16:46] joseinformatica:inteligencia_artificial:tts [2026/06/26 18:55] (current) jose
Line 130: Line 130:
 Uso: Uso:
   python generar_voz.py entrada.txt salida.mp3   python generar_voz.py entrada.txt salida.mp3
 +  
 +  
 +====== COQUI TTS ======
 +instalamos pyenv para poder tener python 3.11
 +  curl https://pyenv.run | bash
 +
 +Metemos esto en .bashrc
 +<code>
 +# Load pyenv automatically by appending
 +# the following to 
 +# ~/.bash_profile if it exists, otherwise ~/.profile (for login shells)
 +# and ~/.bashrc (for interactive shells) :
 +
 +export PYENV_ROOT="$HOME/.pyenv"
 +[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
 +eval "$(pyenv init - bash)"
 +
 +# Restart your shell for the changes to take effect.
 +
 +# Load pyenv-virtualenv automatically by adding
 +# the following to ~/.bashrc:
 +
 +eval "$(pyenv virtualenv-init -)"
 +</code>
 +
 +Cambiamos a python 3.11
 +  pyenv install 3.11.9
 +  pyenv global 3.11.9
 +
 +Reiniciar shell
 +
 +  git clone https://github.com/idiap/coqui-ai-TTS.git
 +  cd coqui-ai-TTS
 +Nos aseguramos versión 3.11 de python
 +  python --version
 +
 +Creamos entorno virtual
 +  python -m venv venv --clear
 +  source venv/bin/activate
 +  pip install -U pip setuptools wheel
 +  pip install --no-cache-dir torch torchaudio torchcodec
 +  pip install -e .
 +
 +Podemos listar los modelos:
 +  tts --list_models
 +
 +Ahora ya funciona, la primera vez se descarga el modelo y tarda bastante:
 +  tts   --text "Hola, esto es una prueba de Coqui TTS funcionando en español."   --model_name tts_models/es/css10/vits   --out_path salida.wav
 +
 +====== Entrenar COQUI TTS con XTTS======
 +Para entrenar a COQUI hay que hacerlo con el modelo de fine-tunning xtts_v2 pero siempre carga los modelos y tarda mínimo 15 segundos. Lo ideal es entrenar a VITS con muchos audios y la ejecución dura menos de 1 segundo. Lo explico mas abajo
 +
 +Tenemos que instalarlo con estable:
 +  git clone https://github.com/idiap/coqui-ai-TTS.git
 +  python3 -m venv venv
 +  pip install -U pip setuptools wheel
 +  pip install torch torchaudio torchcodec
 +
 +Tenía problemas e hice:
 +  pip install "torch<2.6" "torchaudio<2.6" --force-reinstall  
 +
 +<code>
 +tts \
 +  --model_name tts_models/multilingual/multi-dataset/xtts_v2 \
 +  --text "Hola, estoy probando mi propia voz clonada" \
 +  --speaker_wav /ruta/a/tu_audio.wav \
 +  --language_idx es \
 +  --out_path salida.wav
 +</code>
 +
 +Tarda 17 segundos
 +
 +Podemos calcular el espectro de nuestra voz una vez y pasarlo 
 +  calcular_voz.py
 +
 +<code>
 +import os
 +import torch
 +from TTS.tts.configs.xtts_config import XttsConfig
 +from TTS.tts.models.xtts import Xtts
 +
 +# 1. Fijamos la ruta real de la carpeta del snapshot que nos dio tu error
 +# (Quitamos el "model.pth/config.json" del final para quedarnos solo con la carpeta contenedora)
 +checkpoint_dir = os.path.expanduser("~/.cache/huggingface/hub/models--tts-hub--XTTS-v2/snapshots/345b56f6fbe25cca7103f7f34e471b8fe8e4945f")
 +config_file = os.path.join(checkpoint_dir, "config.json")
 +
 +print(f"-> Cargando modelo XTTS v2 desde: {checkpoint_dir}")
 +
 +if not os.path.exists(config_file):
 +    print(f"Error: No se encontró 'config.json' en la ruta {checkpoint_dir}")
 +    exit()
 +
 +# 2. Cargamos la configuración desde el archivo JSON
 +config = XttsConfig()
 +config.load_json(config_file)
 +
 +# 3. Inicializamos el modelo XTTS
 +model = Xtts(config)
 +model.load_checkpoint(config, checkpoint_dir=checkpoint_dir, eval=True)
 +
 +# 4. Listamos tus archivos WAV de referencia
 +folder = "./mis_audios"
 +if not os.path.exists(folder):
 +    os.makedirs(folder)
 +    print(f"\n[!] Se ha creado la carpeta '{folder}'.")
 +    print("Por favor, mete tus archivos .wav allí y vuelve a ejecutar este script.")
 +    exit()
 +
 +audio_files = [os.path.join(folder, f) for f in os.listdir(folder) if f.endswith('.wav')]
 +
 +if not audio_files:
 +    print(f"\n[!] Error: No se encontraron archivos .wav en la carpeta '{folder}'")
 +    print("Mete los audios con los que quieres entrenar tu voz ahí dentro.")
 +    exit()
 +
 +print(f"\nProcesando {len(audio_files)} archivos para crear tu huella de voz...")
 +
 +# 5. Calculamos los latents promediando todos los audios de la carpeta
 +gpt_conditioning_latents, speaker_embedding = model.get_conditioning_latents(audio_path=audio_files)
 +
 +# 6. Guardamos los vectores calculados
 +voice_data = {
 +    "gpt_conditioning_latents": gpt_conditioning_latents,
 +    "speaker_embedding": speaker_embedding
 +}
 +
 +output_path = "mi_voz_entrenada.pth"
 +torch.save(voice_data, output_path)
 +print(f"\n[OK] ¡Listo! Tu voz se ha promediado y guardado con éxito en '{output_path}'")
 +</code>
 +
 +Grabamos ficheros wav con nuestra voz en el directorio mis_audios
 +
 +  python calcular_voz.py
 +<code>
 +-> Cargando modelo XTTS v2 desde: .cache/huggingface/hub/models--tts-hub--XTTS-v2/snapshots/345b56f6fbe25cca7103f7f34e471b8fe8e4945f
 +
 +Procesando 1 archivos para crear tu huella de voz...
 +
 +[OK] ¡Listo! Tu voz se ha promediado y guardado con éxito en 'mi_voz_entrenada.pth'
 +</code>
 +
 +Luego ejecutamos el fichero hablar.py
 +
 +  hablar.py
 +
 +<code>
 +import os
 +import torch
 +import torchaudio
 +from TTS.tts.configs.xtts_config import XttsConfig
 +from TTS.tts.models.xtts import Xtts
 +
 +# 1. Texto a sintetizar y salida
 +texto_a_decir = "Hola, ahora estoy generando voz al vuelo de forma mucho más rápida y directa."
 +archivo_salida = "resultado_rapido2.wav"
 +
 +# 2. Rutas del modelo base
 +checkpoint_dir = os.path.expanduser("~/.cache/huggingface/hub/models--tts-hub--XTTS-v2/snapshots/345b56f6fbe25cca7103f7f34e471b8fe8e4945f")
 +config_file = os.path.join(checkpoint_dir, "config.json")
 +
 +# 3. Cargamos configuración y modelo
 +config = XttsConfig()
 +config.load_json(config_file)
 +model = Xtts(config)
 +model.load_checkpoint(config, checkpoint_dir=checkpoint_dir, eval=True)
 +
 +# 4. Cargamos tu huella de voz precalculada (.pth)
 +print("Cargando tu huella de voz precalculada...")
 +voice_data = torch.load("mi_voz_entrenada.pth", weights_only=False)
 +
 +# Mapeamos los nombres a lo que exige el método interno .inference()
 +gpt_cond_latent = voice_data["gpt_conditioning_latents"]
 +speaker_embedding = voice_data["speaker_embedding"]
 +
 +# 5. Inferencia con los nombres de variables exactos del código de Coqui
 +print("Sintetizando audio al vuelo...")
 +outputs = model.inference(
 +    text=texto_a_decir,
 +    language="es",
 +    gpt_cond_latent=gpt_cond_latent,
 +    speaker_embedding=speaker_embedding,
 +    temperature=config.temperature,
 +    length_penalty=config.length_penalty,
 +    repetition_penalty=config.repetition_penalty,
 +    top_k=config.top_k,
 +    top_p=config.top_p,
 +)
 +
 +# 6. Guardamos el resultado en un archivo .wav
 +audio_tensor = torch.tensor(outputs["wav"]).unsqueeze(0)
 +torchaudio.save(archivo_salida, audio_tensor, 24000)
 +
 +print(f"¡Listo! Audio generado súper rápido en: {archivo_salida}")
 +</code>
 +
 +====== Entrenar COQUI TTS con VITS ======
 +Necesitamos muchísimas horas de audio y preparar un dataset
 +
 +Creamos la siguiente estructura de ficheros
 +<code>
 +mi_dataset_vits/
 +├── wavs/
 +│   ├── 00001.wav
 +│   ├── 00002.wav
 +│   └── 00003.wav ... (todos tus archivos de audio)
 +└── metadata.csv
 +</code>
 +
 +El archivo metadata.csv tiene que tener el formato:
 +  00001|Hola, esta es la primera frase que grabé para mi modelo.
 +  00002|El entrenamiento de inteligencia artificial requiere paciencia.
 +  00003|Generar voz al vuelo ahora será inmediato.
 +
 +Script entrenamiento
 +
 +  entrenar_vits.py
 +
 +<code>
 +import os
 +from unicodedata import normalize
 +
 +from trainer import Trainer, TrainerArgs
 +
 +from TTS.config import BaseAudioConfig
 +from TTS.tts.configs.shared_configs import BaseDatasetConfig
 +from TTS.tts.configs.vits_config import VitsConfig
 +from TTS.tts.models.vits import CharactersConfig, Vits
 +
 +# 1. Rutas de carpetas
 +PATH_DATASET = "/Users/T054810/Personal/IA/coqui-ai-TTS_beta/mi_dataset_vits"
 +PATH_SALIDA = "/Users/T054810/Personal/IA/coqui-ai-TTS_beta/resultado_entrenamiento"
 +SPANISH_PUNCTUATIONS = "!'(),-.:;? ¡¿"
 +
 +# Incluimos el alfabeto base del español y completamos con cualquier carácter extra presente en el dataset.
 +BASE_SPANISH_CHARACTERS = "abcdefghijklmnopqrstuvwxyzáéíóúüñ0123456789"
 +
 +
 +def build_characters_config(texts: list[str]) -> CharactersConfig:
 +    normalized_text = normalize("NFC", " ".join(texts)).lower()
 +    discovered_characters = sorted(
 +        {
 +            char
 +            for char in normalized_text
 +            if not char.isspace() and char not in SPANISH_PUNCTUATIONS
 +        }
 +    )
 +    characters = "".join(dict.fromkeys(BASE_SPANISH_CHARACTERS + "".join(discovered_characters)))
 +
 +    return CharactersConfig(
 +        characters_class="TTS.tts.models.vits.VitsCharacters",
 +        pad="<PAD>",
 +        eos=None,
 +        bos=None,
 +        blank="<BLNK>",
 +        characters=characters,
 +        punctuations=SPANISH_PUNCTUATIONS,
 +        phonemes=None,
 +        is_unique=False,
 +        is_sorted=True,
 +    )
 +
 +
 +def load_samples(dataset_path: str) -> list[dict]:
 +    samples = []
 +    csv_path = os.path.join(dataset_path, "metadata.csv")
 +
 +    with open(csv_path, "r", encoding="utf-8") as file_handle:
 +        for line in file_handle:
 +            parts = line.strip().split("|")
 +            if len(parts) < 2:
 +                continue
 +
 +            audio_id, text = parts[0], parts[1]
 +            samples.append(
 +                {
 +                    "text": text,
 +                    "audio_file": os.path.join(dataset_path, "wavs", f"{audio_id}.wav"),
 +                    "speaker_name": "mi_voz",
 +                    "language": "es",
 +                    "audio_unique_name": audio_id,
 +                }
 +            )
 +
 +    return samples
 +
 +
 +def main():
 +    samples = load_samples(PATH_DATASET)
 +    if not samples:
 +        raise RuntimeError(f"No se encontraron muestras válidas en {PATH_DATASET}")
 +
 +    characters_config = build_characters_config([sample["text"] for sample in samples])
 +
 +# 2. Configurar el Dataset Base
 +    dataset_config = BaseDatasetConfig(
 +        formatter="ljspeech",
 +        path=PATH_DATASET,
 +        language="es",
 +    )
 +
 +# Configuración estándar de audio para VITS
 +    audio_config = BaseAudioConfig(
 +        sample_rate=22050,
 +        resample=True,
 +    )
 +
 +# 3. Configurar la arquitectura VITS
 +# 3. Configurar la arquitectura VITS (Modo caracteres puros, sin fonemas externos)
 +    config = VitsConfig(
 +        audio=audio_config,
 +        run_name="mi_voz_vits_rapida",
 +        batch_size=16,
 +        eval_batch_size=8,
 +        num_loader_workers=0,
 +        num_eval_loader_workers=0,
 +        run_eval=True,
 +        test_delay_epochs=5,
 +        epochs=100,
 +        text_cleaner="multilingual_cleaners",
 +        use_phonemes=False,
 +        datasets=[dataset_config],
 +        characters=characters_config,
 +        output_path=PATH_SALIDA,
 +    )
 +
 +    # Fuerza la serialización de `characters` para que el tokenizer use este vocabulario desde el config.
 +    config.from_dict(config.to_dict())
 +
 +    train_samples = samples
 +    eval_samples = samples[:1]
 +
 +    model = Vits(config)
 +
 +    trainer = Trainer(
 +        TrainerArgs(),
 +        config,
 +        output_path=PATH_SALIDA,
 +        model=model,
 +        train_samples=train_samples,
 +        eval_samples=eval_samples,
 +    )
 +
 +    print(f"Dataset cargado manualmente con éxito. Muestras encontradas: {len(samples)}")
 +    print(f"Vocabulario de texto preparado con {len(config.characters.characters)} caracteres.")
 +    print("Iniciando entrenamiento del modelo VITS con tu voz...")
 +    trainer.fit()
 +
 +
 +if __name__ == "__main__":
 +    main()
 +</code>
 +
 +Luego lo ejecutamos con (cambiar directorio de entreno):
 +  python entrenar_vits.py --device mps --continue_path resultado_entrenamiento/mi_voz_vits_rapida-June-26-2026_05+24PM-ca2cf515 --epochs 200
 +
 +En mi caso:
 +  python entrenar_vits.py --device mps --continue_path resultado_entrenamiento/entrenamiento1 --epochs 200
 +
 +MAC:
 +
 +Las notas de audio están en
 +  open ~/Library/Group\ Containers/group.com.apple.VoiceMemos.shared
 +
 +
 +
 +====== Gráficas de rendimiento ======
 +Levantamos servidor tensor con:
 +  tensorboard --logdir=/Users/T054810/Personal/IA/coqui-ai-TTS_beta/resultado_entrenamiento/
 +
 +Entramos en: http://localhost:6006/
 +
 +Sacado de chatGPT:
 +<code>
 +oss_disc y loss_gen: Son las gráficas de rendimiento del Discriminador y el Generador de VITS. Verás curvas que van bajando. Cuanto más abajo y estables estén, mejor y más limpia sonará tu voz.
 +
 +loss_mel: Te indica cómo de bien está aprendiendo el modelo a imitar las frecuencias exactas de tu tono de voz.
 +
 +Rendimiento de tiempo: Te muestra cuántos segundos tarda por cada paso de entrenamiento.
 +</code>
informatica/inteligencia_artificial/tts.1782406013.txt.gz · Last modified: by jose