Sintesi del parlato, riconoscimento e altro con SpeechT5

Trasformazione del parlato, riconoscimento e altro con SpeechT5.

Siamo felici di annunciare che SpeechT5 è ora disponibile in 🤗 Transformers, una libreria open-source che offre implementazioni facili da usare di modelli di apprendimento automatico all’avanguardia.

SpeechT5 è stato originariamente descritto nell’articolo SpeechT5: Pre-Training Unified-Modal Encoder-Decoder per l’elaborazione del linguaggio parlato di Microsoft Research Asia. I checkpoint ufficiali pubblicati dagli autori dell’articolo sono disponibili su Hugging Face Hub.

Se vuoi iniziare subito, ecco alcune demo su Spaces:

  • Sintesi vocale (TTS)
  • Conversione vocale
  • Riconoscimento automatico della voce

Introduzione

SpeechT5 non è uno, non due, ma tre tipi di modelli di linguaggio parlato in un’unica architettura.

Può fare:

  • speech-to-text per il riconoscimento automatico della voce o l’identificazione del parlante,
  • text-to-speech per sintetizzare l’audio, e
  • speech-to-speech per la conversione tra voci diverse o per eseguire il miglioramento della voce.

L’idea principale dietro SpeechT5 è quella di pre-allenare un singolo modello su una miscela di dati di text-to-speech, speech-to-text, text-to-text e speech-to-speech. In questo modo, il modello apprende contemporaneamente dal testo e dalla voce. Il risultato di questo approccio di pre-allenamento è un modello che ha uno spazio unificato di rappresentazioni nascoste condivise sia dal testo che dalla voce.

Al centro di SpeechT5 c’è un regolare modello di codificatore-decodificatore Transformer. Proprio come qualsiasi altro Transformer, la rete encoder-decoder modella una trasformazione sequenza-sequenza utilizzando rappresentazioni nascoste. Questa struttura di base del Transformer è la stessa per tutti i compiti di SpeechT5.

Per rendere possibile al Transformer di gestire sia dati di testo che di voce, sono state aggiunte le cosiddette pre-net e post-net. Il compito della pre-net è convertire il testo o la voce in input nelle rappresentazioni nascoste utilizzate dal Transformer. La post-net prende le uscite dal Transformer e le trasforma nuovamente in testo o voce.

Di seguito è riportata un’immagine che illustra l’architettura di SpeechT5 (tratta dall’articolo originale).

Durante il pre-allenamento, tutte le pre-net e post-net vengono utilizzate contemporaneamente. Dopo il pre-allenamento, l’intero backbone del codificatore-decodificatore viene messo a punto su un singolo compito. Un modello così messo a punto utilizza solo le pre-net e post-net specifiche per il compito assegnato. Ad esempio, per utilizzare SpeechT5 per il text-to-speech, dovresti sostituire la pre-net del codificatore di testo per gli input di testo e le pre-net e post-net del decodificatore di voce per le uscite vocali.

Nota: Anche se i modelli messi a punto iniziano utilizzando lo stesso insieme di pesi dal modello pre-allenato condiviso, le versioni finali sono tutte abbastanza diverse alla fine. Ad esempio, non puoi prendere un modello ASR messo a punto e sostituire le pre-net e post-net per ottenere un modello TTS funzionante. SpeechT5 è flessibile, ma non così flessibile.

Text-to-speech

SpeechT5 è il primo modello di text-to-speech che abbiamo aggiunto a 🤗 Transformers e abbiamo intenzione di aggiungere altri modelli TTS in futuro.

Per il compito di TTS, il modello utilizza le seguenti pre-net e post-net:

  • Pre-net del codificatore di testo. Uno strato di incorporamento del testo che mappa i token di testo alle rappresentazioni nascoste che il codificatore si aspetta. Simile a quanto avviene in un modello di NLP come BERT.

  • Pre-net del decodificatore di voce. Questo prende uno spettrogramma log mel come input e utilizza una sequenza di strati lineari per comprimere lo spettrogramma in rappresentazioni nascoste. Questo design è tratto dal modello TTS Tacotron 2.

  • Post-net del decodificatore di voce. Questo prevede un residuo da aggiungere allo spettrogramma di output ed è utilizzato per perfezionare i risultati, anche da Tacotron 2.

L’architettura del modello messo a punto sembra la seguente.

Ecco un esempio completo di come utilizzare il modello di text-to-speech SpeechT5 per sintetizzare la voce. Puoi anche seguire l’esempio in questo notebook interattivo di Colab.

SpeechT5 non è ancora disponibile nell’ultima versione di Transformers, quindi dovrai installarlo da GitHub. Installa anche la dipendenza aggiuntiva sentencepiece e quindi riavvia il tuo runtime.

pip install git+https://github.com/huggingface/transformers.git
pip install sentencepiece

Prima di tutto, carichiamo il modello pre-addestrato dal Hub, insieme all’oggetto processore utilizzato per la tokenizzazione e l’estrazione delle caratteristiche. La classe che utilizzeremo è SpeechT5ForTextToSpeech.

from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")

Successivamente, tokenizziamo il testo di input.

inputs = processor(text="Non contare i giorni, fai in modo che i giorni contino.", return_tensors="pt")

Il modello di sintesi vocale SpeechT5 non è limitato alla creazione di discorsi per un singolo speaker. Utilizza invece cosiddetti speaker embeddings che catturano le caratteristiche vocali di un determinato speaker. Caricheremo tali speaker embeddings da un dataset sul Hub.

from datasets import load_dataset
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")

import torch
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)

Lo speaker embedding è un tensore di forma (1, 512). Questo particolare speaker embedding descrive una voce femminile. Gli embeddings sono stati ottenuti dal dataset CMU ARCTIC utilizzando questo script, ma qualsiasi embedding X-Vector dovrebbe funzionare.

Ora possiamo dire al modello di generare il discorso, dati i token di input e lo speaker embedding.

spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings)

Questo restituisce un tensore di forma (140, 80) contenente uno spettrogramma log mel. La prima dimensione è la lunghezza della sequenza e può variare tra le esecuzioni poiché il pre-net del decodificatore del discorso applica sempre il dropout alla sequenza di input. Questo aggiunge un po’ di variabilità casuale al discorso generato.

Per convertire lo spettrogramma log mel previsto in una forma d’onda audio effettiva, abbiamo bisogno di un vocoder. In teoria, è possibile utilizzare qualsiasi vocoder che funzioni su spettrogrammi mel a 80 bin, ma per comodità, ne abbiamo fornito uno in Transformers basato su HiFi-GAN. I pesi per questo vocoder, così come i pesi per il modello TTS pre-addestrato, sono stati gentilmente forniti dagli autori originali di SpeechT5.

Caricare il vocoder è semplice come con qualsiasi altro modello di 🤗 Transformers.

from transformers import SpeechT5HifiGan
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

Per generare l’audio dallo spettrogramma, eseguire quanto segue:

with torch.no_grad():
    speech = vocoder(spectrogram)

Forniamo anche una scorciatoia in modo da non dover fare il passaggio intermedio della creazione dello spettrogramma. Quando si passa l’oggetto vocoder a generate_speech, restituisce direttamente la forma d’onda del discorso.

speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)

E infine, salviamo la forma d’onda del discorso in un file. Il tasso di campionamento utilizzato da SpeechT5 è sempre di 16 kHz.

import soundfile as sf
sf.write("tts_example.wav", speech.numpy(), samplerate=16000)

L’output suona così (scarica audio):

Il tuo browser non supporta l’elemento audio.

Questo è tutto per il modello TTS! La chiave per ottenere un buon suono è utilizzare gli speaker embeddings giusti.

Puoi giocare con una demo interattiva su Spaces.

💡 Se sei interessato a imparare come addestrare SpeechT5 TTS sul tuo dataset o lingua, dai un’occhiata a questo notebook di Colab con una descrizione dettagliata del processo.

Speech-to-speech per la conversione vocale

Concettualmente, fare modellazione del discorso al discorso con SpeechT5 è lo stesso del testo al discorso. Basta sostituire il pre-net dell’encoder del testo con il pre-net dell’encoder del discorso. Il resto del modello rimane lo stesso.

Il pre-net dell’encoder del discorso è lo stesso modulo di codifica delle caratteristiche di wav2vec 2.0. È composto da strati di convoluzione che riducono il campione audio di input in una sequenza di rappresentazioni frame audio.

Come esempio di un compito di conversione vocale-vocale, gli autori di SpeechT5 forniscono un checkpoint preaddestrato per fare la conversione della voce. Per utilizzarlo, inizia caricando il modello dal Hub. Nota che la classe del modello ora è SpeechT5ForSpeechToSpeech.

from transformers import SpeechT5Processor, SpeechT5ForSpeechToSpeech

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_vc")
model = SpeechT5ForSpeechToSpeech.from_pretrained("microsoft/speecht5_vc")

Avremo bisogno di un audio di discorso da utilizzare come input. Per scopi di esempio, caricheremo l’audio da un piccolo dataset di discorsi sul Hub. Puoi anche caricare i tuoi waveform di discorsi, purché siano mono e utilizzino una frequenza di campionamento di 16 kHz. I campioni del dataset che stiamo usando sono già in questo formato.

from datasets import load_dataset
dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset = dataset.sort("id")
example = dataset[40]

Successivamente, preprocessa l’audio per metterlo nel formato che il modello si aspetta.

frequenza_campionamento = dataset.features["audio"].sampling_rate
inputs = processor(audio=example["audio"]["array"], sampling_rate=frequenza_campionamento, return_tensors="pt")

Come per il modello TTS, avremo bisogno di embedding del parlante. Questi descrivono come suona la voce di destinazione.

import torch
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)

Dobbiamo anche caricare il vocoder per trasformare gli spettrogrammi generati in una forma d’onda audio. Utilizziamo lo stesso vocoder del modello TTS.

from transformers import SpeechT5HifiGan
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

Ora possiamo eseguire la conversione vocale chiamando il metodo generate_speech del modello.

speech = model.generate_speech(inputs["input_values"], speaker_embeddings, vocoder=vocoder)

import soundfile as sf
sf.write("speech_converted.wav", speech.numpy(), samplerate=16000)

Cambiare voce è semplice come caricare un nuovo embedding del parlante. Puoi persino creare un embedding dalla tua voce!

L’input originale (scarica):

Il tuo browser non supporta l’elemento audio.

La voce convertita (scarica):

Il tuo browser non supporta l’elemento audio.

Nota che l’audio convertito in questo esempio si interrompe prima della fine della frase. Questo potrebbe essere dovuto alla pausa tra le due frasi, che fa sì che SpeechT5 (erroneamente) preveda che sia stata raggiunta la fine della sequenza. Provalo con un altro esempio, scoprirai che spesso la conversione è corretta ma a volte si interrompe prematuramente.

Puoi giocare con una demo interattiva qui. 🔥

Speech-to-text per il riconoscimento automatico della voce

Il modello ASR utilizza i seguenti pre-net e post-net:

  • Pre-net dell’encoder vocale. Questo è lo stesso pre-net utilizzato dal modello vocale-vocale e consiste nei livelli di encoder delle caratteristiche CNN di wav2vec 2.0.

  • Pre-net del decoder di testo. Simile al pre-net dell’encoder utilizzato dal modello TTS, questo mappa i token di testo nelle rappresentazioni nascoste utilizzando uno strato di embedding. (Durante il pre-addestramento, questi embedding sono condivisi tra i pre-net dell’encoder di testo e decoder.)

  • Post-net del decoder di testo. Questo è il più semplice di tutti e consiste in un singolo strato lineare che proietta le rappresentazioni nascoste in probabilità sul vocabolario.

L’architettura del modello preaddestrato sembra la seguente.

Se hai già provato alcuni dei modelli di riconoscimento vocale dei 🤗 Transformers prima, troverai SpeechT5 altrettanto facile da usare. Il modo più rapido per iniziare è utilizzare una pipeline.

from transformers import pipeline
generator = pipeline(task="automatic-speech-recognition", model="microsoft/speecht5_asr")

Come audio del discorso, utilizzeremo lo stesso input della sezione precedente, ma qualsiasi file audio funzionerà, poiché il sistema converte automaticamente l’audio nel formato corretto.

from datasets import load_dataset
dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset = dataset.sort("id")
example = dataset[40]

Ora possiamo chiedere alla pipeline di elaborare il discorso e generare una trascrizione di testo.

transcription = generator(example["audio"]["array"])

Stampando la trascrizione otteniamo:

un uomo disse all'universo signore io esisto

Sembra esatto! Il tokenizer utilizzato da SpeechT5 è molto semplice e lavora a livello di carattere. Quindi, il modello ASR non restituirà alcuna punteggiatura o maiuscole.

Ovviamente è anche possibile utilizzare direttamente la classe del modello. Prima, carica il modello pre-intonato e l’oggetto processore. La classe è ora SpeechT5ForSpeechToText.

from transformers import SpeechT5Processor, SpeechT5ForSpeechToText

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_asr")
model = SpeechT5ForSpeechToText.from_pretrained("microsoft/speecht5_asr")

Preelabora l’input del discorso:

sampling_rate = dataset.features["audio"].sampling_rate
inputs = processor(audio=example["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")

Infine, indica al modello di generare token di testo dall’input del discorso, e quindi utilizza la funzione di decodifica del processore per trasformare questi token in testo effettivo.

predicted_ids = model.generate(**inputs, max_length=100)
transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)

Gioca con una demo interattiva per il compito di conversione da testo a discorso .

Conclusione

SpeechT5 è un modello interessante perché – a differenza della maggior parte degli altri modelli – consente di eseguire più compiti con la stessa architettura. Solo le pre-reti e le post-reti cambiano. Pre-addestrando il modello su questi compiti combinati, diventa più capace di svolgere ciascuno dei compiti individuali quando viene ulteriormente pre-intonato.

Abbiamo incluso solo i checkpoint per il riconoscimento del discorso (ASR), la sintesi del discorso (TTS) e i compiti di conversione vocale, ma nell’articolo si menziona anche che il modello è stato utilizzato con successo per la traduzione del discorso, il miglioramento del discorso e l’identificazione del parlante. È molto versatile!