Guía de Preparación de Datasets para TTS¶
Esta guía cubre la primera fase crítica de cualquier proyecto de TTS: preparar datos de audio y texto de alta calidad y con el formato correcto. La calidad de tu dataset impacta directamente en la calidad de tu modelo TTS final.
Si algún término de audio no te resulta familiar, consulta el glosario. Esta página solo se detiene en los términos que afectan directamente al paso que estás realizando.
Pasos de Preparación del Dataset¶
Sigue estos pasos de forma sistemática para transformar el audio en bruto en un dataset listo para entrenar.
1. Adquisición de Audio y Procesamiento Inicial¶
- Reunir Audio: Recopila tus archivos de audio en bruto (los formatos comunes incluyen WAV, MP3, FLAC, OGG, M4A). Asegúrate de tener los derechos para usar este audio.
- Convertir a WAV: La mayoría de los frameworks de TTS esperan el formato WAV. Usa herramientas como
ffmpego librerías de audio (pydub,soundfile) para convertir tu audio. Apunta a una codificación WAV estándar como PCM de 16 bits. - Estandarizar Canales (Mono): Los modelos TTS normalmente se entrenan con audio de un solo canal (mono). Convierte las pistas estéreo a mono.
# Ejemplo usando ffmpeg para convertir WAV estéreo a WAV mono ffmpeg -i stereo_input.wav -ac 1 mono_output.wav-ac 1: Establece el número de canales de audio en 1.
- Remuestrear Audio: Asegúrate de que todos los archivos de audio tengan exactamente el mismo sampling rate. Elige tu frecuencia objetivo según los objetivos de tu proyecto y la compatibilidad con el framework (por ejemplo, 16000 Hz, 22050 Hz, 48000 Hz). 22050 Hz es común para muchos modelos.
# Ejemplo usando ffmpeg para remuestrear a 22050 Hz ffmpeg -i input.wav -ar 22050 resampled_output.wav-ar 22050: Establece el sampling rate del audio (muestras por segundo).
Pequeña pero importante advertencia: no mezcles distintos sampling rates, distintas configuraciones de canales o archivos con clipping fuerte dentro del mismo dataset esperando que el modelo lo resuelva solo. Estas inconsistencias suelen aparecer después como voz ruidosa, inestable o poco natural.
2. Limpieza Avanzada del Audio (Eliminación de Ruido/Música) - Opcional pero Recomendado¶
- Objetivo: Eliminar sonidos de fondo no deseados como ruido (zumbidos, siseos, ventiladores), música, reverberación u otras voces que interfieran de tu audio fuente, aislando la voz del locutor objetivo en la medida de lo posible. Este paso es crucial si tu audio fuente no tiene calidad de estudio.
-
¿Por qué? Los modelos TTS aprenden del audio que se les proporciona. Si el audio contiene ruido de fondo o música, es probable que la voz TTS resultante herede estas características, sonando ruidosa o "turbia". Un audio más limpio conduce a una voz TTS más limpia.
-
Herramientas y Técnicas:
- Herramientas de Separación de Fuentes por IA (Recomendadas para Música/Voz): Estas herramientas usan modelos de IA para separar el audio en diferentes pistas (stems) (voces, música, batería, bajo, otros).
- Ultimate Vocal Remover (UVR): Una aplicación con interfaz gráfica (GUI) popular, gratuita y de código abierto que proporciona acceso a varios modelos de separación por IA de última generación. Es excelente para eliminar música de fondo o aislar diálogos.
- Modelos (como los mencionados): UVR te permite usar diferentes modelos de IA.
MDX-Inst-HQ3es uno de esos modelos, a menudo bueno para separar voces de instrumentos (de ahí "Inst"). Otros modelos MDX, los modelos Demucs (comohtdemucs) y, potencialmente, modelos como Mel-Roformer (si está integrado o disponible de forma independiente) están diseñados para tareas similares, cada uno con fortalezas y debilidades ligeramente diferentes. La experimentación es clave. Elige modelos enfocados en el aislamiento de voz.
- Modelos (como los mencionados): UVR te permite usar diferentes modelos de IA.
- Otras Herramientas: Los servicios en línea (por ejemplo, Lalal.ai) u otro software independiente podrían usar modelos subyacentes similares (a menudo variantes de Demucs o Spleeter).
- Ultimate Vocal Remover (UVR): Una aplicación con interfaz gráfica (GUI) popular, gratuita y de código abierto que proporciona acceso a varios modelos de separación por IA de última generación. Es excelente para eliminar música de fondo o aislar diálogos.
- Herramientas Tradicionales de Reducción de Ruido: A menudo se encuentran en estaciones de trabajo de audio digital (DAWs) o editores de audio.
- Audacity: Contiene efectos integrados de reducción de ruido (requiere muestrear un perfil de ruido). Puede ser eficaz para el ruido de fondo constante (como siseos o zumbidos).
- Plugins Comerciales (por ejemplo, Izotope RX, Waves Clarity): Ofrecen herramientas de aislamiento de voz, ruido y reverberación más sofisticadas y basadas en IA, pero tienen un coste.
- Edición Espectral: Eliminar manualmente sonidos no deseados en un editor espectral (como Adobe Audition, Izotope RX, Acon Digital Acoustica). Potente, pero muy laborioso.
- Herramientas de Separación de Fuentes por IA (Recomendadas para Música/Voz): Estas herramientas usan modelos de IA para separar el audio en diferentes pistas (stems) (voces, música, batería, bajo, otros).
-
Consideraciones sobre el Flujo de Trabajo:
- Cuándo Aplicarlo: Generalmente se recomienda aplicar la limpieza a tus archivos de audio más largos antes de la segmentación (Paso 1.3 a continuación). Esto permite que los modelos de IA trabajen con más contexto y puede ser más eficiente que procesar miles de segmentos pequeños. Sin embargo, si la limpieza introduce demasiados artefactos en los archivos largos, podrías intentar limpiar individualmente los segmentos problemáticos más adelante.
- Proceso:
- Carga tu archivo WAV estandarizado (del Paso 1.1) en la herramienta elegida (por ejemplo, UVR).
- Selecciona un modelo de aislamiento de voz apropiado (por ejemplo, un modelo de voz MDX o Demucs).
- Procesa el audio para generar una pista de "solo voces".
- Escucha con Atención: Evalúa críticamente la pista de voz separada. Comprueba si hay:
- Artefactos: La separación por IA a veces puede introducir sonidos "acuosos", fallos (glitches), o partes de la voz que se eliminan por error.
- Ruido/Música Restantes: ¿Con qué eficacia se eliminó el sonido no deseado?
- Itera: Es posible que necesites probar diferentes modelos, ajustar la configuración dentro de la herramienta, o incluso aplicar una segunda pasada de reducción de ruido (por ejemplo, usando la reducción de ruido de Audacity sobre las voces separadas por IA) para obtener los mejores resultados.
- Guardar la Salida: Guarda la pista de voz limpia como un nuevo archivo WAV (por ejemplo,
original_file_cleaned.wav). Usa estos archivos limpios como entrada para el siguiente paso (Segmentación).
-
Advertencias:
- Los Artefactos son Posibles: Una limpieza agresiva puede degradar la naturalidad de la voz objetivo. Busca un equilibrio entre eliminar el ruido y preservar la calidad de la voz.
- Coste Computacional: Los modelos de separación por IA pueden ser computacionalmente intensivos y pueden requerir un tiempo significativo, especialmente en archivos de audio largos y sin una GPU potente.
3. Segmentación del Audio (División en Segmentos)¶
- Objetivo: Dividir archivos de audio largos (como capítulos de un audiolibro o episodios de podcast) en segmentos más cortos y manejables. La duración ideal de un segmento suele estar entre 2 y 15 segundos.
- ¿Por qué Segmentar?
- Alinea la duración del audio con las longitudes típicas de las frases.
- Hace factible la transcripción (transcribir archivos de horas de duración es difícil).
- Ayuda a gestionar la memoria durante el entrenamiento.
- Permite filtrar segmentos no aptos (por ejemplo, silencio puro, ruido, música).
-
Método: Usa herramientas que detecten el silencio para dividir el audio.
pydubes una librería de Python popular para esto.- Revisión: Escucha una muestra de los segmentos generados. ¿Son lógicas las divisiones? ¿Se corta el habla? Ajusta# Ejemplo usando pydub para la división basada en silencio from pydub import AudioSegment from pydub.silence import split_on_silence import os input_file = "resampled_mono_audio.wav" # Usa la salida del paso 1.1 output_dir = "audio_chunks" # Crea este directorio os.makedirs(output_dir, exist_ok=True) print(f"Loading audio file: {input_file}") sound = AudioSegment.from_wav(input_file) print("Audio loaded. Splitting based on silence...") chunks = split_on_silence( sound, min_silence_len=500, # Duración mínima del silencio en milisegundos para activar una división. Ajusta según sea necesario. silence_thresh=-40, # Umbral de silencio en dBFS (decibelios relativos a la escala completa). Valores más bajos (p. ej., -50) detectan silencios más tenues. Ajusta según el nivel de ruido de fondo de tu audio. keep_silence=200 # Opcional: cantidad de silencio (en ms) a dejar al inicio/final de cada segmento. Ayuda a evitar cortes bruscos. ) print(f"Found {len(chunks)} potential chunks before duration filtering.") # --- Filtrado y Exportación --- min_duration_sec = 2.0 # Duración mínima del segmento en segundos max_duration_sec = 15.0 # Duración máxima del segmento en segundos target_sr = 22050 # Asegura que los segmentos conserven el sampling rate correcto (pydub suele encargarse de esto) exported_count = 0 for i, chunk in enumerate(chunks): duration_sec = len(chunk) / 1000.0 if min_duration_sec <= duration_sec <= max_duration_sec: # Asegura que el segmento use el sampling rate objetivo si es necesario (pydub intenta preservarlo) # chunk = chunk.set_frame_rate(target_sr) # Normalmente no es necesario si la fuente se muestreó correctamente chunk_filename = f"segment_{exported_count:05d}.wav" # Usa relleno (padding) para facilitar la ordenación chunk_path = os.path.join(output_dir, chunk_filename) print(f"Exporting chunk {i} ({duration_sec:.2f}s) to {chunk_path}") chunk.export(chunk_path, format="wav") exported_count += 1 else: print(f"Skipping chunk {i} due to duration: {duration_sec:.2f}s") print(f"\nExported {exported_count} chunks meeting duration criteria ({min_duration_sec}-{max_duration_sec}s) to '{output_dir}'.")min_silence_lenysilence_threshy vuelve a ejecutar si es necesario. Para audio complicado podría ser necesario dividir o refinar las divisiones manualmente en un editor de audio (como Audacity).
4. Normalización de Volumen¶
- Objetivo: Asegurar que todos los segmentos de audio tengan un nivel de volumen consistente. Esto evita que los segmentos silenciosos o ruidosos afecten de forma desproporcionada al entrenamiento.
- Métodos:
- Normalización de Pico (Peak Normalization): Ajusta el audio para que el punto más alto alcance un nivel específico (por ejemplo, -3.0 dBFS). Simple, pero no garantiza una sonoridad percibida consistente.
- Normalización de Sonoridad (LUFS): Ajusta el audio para alcanzar un nivel de sonoridad percibida objetivo (por ejemplo, -23 LUFS es común para radiodifusión). Generalmente preferida, ya que refleja mejor la audición humana. Requiere librerías como
pyloudnorm.
-
Aplicar de Forma Consistente: Aplica el método de normalización elegido a todos los segmentos creados en el paso anterior. Guarda los archivos normalizados en un nuevo directorio (por ejemplo,
normalized_chunks) para mantener los originales intactos.* Nota: Para la normalización LUFS, usarías una librería como# Ejemplo usando pydub para la normalización de PICO (PEAK) from pydub import AudioSegment import os import glob input_chunk_dir = "audio_chunks" output_norm_dir = "normalized_chunks" os.makedirs(output_norm_dir, exist_ok=True) target_dBFS = -3.0 # Amplitud de pico objetivo def match_target_amplitude(sound, target_dBFS): change_in_dBFS = target_dBFS - sound.dBFS return sound.apply_gain(change_in_dBFS) print(f"Normalizing chunks from '{input_chunk_dir}' to '{output_norm_dir}' with target peak {target_dBFS} dBFS.") wav_files = glob.glob(os.path.join(input_chunk_dir, "*.wav")) for i, wav_file in enumerate(wav_files): filename = os.path.basename(wav_file) output_path = os.path.join(output_norm_dir, filename) try: sound = AudioSegment.from_wav(wav_file) # Aplica ganancia solo si el sonido no es silencio (dBFS no es -inf) if sound.dBFS > -float('inf'): normalized_sound = match_target_amplitude(sound, target_dBFS) normalized_sound.export(output_path, format="wav") else: print(f"Skipping silent file: {filename}") # Opcionalmente copia los archivos silenciosos o gestiónalos según sea necesario # shutil.copy(wav_file, output_path) if (i + 1) % 50 == 0: # Imprime el progreso print(f"Processed {i+1}/{len(wav_files)} files...") except Exception as e: print(f"Error processing {filename}: {e}") print(f"\nNormalization complete. Normalized files saved in '{output_norm_dir}'.")pyloudnorm, iterando por los archivos de forma similar.
5. Transcripción: Creación de Pares de Texto¶
- Objetivo: Obtener una transcripción de texto precisa para cada uno de los segmentos de audio normalizados. El texto debe representar exactamente lo que se dice en el audio.
- Métodos:
- Reconocimiento Automático del Habla (ASR): Lo mejor para datasets grandes. Usa modelos ASR de alta calidad.
- OpenAI Whisper: Una excelente opción multilingüe y de código abierto. Se ejecuta localmente (se recomienda GPU) o a través de API. Nota: Aunque es potente para la precisión de las palabras, la puntuación y el uso de mayúsculas de Whisper pueden requerir una revisión y corrección cuidadosas durante el paso de limpieza. Varios modelos de Whisper con fine-tuning de la comunidad (a menudo encontrados en Hugging Face) pueden ofrecer mejoras.
- Modelos Google Gemini (por ejemplo, vía API o AI Studio): Modelos como Gemini Pro o Flash pueden realizar la transcripción de audio. A menudo requieren que el audio esté en formatos específicos y pueden rendir mejor en segmentos más cortos (alineándose bien con el paso previo de segmentación). Comprueba las ofertas actuales de la API y los posibles niveles gratuitos.
- Servicios en la Nube: Google Cloud Speech-to-Text, AWS Transcribe, Azure Speech Service ofrecen APIs robustas, a menudo con precios de pago por uso y posibles niveles gratuitos iniciales.
- Otros Modelos: Explora Hugging Face Models para encontrar otros modelos ASR de código abierto o con fine-tuning específicos para tu idioma.
- Transcripción Manual: La más precisa, pero muy laboriosa. Adecuada para datasets pequeños y de alto valor o para corregir las salidas de ASR.
- Transcripciones Existentes: Si tu audio fuente viene con transcripciones alineadas (por ejemplo, algunos audiolibros, archivos de radiodifusión), es posible que necesites scripts para analizarlas y alinearlas con tus segmentos.
- Advertencia: Los nombres de modelos, los límites de API y los precios de servicios externos pueden cambiar con rapidez. Verifica siempre la documentación actual antes de depender de un servicio ASR alojado concreto.
- Formato de Salida: Crea un archivo
.txtpor cada archivo.wavcorrespondiente en tu directorionormalized_chunks. Los nombres de los archivos deben coincidir exactamente (por ejemplo,normalized_chunks/segment_00001.wavnecesitatranscripts/segment_00001.txt). -
Limpieza y Normalización del Texto: ¡Esto es crucial!
- Eliminar Elementos que no son Habla: Elimina marcas de tiempo (como
[00:01:05]), etiquetas de locutor ("SPEAKER A:", "John Doe:"), etiquetas de eventos sonoros ([laughter],[music]), comentarios de transcripción. - Gestionar Muletillas (Filler Words): Decide si conservar o eliminar las muletillas comunes ("uh", "um", "ah"). Conservarlas puede hacer que el TTS suene más natural, pero también puede introducir vacilaciones no deseadas. Eliminarlas conduce a un habla más limpia y directa. La consistencia es clave.
- Puntuación: Asegura una puntuación consistente y apropiada. Las comas, puntos y signos de interrogación ayudan al modelo a aprender la prosodia. Evita la puntuación excesiva o no estándar.
- Números, Acrónimos, Símbolos: Expándelos a palabras (por ejemplo, "101" -> "ciento uno", "EE. UU." -> "E E U U" o "Estados Unidos de América", "%" -> "por ciento"). La forma de expandirlos depende de cómo quieras que el TTS los pronuncie. Crea un diccionario/conjunto de reglas de normalización si es necesario.
- Mayúsculas/Minúsculas: Normalmente convierte el texto a un formato consistente (por ejemplo, minúsculas), a menos que tu framework/tokenizador de TTS gestione las mayúsculas adecuadamente. Consulta la documentación del framework.
- Caracteres Especiales: Elimina o reemplaza los caracteres que podrían confundir al tokenizador (por ejemplo, emojis, caracteres de control).
flowchart TD dataset["my_tts_dataset/"] audio["normalized_chunks/"] wav1["segment_00001.wav"] wav2["segment_00002.wav"] wavMore["..."] transcripts["transcripts/"] txt1["segment_00001.txt<br/>Contiene: Hola mundo."] txt2["segment_00002.txt<br/>Contiene: Esta es una frase de prueba."] txtMore["..."] dataset --> audio audio --> wav1 audio --> wav2 audio --> wavMore dataset --> transcripts transcripts --> txt1 transcripts --> txt2 transcripts --> txtMore - Eliminar Elementos que no son Habla: Elimina marcas de tiempo (como
6. Estructuración de los Datos y Creación del Archivo Manifest¶
- Objetivo: Crear archivos de índice (manifests) que le indiquen al script de entrenamiento de TTS dónde encontrar los archivos de audio y sus transcripciones correspondientes.
- Formato del Manifest: El formato más común es un archivo de texto plano donde cada línea representa un par de audio-texto, separados por un delimitador (normalmente una barra vertical
|).path/to/audio_chunk.wav: Ruta relativa al archivo de audio normalizado desde el directorio donde se ejecutará el script de entrenamiento.El texto de transcripción correspondiente: El texto limpio y normalizado del archivo.txt.speaker_id: Un identificador para el locutor (por ejemplo,speaker0,mary_smith). Para datasets de un solo locutor, usa el mismo ID para todas las líneas. Para datasets multi-locutor, usa IDs únicos para cada locutor distinto.
- División de los Datos (Entrenamiento/Validación): Divide tus datos en un conjunto de entrenamiento (usado para actualizar los pesos del modelo) y un conjunto de validación (usado para monitorizar el rendimiento sobre datos no vistos y prevenir el overfitting). Una división común es del 90-98% para entrenamiento y del 2-10% para validación. De forma crucial, asegúrate de que los segmentos de una misma grabación larga original no acaben en ambos conjuntos (entrenamiento y validación) si es posible, para evitar fugas de datos (data leakage). Si divides de forma aleatoria, mezcla (shuffle) primero.
- Opción segura para principiantes: Si todavía no tienes una estrategia mejor, una validación pequeña pero representativa suele ser suficiente. Una división simple 95/5 suele funcionar bien para una primera pasada, siempre que no mezcles fragmentos del mismo audio largo original entre entrenamiento y validación.
- Advertencia sobre rutas: Muchos frameworks TTS esperan que las rutas de audio dentro del manifest sean relativas a un directorio de trabajo concreto, no relativas al propio archivo manifest. Antes de entrenar, abre una línea del manifest y comprueba que el script realmente puede resolver esa ruta desde el directorio donde vas a ejecutar
train.py. -
Script para Generar Manifests:
import os import random # --- Configuración --- dataset_name = "my_tts_dataset" normalized_audio_dir = os.path.join(dataset_name, "normalized_chunks") transcripts_dir = os.path.join(dataset_name, "transcripts") output_dir = dataset_name # Donde se guardarán los archivos manifest train_manifest_path = os.path.join(output_dir, "train_list.txt") val_manifest_path = os.path.join(output_dir, "val_list.txt") speaker_id = "main_speaker" # Usa un ID consistente para datasets de un solo locutor # Para multi-locutor, determina el ID según el nombre de archivo o la fuente val_split_ratio = 0.05 # 5% para el conjunto de validación random_seed = 42 # Para divisiones reproducibles # --------------------- manifest_entries = [] print("Reading audio and transcript files...") # Itera por los archivos de audio normalizados wav_files = sorted([f for f in os.listdir(normalized_audio_dir) if f.endswith(".wav")]) for wav_filename in wav_files: base_filename = os.path.splitext(wav_filename)[0] txt_filename = base_filename + ".txt" audio_path = os.path.join(normalized_audio_dir, wav_filename) # Usa os.path.relpath si tu script de entrenamiento se ejecuta desde una raíz diferente # relative_audio_path = os.path.relpath(audio_path, start=training_script_dir) relative_audio_path = audio_path # Asumiendo que el script se ejecuta desde la raíz que contiene 'my_tts_dataset' transcript_path = os.path.join(transcripts_dir, txt_filename) if os.path.exists(transcript_path): try: with open(transcript_path, "r", encoding="utf-8") as f: transcript = f.read().strip() # Limpieza básica: elimina caracteres de barra vertical, recorta espacios sobrantes transcript = transcript.replace('|', ' ').strip() transcript = ' '.join(transcript.split()) # Normaliza los espacios en blanco if transcript: # Asegura que la transcripción no esté vacía tras la limpieza manifest_entries.append(f"{relative_audio_path}|{transcript}|{speaker_id}") else: print(f"Warning: Empty transcript for {wav_filename}. Skipping.") except Exception as e: print(f"Error reading or processing transcript {txt_filename}: {e}. Skipping.") else: print(f"Warning: Missing transcript file {txt_filename} for {wav_filename}. Skipping.") print(f"Found {len(manifest_entries)} valid audio-transcript pairs.") # Mezcla y divide random.seed(random_seed) random.shuffle(manifest_entries) split_idx = int(len(manifest_entries) * (1 - val_split_ratio)) train_entries = manifest_entries[:split_idx] val_entries = manifest_entries[split_idx:] # Escribe los archivos manifest try: with open(train_manifest_path, "w", encoding="utf-8") as f: f.write("\n".join(train_entries)) print(f"Successfully wrote {len(train_entries)} entries to {train_manifest_path}") with open(val_manifest_path, "w", encoding="utf-8") as f: f.write("\n".join(val_entries)) print(f"Successfully wrote {len(val_entries)} entries to {val_manifest_path}") except Exception as e: print(f"Error writing manifest files: {e}")
Scripts Prácticos de Verificación¶
Aquí tienes algunos scripts prácticos para ayudarte a verificar la calidad de tu dataset:
Comprobar las Propiedades del Audio (Sampling Rate, Canales, Duración)¶
#!/bin/bash
# verify_audio.sh - Comprueba las propiedades del audio en todos los archivos WAV
# Uso: ./verify_audio.sh /path/to/audio/directory
AUDIO_DIR="$1"
echo "Checking audio files in $AUDIO_DIR..."
# Comprueba si SoX está instalado
if ! command -v soxi &> /dev/null; then
echo "SoX not found. Please install it first (e.g., 'apt-get install sox' or 'brew install sox')."
exit 1
fi
# Inicializa contadores y arrays
total_files=0
non_mono=0
wrong_rate=0
too_short=0
too_long=0
target_rate=22050 # Cambia esto por tu sampling rate objetivo
min_duration=1.0 # Duración mínima en segundos
max_duration=15.0 # Duración máxima en segundos
# Procesa todos los archivos WAV
find "$AUDIO_DIR" -name "*.wav" | while read -r file; do
total_files=$((total_files + 1))
# Obtiene las propiedades del audio
channels=$(soxi -c "$file")
rate=$(soxi -r "$file")
duration=$(soxi -d "$file" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
# Comprueba las propiedades
if [ "$channels" -ne 1 ]; then
echo "WARNING: Non-mono file: $file (channels: $channels)"
non_mono=$((non_mono + 1))
fi
if [ "$rate" -ne "$target_rate" ]; then
echo "WARNING: Wrong sampling rate: $file (rate: $rate Hz, expected: $target_rate Hz)"
wrong_rate=$((wrong_rate + 1))
fi
if (( $(echo "$duration < $min_duration" | bc -l) )); then
echo "WARNING: File too short: $file (duration: ${duration}s, minimum: ${min_duration}s)"
too_short=$((too_short + 1))
fi
if (( $(echo "$duration > $max_duration" | bc -l) )); then
echo "WARNING: File too long: $file (duration: ${duration}s, maximum: ${max_duration}s)"
too_long=$((too_long + 1))
fi
# Imprime el progreso cada 100 archivos
if [ $((total_files % 100)) -eq 0 ]; then
echo "Processed $total_files files..."
fi
done
# Imprime el resumen
echo "===== SUMMARY ====="
echo "Total files checked: $total_files"
echo "Non-mono files: $non_mono"
echo "Files with wrong sampling rate: $wrong_rate"
echo "Files too short (<${min_duration}s): $too_short"
echo "Files too long (>${max_duration}s): $too_long"
if [ $((non_mono + wrong_rate + too_short + too_long)) -eq 0 ]; then
echo "All files passed basic checks!"
else
echo "Some issues were found. Please review the warnings above."
fi
Verificar la Integridad del Archivo Manifest¶
#!/usr/bin/env python3
# verify_manifest.py - Comprueba que todos los archivos del manifest existen y tienen transcripciones coincidentes
# Uso: python verify_manifest.py path/to/manifest.txt
import os
import sys
from pathlib import Path
def verify_manifest(manifest_path):
"""Verifica que todos los archivos de audio y transcripciones del manifest existen y son válidos."""
if not os.path.exists(manifest_path):
print(f"Error: Manifest file '{manifest_path}' not found.")
return False
print(f"Verifying manifest: {manifest_path}")
base_dir = os.path.dirname(os.path.abspath(manifest_path))
# Estadísticas
total_entries = 0
missing_audio = 0
empty_transcripts = 0
with open(manifest_path, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
total_entries += 1
# Analiza la línea (asumiendo formato separado por barra vertical: audio_path|transcript|speaker_id)
parts = line.split('|')
if len(parts) < 2:
print(f"Line {line_num}: Invalid format. Expected at least 'audio_path|transcript'")
continue
audio_path = parts[0]
transcript = parts[1]
# Comprueba si la ruta del audio es relativa y resuélvela
if not os.path.isabs(audio_path):
audio_path = os.path.join(base_dir, audio_path)
# Comprueba si el archivo de audio existe
if not os.path.exists(audio_path):
print(f"Line {line_num}: Audio file not found: {audio_path}")
missing_audio += 1
# Comprueba si la transcripción está vacía
if not transcript or transcript.isspace():
print(f"Line {line_num}: Empty transcript for {audio_path}")
empty_transcripts += 1
# Imprime el resumen
print("\n===== SUMMARY =====")
print(f"Total entries: {total_entries}")
print(f"Missing audio files: {missing_audio}")
print(f"Empty transcripts: {empty_transcripts}")
if missing_audio == 0 and empty_transcripts == 0:
print("All manifest entries are valid!")
return True
else:
print("Issues found in manifest. Please fix them before proceeding.")
return False
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python verify_manifest.py path/to/manifest.txt")
sys.exit(1)
success = verify_manifest(sys.argv[1])
sys.exit(0 if success else 1)
Visualizar Espectrogramas de Audio para Evaluar la Calidad¶
Este script te ayuda a inspeccionar visualmente la calidad de tus archivos de audio generando espectrogramas:
#!/usr/bin/env python3
# generate_spectrograms.py - Crea espectrogramas para evaluar la calidad del audio
# Uso: python generate_spectrograms.py /path/to/audio/directory /path/to/output/directory [num_samples]
import os
import sys
import random
import numpy as np
import matplotlib.pyplot as plt
import librosa
import librosa.display
from pathlib import Path
def generate_spectrograms(audio_dir, output_dir, num_samples=10):
"""Genera espectrogramas para una muestra aleatoria de archivos de audio."""
# Crea el directorio de salida si no existe
os.makedirs(output_dir, exist_ok=True)
# Obtiene todos los archivos WAV
wav_files = list(Path(audio_dir).glob('**/*.wav'))
if not wav_files:
print(f"No WAV files found in {audio_dir}")
return False
# Toma una muestra de los archivos si hay más de los solicitados
if len(wav_files) > num_samples:
wav_files = random.sample(wav_files, num_samples)
print(f"Generating spectrograms for {len(wav_files)} files...")
for i, wav_path in enumerate(wav_files):
try:
# Carga el archivo de audio
y, sr = librosa.load(wav_path, sr=None)
# Crea la figura con dos subgráficos
plt.figure(figsize=(12, 8))
# Dibuja la forma de onda
plt.subplot(2, 1, 1)
librosa.display.waveshow(y, sr=sr)
plt.title(f'Waveform: {wav_path.name}')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
# Dibuja el espectrograma
plt.subplot(2, 1, 2)
D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
librosa.display.specshow(D, sr=sr, x_axis='time', y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Log-frequency power spectrogram')
# Guarda la figura
output_path = os.path.join(output_dir, f'spectrogram_{i+1}_{wav_path.stem}.png')
plt.tight_layout()
plt.savefig(output_path)
plt.close()
print(f"Generated: {output_path}")
except Exception as e:
print(f"Error processing {wav_path}: {e}")
print(f"Spectrograms saved to {output_dir}")
return True
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python generate_spectrograms.py /path/to/audio/directory /path/to/output/directory [num_samples]")
sys.exit(1)
audio_dir = sys.argv[1]
output_dir = sys.argv[2]
num_samples = int(sys.argv[3]) if len(sys.argv) > 3 else 10
success = generate_spectrograms(audio_dir, output_dir, num_samples)
sys.exit(0 if success else 1)
Estos scripts proporcionan herramientas prácticas para verificar la calidad de tu dataset antes del entrenamiento, ayudándote a identificar y solucionar problemas en una fase temprana del proceso.
Checklist de Calidad de los Datos¶
Antes de pasar a la configuración del entrenamiento, haz una revisión final rápida del dataset preparado:
- Todos los archivos
.wavlistados en los manifests existen realmente. - Cada segmento de audio tiene su transcripción correspondiente y los nombres coinciden.
- La mayoría de los segmentos está dentro del rango de duración esperado y hay pocos valores atípicos.
- Las muestras aleatorias que escuchas no tienen ruido fuerte, música, eco ni otros locutores no deseados.
- Todos los archivos usan el mismo sampling rate, el mismo número de canales y el mismo formato esperado.
- Los volúmenes son razonablemente consistentes entre segmentos.
- Las transcripciones están limpias: sin timestamps, sin etiquetas de locutor y con puntuación coherente.
- El manifest usa el formato correcto y las rutas funcionan desde la carpeta donde vas a ejecutar
train.py. - El conjunto de validación no se solapa con el de entrenamiento.
Consejo: Usa herramientas como soxi (de SoX) o ffprobe para comprobar por lotes las propiedades del audio (sampling rate, canales, duración). Escribe pequeños scripts para verificar la existencia de los archivos y el formato básico del manifest.
Una vez que tu dataset pase esta comprobación de calidad, estarás listo para proceder con la configuración del entorno de entrenamiento.