Saltar a contenido

Audio en Hugging Face

Tal como vimos en la sesión de Hugging Face, existen múltiples modelos tanto para el reconocimiento del audio (ASR - Automatic Speech Recognition), como para el paso de texto a audio (TTS - Text-to-Speech), así como nuevos modelos centrados en la generación de audio y música.

En esta sesión vamos a realizar algunos casos de uso sencillos sobre los dos primeros tipo de modelos de audio mediante Hugging Face.

Caso 1: ASR con Whisper

A día de hoy, uno de los modelos que mejor funciona reconociendo la voz humana es Whisper, de Open AI, el cual podemos utilizar desde Hugging Face

Tamaños y parámetros

El modelo está disponible en 5 tamaños. Los cuatro más pequeños se entrenan con datos en inglés o multilingües, mientras que el más grandes sólo multilingües:

Tamaño Parámetros
tiny 39M
base 74M
small 244M
medium 769M
large 1550M
large-v2 1550M

Whisper es un modelo codificador-decodificador basado en transformers, también conocido como modelo secuencia a secuencia. Se entrenó con 680.000 horas de datos de voz etiquetados y anotados mediante una supervisión débil a gran escala.

Los modelos se entrenaron con datos en inglés y con datos multilingües. Los modelos en inglés se entrenaron para la tarea de reconocimiento del habla. Los modelos multilingües se entrenaron tanto para el reconocimiento como para la traducción. Para el reconocimiento de voz, el modelo predice transcripciones en el mismo idioma que el audio. Para la traducción del habla, el modelo predice transcripciones a un idioma distinto al del audio.

Haciendo uso de Gradio, vamos a utilizar Whisper para transcribir un audio. El primer paso es instalar las librerías necesarias:

pip install torch torchaudio

Y a continuación, haciendo uso de un pipeline, vamos a cargar el modelo base y realizar la inferencia. La función transcribe toma un único parámetro un audio como un array NumPy del audio grabado por el usuario. El objeto pipeline lo espera en formato float32, así que primero lo convertimos y luego extraemos el texto transcrito.

gradio-whisper.py
import torch
from transformers import pipeline
import numpy as np

pipe = pipeline(
    "automatic-speech-recognition", model="openai/whisper-base"
)

def transcribe(audio):
    sr, y = audio
    # Pasamos el array de muestras a tipo NumPy de 32 bits
    y = y.astype(np.float32)
    y /= np.max(np.abs(y))

    return pipe({"sampling_rate": sr, "raw": y})["text"]

import gradio as gr

demo = gr.Interface(
    transcribe,
    gr.Audio(sources=["microphone"]),
    "text",
)

demo.launch()

Para ponerlo en marcha, lanzamos el gradio:

gradio gradio-whisper.py

Obteniendo:

Gradio con Whisper
Gradio con Whisper

Caso 2: Whisper en streaming

¿Y podemos hacer que en vez de esperar a tener todo un audio, se dedique a transcribir el texto conforme vayamos hablando?

Para que el caso anterior funcione en streaming, necesitamos:

  • Indicar streaming=True en el componente de Audio
  • Indicar live=True en Interface
  • Añadir un estado en el interfaz para almacenar el audio grabado por el usuario, a modo de historial

A medida que se ejecuta la interfaz, se llama a la función transcribe, con un registro de todo el audio hablado previamente en stream, así como el nuevo trozo de audio como nuevo_fragmento, y devuelve el nuevo audio completo para que pueda ser almacenado de nuevo en el estado, y la nueva transcripción (*no es la solución más optima, ya que no hace falta volver la transcripción de todo el audio almacenado - probablemente, con los últimos 5 segundos sería suficiente):

gradio-whisper-streaming.py
from transformers import pipeline
import numpy as np
import gradio as gr

pipe = pipeline(
    "automatic-speech-recognition", model="openai/whisper-base"
)

def transcribe(stream, nuevo_fragmento):
    sr, y = nuevo_fragmento
    y = y.astype(np.float32)
    y /= np.max(np.abs(y))

    if stream is not None:
        stream = np.concatenate([stream, y])
    else:
        stream = y

    return stream, pipe({"sampling_rate": sr, "raw": stream})["text"]

demo = gr.Interface(
    transcribe,
    ["state", gr.Audio(sources=["microphone"], streaming=True)],
    ["state", "text"],
    live=True,
)

demo.launch()

Podemos observar como en un primer momento, realiza una inferencia del idioma, y a continuación, conforme hablamos, va generando el texto:

Gradio con Whisper en Streaming
Gradio con Whisper en Streaming

Caso 3: De Whisper a Bark

Para cerrar el circulo, vamos a realizar un ejemplo donde la salida del primer modelo, sea la entrada de un segundo modelo que genere un audio a partir del texto saliente de Whisper.

Caso 3a: TTS mediante Bark

Como TTS, vamos a utilizar el modelo Bark, el cual, además de ser multi-idioma, también permite incluir sonidos como música, sonrisas, tos, etc...

gradio-bark.py
from transformers import pipeline
import gradio as gr

pipe = pipeline("text-to-speech", model="suno/bark-small")

def tts(frase):
    audio_generated = pipe(frase)

    return audio_generated["sampling_rate"],audio_generated["audio"][0]

demo = gr.Interface(
    tts,
    inputs=gr.Text(label="Teclea el texto a pronunciar"),
    outputs=gr.Audio(label="audio generado"),
    title="De texto a voz",
)

demo.launch()

Así pues, ahora tras introducir un texto, por ejemplo Hola, ¿Cómo estás? ... ¡De lujo! [laughs], obtenemos un audio con la voz generada, donde se puede comprobar la entonación, la elipsis, y las risas finales:

Gradio con Bark
Gradio con Bark

Configurando Bark

Si queremos configurar el tono de la voz, si es un hombre o una mujer, incluso "ayudarle" con el idioma a emplear, en vez de acceder via un Pipeline, accederemos mediante un AutoProcessor y el BarkModel:

gradio-bark-processor.py
from transformers import AutoProcessor, BarkModel
import gradio as gr

model_name="suno/bark-small"

processor = AutoProcessor.from_pretrained(model_name)
model = BarkModel.from_pretrained(model_name)

# Selección de voz - Valores: https://suno-ai.notion.site/8b8e8749ed514b0cbf3f699013548683
voice_preset = "v2/es_speaker_0"

def tts(frase):
    # Obtenemos el procesador
    inputs = processor(frase, voice_preset=voice_preset)

    # Realiza la inferencia a partir de procesador y el modelo
    audio_array = model.generate(**inputs, pad_token_id=100)
    audio_array = audio_array.cpu().numpy().squeeze()

    sample_rate = model.generation_config.sample_rate

    return sample_rate,audio_array

demo = gr.Interface(
    tts,
    inputs=gr.Text(label="Teclea el texto a pronunciar"),
    outputs=gr.Audio(label="audio generado"),
    title="De texto a voz",
)

demo.launch()

Caso 3b: Uniendo Whisper con Bark

En nuestro caso, necesitamos crear dos pipelines, y en la salida hemos indicado dos componentes, y por lo tanto, la función transcribe devuelve una tupla de valor (el texto y el audio generado):

gradio-whisper-tts.py
from transformers import pipeline
import numpy as np
import gradio as gr

transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-base")
tts = pipeline("text-to-speech", model="suno/bark-small")

def transcribe(audio):
    sr, y = audio
    y = y.astype(np.float32)
    y /= np.max(np.abs(y))

    text_generated = transcriber({"sampling_rate": sr, "raw": y})["text"]
    audio_generated = tts(text_generated)

    audio_returned = audio_generated["sampling_rate"],audio_generated["audio"][0]

    return [text_generated, audio_returned]


demo = gr.Interface(
    transcribe,
    inputs=gr.Audio(sources=["microphone"]),
    outputs=[
        gr.Text(label="texto generado"),
        gr.Audio(label="audio generado")
    ],
    title="De audio a Whisper y TTS",
    description="Transcribe el audio y luego sintetiza el texto en audio"
)

demo.launch()

Así pues, ahora tras la entrada del audio, se genera un texto y un nuevo audio:

Gradio con Whisper y TTS
Gradio con Whisper y TTS

Referencias

Actividades

  1. (RAPIA.3 / CEPIA.3b, CEPIA.3c / 3p) Realiza los tres casos de uso, tanto en un entorno local mediante un entorno virtual, como en tres espacios diferentes de Hugging Face.

  2. (RAPIA.3 / CEPIA.3b, CEPIA.3c / 1p) Investiga los modelos disponibles en Hugging Face, y modifica el tercer caso de uso y emplea un modelo diferente tanto para el ASR como para el TTS.