# Предварительно обученные модели text-to-speech

По сравнению с задачами ASR (автоматическое распознавание речи) и классификации звука, здесь значительно меньше предварительно обученных 
контрольных точек. На 🤗 Hub вы найдете около 300 подходящих контрольных точек. Среди 
этих предварительно обученных моделей мы остановимся на двух архитектурах, которые легко доступны для вас в библиотеке 
🤗 Transformers - SpeechT5 и Massive Multilingual Speech (MMS).
В этом разделе мы рассмотрим, как использовать эти предварительно обученные модели в библиотеке Transformers для TTS.

## SpeechT5 

[SpeechT5](https://arxiv.org/abs/2110.07205) - это модель, опубликованная Джуньи Ао и другими специалистами компании Microsoft, которая способна
решать целый ряд речевых задач. Несмотря на то, что в данном разделе мы сосредоточились на аспекте преобразования текста в речь,
эта модель может быть адаптирована как для задач преобразования речи в текст (автоматическое распознавание речи или идентификация диктора),
так и для задач преобразования речи в речь (например, улучшение речи или преобразование между различными голосами). Это обусловлено тем, как эта модель
была спроектирована и предварительно обучена.

В основе SpeechT5 лежит обычная модель трансформера энкодер-декодер. Как и любой другой трансформер, модель энкодер-декодер
осуществляет преобразование последовательности в последовательность с использованием скрытых представлений. Эта основа трансформера
одинакова для всех задач, поддерживаемых SpeechT5.

Этот трансформер дополнен шестью модально-специфическими (речь/текст) _пред-сетями_ и _пост-сетями_. Входная речь или текст
(в зависимости от задачи) предварительно обрабатывается через соответствующую предварительную сеть для получения скрытых представлений, которые может использовать трансформер.
Выходные данные трансформера передаются в пост-сеть, которая использует их для генерации вывода в целевой модальности.

Вот как выглядит архитектура (изображение из оригинальной статьи):

    

SpeechT5 сначала проходит предварительное обучение на больших объемах немаркированных речевых и текстовых данных, чтобы получить единое представление
различных модальностей. На этапе предварительного обучения все предварительные и последующие сети используются одновременно.

После предварительного обучения вся структура энкодера-декодера настраивается для каждой конкретной задачи. На этом этапе используются только те
пред-сети и пост-сети, которые имеют отношение к конкретной задаче. Например, чтобы использовать SpeechT5 для преобразования текста в речь, необходимо
использовать предварительную сеть энкодера текста для текстовых входов и предварительную и пост-сети декодера речи для речевых выходов.

Такой подход позволяет получить несколько моделей, дообученных для различных речевых задач, все они выигрывают от первоначального
предварительного обучения на немаркированных данных.   

Несмотря на то что в начале работы дообученные модели используют один и тот же набор весов из общей предварительно обученной модели, конечные версии
в итоге оказываются совершенно разными. Например, вы не можете взять дообученную ASR-модель и поменять местами пред-сети и пост-сети,
чтобы получить рабочую TTS-модель. SpeechT5 гибкая, но не настолько ;)

Посмотрим, какие пред- и пост-сети использует SpeechT5 для решения задачи TTS:

* Предварительная сеть энкодера текста: Слой эмбедингов текста, который сопоставляет текстовые токены со скрытыми представлениями, ожидаемыми энкодером. Это аналогично тому, что происходит в NLP-модели, такой как BERT.
* Предварительная сеть декодера речи: На вход подается лог мел спектрограммы, и с помощью последовательности линейных слоев спектрограмма сжимается в скрытые представления. 
* Пост-сеть декодера речи: Здесь прогнозируется остаток, который добавляется к выходной спектрограмме и используется для уточнения результатов.

В совокупности именно так выглядит архитектура SpeechT5 для преобразования текста в речь:

    

Как видите, на выходе получается лог-мел спектрограмма, а не конечная форма волны. Если вы помните, мы вкратце касались
этой темы в [Разделе 3](../chapter3/introduction#spectrogram-output). Обычно модели, генерирующие звук, выдают
лог мел спектограмму, которой необходимо преобразовать в форму волны с помощью дополнительной нейронной сети, называемой вокодером.

Давайте посмотрим, как это можно сделать.

Сначала загрузим из 🤗 Hub настроенную TTS-модель SpeechT5, а также объект процессора, используемый для токенизации
и извлечения признаков:

```python
from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech

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

Далее необходимо выполнить токенизацию входного текста.

```python
inputs = processor(text="Don't count the days, make the days count.", return_tensors="pt")
```

Модель SpeechT5 TTS не ограничивается созданием речи для одного диктора. Вместо этого она использует так называемые эмбединги диктора,
которые фиксируют голосовые характеристики конкретного диктора.

Эмбеддинги диктора - это метод компактного представления личности диктора в виде вектора
фиксированного размера, независимо от длины высказывания. Эти эмбеддинги фиксируют важную информацию о голосе,
акценте, интонации и других уникальных характеристиках, отличающих одного диктора от другого. Такие эмбеддинги могут быть
использованы для верификации диктора, диаризации, идентификации диктора и т.д.
 
Наиболее распространенными методами генерации эмбеддингов диктора являются:

* I-векторы (I-Vectors): I-векторы (векторы идентичности) основаны на смешанной модели Гаусса (Gaussian mixture model, GMM). Они представляют говорящих в виде низкоразмерных векторов фиксированной длины, полученных на основе статистики GMM, специфичной для конкретного говорящего, и получаются неконтролируемым (unsupervised) способом. 
* X-векторы (X-Vectors): X-векторы создаются с помощью глубоких нейронных сетей (DNN) и захватывают информацию о дикторе на уровне фрейма с учетом временного контекста. 

[X-Vectors](https://www.danielpovey.com/files/2018_icassp_xvectors.pdf) это современный метод, который показывает более высокую эффективность
на оценочных наборах данных по сравнению с I-векторами.  Для получения X-векторов используется глубокая нейронная сеть: она обучается различать
дикторов и сопоставляет высказывания переменной длины с эмбеддингами фиксированной размерности. Также можно загрузить X-вектор заранее вычисленных эмбеддингов диктора, в котором будут заключены речевые характеристики конкретного диктора.

Загрузим такие эмбединги диктора из набора датсета в Hub. Эмбединги были получены из [датасета CMU ARCTIC](http://www.festvox.org/cmu_arctic/) с помощью
[этого скрипта](https://huggingface.co/mechanicalsea/speecht5-vc/blob/main/manifest/utils/prep_cmu_arctic_spkemb.py), но любой Х-вектор эмбединг должен работать.

```python
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)
```

Эмбеддинг диктора представляет собой тензор формы (1, 512). Данный эмбеддинг диктора описывает женский голос.

На данном этапе у нас уже достаточно входных данных, чтобы сгенерировать на выходе лог-мел спектрограмму, это можно сделать следующим образом:

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

В результате получается тензор формы (140, 80), содержащий лог-мел спектрограмму. Первое измерение - длина последовательности, и
она может изменяться между запусками, так как предварительная сеть декодер речи всегда применяет исключение (dropout) к входной последовательности. Это вносит некоторую
случайную вариативность в генерируемую речь.

Однако если мы хотим генерировать форму волны речи, нам необходимо указать вокодер, который будет использоваться для преобразования спектрограммы в форму волны.
Теоретически можно использовать любой вокодер, работающий с 80-биновыми мел-спектрограммами. Удобно, что 🤗 Transformers предлагает вокодер,
основанный на HiFi-GAN. Его весовые коэффициенты были любезно предоставлены авторами SpeechT5.

[HiFi-GAN](https://arxiv.org/pdf/2010.05646v2.pdf) представляет собой современную генеративную состязательную сеть (generative adversarial network, GAN), разработанную
для высокоточного синтеза речи. Она способна генерировать высококачественные и реалистичные формы волны звука на основе спектрограмм.

В общем случае HiFi-GAN состоит из одного генератора и двух дискриминаторов. Генератор представляет собой полностью сверточную
нейронную сеть, которая принимает на вход mel-спектрограмму и учится генерировать исходные аудиосигналы. Роль дискриминаторов
заключается в том, чтобы различать реальный и сгенерированный звук. Оба дискриминатора фокусируются на различных аспектах звука.

HiFi-GAN обучается на большом наборе данных высококачественных аудиозаписей. В нем используется так называемое состязательное обучение,
при котором сети генератора и дискриминатора соревнуются друг с другом. Вначале генератор выдает низкокачественный звук и дискриминатор легко
отличает его от реального звука. В ходе обучения генератор улучшает свой выход, пытаясь обмануть дискриминатор. Дискриминатор, в свою очередь,
становится более точным в различении реального и сгенерированного звука. Такая состязательная обратная связь помогает обеим сетям совершенствоваться
с течением времени. В конечном итоге HiFi-GAN учится генерировать звук высокой достоверности, близкий по характеристикам к обучающим данным.

Загрузить вокодер так же просто, как и любую другую модель 🤗 Transformers.

```python
from transformers import SpeechT5HifiGan

vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
```

Теперь достаточно передать его в качестве аргумента при генерации речи, и выходные данные будут автоматически преобразованы в форму волны речи.

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

Давайте послушаем результат. Частота дискретизации, используемая SpeechT5, всегда равна 16 кГц.

```python
from IPython.display import Audio

Audio(speech, rate=16000)
```

Отлично!

Не стесняйтесь пользоваться демонстрационной версией SpeechT5, изучайте другие голоса, экспериментируйте с вводом. Обратите внимание, что эта
предварительно обученная контрольная точка поддерживает только английский язык:

## Bark

Bark - это модель преобразования текста в речь на основе трансформера, предложенная компанией Suno AI в [suno-ai/bark](https://github.com/suno-ai/bark).

В отличие от SpeechT5, Bark генерирует непосредственно "сырые" формы волны речи, что избавляет от необходимости использования отдельного вокодера при инференсе - он уже интегрирован. Такая эффективность достигается за счет использования [`Encodec`](https://huggingface.co/docs/transformers/main/en/model_doc/encodec), который служит одновременно и кодеком, и инструментом сжатия.

С помощью `Encodec` можно сжимать звук в облегченный формат для уменьшения занимаемой памяти и впоследствии распаковывать его для восстановления исходного звучания. Процесс сжатия осуществляется с помощью 8 кодовых книг (codebook), каждая из которых состоит из целочисленных векторов. Эти кодовые книги можно рассматривать как представления или эмбеддинги звука в целочисленной форме. Важно отметить, что каждая последующая кодовая книга улучшает качество восстановления звука из предыдущих кодовых книг. Поскольку кодовые книги являются целочисленными векторами, они могут быть выучены с помощью трансформерных моделей, которые очень эффективно справляются с этой задачей. Именно для этого и был специально обучен Bark. 

Если говорить более конкретно, то Bark состоит из 4 основных моделей:

- `BarkSemanticModel` (также называемая 'текстовой' моделью): каузальная авторегрессионная трансформерная модель, принимающая на вход токены из текста и предсказывающая семантические токены, отражающие смысл текста.
- `BarkCoarseModel` (также называемая моделью 'грубой акустики'): каузальный авторегрессионный трансформер, принимающий на вход результаты работы модели `BarkSemanticModel`. Его цель - предсказать первые две кодовые книги, необходимые для работы [EnCodec](https://github.com/facebookresearch/encodec).
- `BarkFineModel` (модель 'тонкой акустики'), на этот раз некаузальный автоэнкодерный трансформер, который итеративно предсказывает последние кодовые книги на основе суммы эбеддингов предыдущих кодовых книг.
- спрогнозировав все каналы кодовой книги из `EncodecModel`, Bark использует ее для декодирования выходного звукового массива.

Следует отметить, что каждый из первых трех модулей может поддерживать условные эмбеддинги диктора, обусловливающие выходной звук в соответствии с определенным заранее заданным голосом.

Bark - это высокоуправляемая модель преобразования текста в речь, то есть ее можно использовать с различными настройками, в чем мы сейчас убедимся.

Прежде всего, загрузите модель и ее процессор.

Роль процессора здесь двухсторонняя:
1. Он используется для токенизации входного текста, т.е. для разбиения его на небольшие фрагменты, понятные модели.
2. В нем хранятся эбеддинги дикторов, т.е. голосовые предустановки, которые могут обуславливать генерацию.

```python
from transformers import BarkModel, BarkProcessor

model = BarkModel.from_pretrained("suno/bark-small")
processor = BarkProcessor.from_pretrained("suno/bark-small")
```

Bark очень универсален и может генерировать звук, обусловленный [библиотекой эбеддингов дикторов](https://suno-ai.notion.site/8b8e8749ed514b0cbf3f699013548683?v=bc67cff786b04b50b3ceb756fd05f68c) которая может быть загружена через процессор.

```python
# add a speaker embedding
inputs = processor("This is a test!", voice_preset="v2/en_speaker_3")

speech_output = model.generate(**inputs).cpu().numpy()
```

 
   
Your browser does not support the audio element. 
 

Он также может генерировать готовую многоязычную речь, например, на французском и китайском языках. Список поддерживаемых языков можно найти [здесь](https://huggingface.co/suno/bark). В отличие от MMS, о котором речь пойдет ниже, здесь не нужно указывать используемый язык, а достаточно просто адаптировать входной текст к соответствующему языку.

```python
# try it in French, let's also add a French speaker embedding
inputs = processor("C'est un test!", voice_preset="v2/fr_speaker_1")

speech_output = model.generate(**inputs).cpu().numpy()
```

 
   
Your browser does not support the audio element. 
 

Модель также может генерировать **невербальные коммуникации**, такие как смех, вздох и плач. Для этого достаточно модифицировать входной текст соответствующими подсказками, такими как `[clears throat]`, `[laughter]` или `...`.

```python
inputs = processor(
    "[clears throat] This is a test ... and I just took a long pause.",
    voice_preset="v2/fr_speaker_1",
)

speech_output = model.generate(**inputs).cpu().numpy()
```

 
   
Your browser does not support the audio element. 
 

Bark может даже генерировать музыку. Вы можете помочь, добавив ♪ музыкальные ноты ♪ вокруг ваших слов.

```python
inputs = processor(
    "♪ In the mighty jungle, I'm trying to generate barks.",
)

speech_output = model.generate(**inputs).cpu().numpy()
```

 
   
Your browser does not support the audio element. 
 

В отличие от SpeechT5, Bark напрямую генерирует форму волны сырой речи. Это означает, что для инференса не нужно добавлять вокодер, он уже "встроен".

Кроме того, Bark поддерживает пакетную обработку, то есть можно одновременно обрабатывать несколько текстовых записей за счет более интенсивных вычислений.
На некоторых аппаратных средствах, таких как GPU, пакетная обработка позволяет ускорить общую генерацию, что означает, что генерация всех образцов одновременно может быть быстрее, чем генерация их по одному.

Попробуем сгенерировать несколько примеров:

```python
input_list = [
    "[clears throat] Hello uh ..., my dog is cute [laughter]",
    "Let's try generating speech, with Bark, a text-to-speech model",
    "♪ In the jungle, the mighty jungle, the lion barks tonight ♪",
]

# также добавляем эмбеддинги диктора
inputs = processor(input_list, voice_preset="v2/en_speaker_3")

speech_output = model.generate(**inputs).cpu().numpy()
```

Давайте прослушаем выводы по очереди.

Первый:
```python
from IPython.display import Audio

sampling_rate = model.generation_config.sample_rate
Audio(speech_output[0], rate=sampling_rate)
```

 
   
Your browser does not support the audio element. 
 

Второй:
```python
Audio(speech_output[1], rate=sampling_rate)
```

 
   
Your browser does not support the audio element. 
 

Третий:
```python
Audio(speech_output[2], rate=sampling_rate)
```

 
   
Your browser does not support the audio element. 
 

Bark, как и другие 🤗 модели трансформеров, могут быть оптимизированы всего в нескольких строках кода в отношении скорости и потребления памяти. Чтобы узнать, как это сделать, нажмите на [этот демонстрационный блокнот Colab](https://colab.research.google.com/github/ylacombe/notebooks/blob/main/Benchmark_Bark_HuggingFace.ipynb).

## Massive Multilingual Speech (MMS)

Что делать, если вам нужна предварительно обученная модель на языке, отличном от английского? Массивная многоязыковая речь (Massive Multilingual Speech, MMS) - это 
еще одна модель, которая охватывает целый ряд речевых задач, но при этом поддерживает большое количество языков. Например, она может
синтезировать речь на более чем 1100 языках.

MMS для преобразования текста в речь базируется на технологии описанной в [статье VITS написанной Kim и другими специалистами в 2021 году]((https://arxiv.org/pdf/2106.06103.pdf)),
которая является одним из современных подходов в TTS.

VITS - это сеть генерации речи, преобразующая текст в сырую форму волны речи. Он работает как условный вариационный
автокодер, вычисляя звуковые признаки из входного текста. Сначала генерируются акустические признаки, представленные 
в виде спектрограмм. Затем форма сигнала декодируется с помощью транспонированных сверточных слоев, адаптированных из HiFi-GAN.
В процессе инференса кодировки текста подвергаются апсемплингу и преобразуются в волновые формы с помощью потокового модуля и декодера HiFi-GAN.
Это означает, что не нужно добавлять вокодер для инференса, он уже "встроен". 

	
Модель MMS была добавлена в 🤗 Transformers совсем недавно, поэтому ее API может немного измениться. На момент выхода этого раздела
MMS для TTS планируется интегрировать в Transformers `main` через пару дней.
После слияния вам придется установить библиотеку из исходного кода. Тем временем, если вы хотите попробовать следующий пример инференса,
вы можете установить модель из ветки PR:

```bash
pip install git+https://github.com/hollance/transformers.git@6900e8ba6532162a8613d2270ec2286c3f58f57b
```

Давайте попробуем использовать MMS и посмотрим, как можно синтезировать речь на языке, отличном от английского, например, на немецком.
Сначала загрузим контрольную точку модели и токенизатор для нужного языка: 

```python
from transformers import VitsModel, VitsTokenizer

model = VitsModel.from_pretrained("facebook/mms-tts-deu")
tokenizer = VitsTokenizer.from_pretrained("facebook/mms-tts-deu")
```

Вы можете заметить, что для загрузки модели MMS необходимо использовать `VitsModel` и `VitsTokenizer`. Это связано с тем, что MMS для преобразования текста в речь
основана на модели VITS, о которой говорилось выше.

Возьмем для примера текст на немецком языке, например, эти две первые строчки из детской песенки:

```python
text_example = (
    "Ich bin Schnappi das kleine Krokodil, komm aus Ägypten das liegt direkt am Nil."
)
```

Для генерации выходной волновой формы необходимо предварительно обработать текст с помощью токенизатора и передать его в модель:

```python
import torch

inputs = tokenizer(text_example, return_tensors="pt")
input_ids = inputs["input_ids"]

with torch.no_grad():
    outputs = model(input_ids)

speech = outputs.audio[0]
```

Давайте послушаем:

```python
from IPython.display import Audio

Audio(speech, rate=16000)
```

Замечательно! Если вы хотите попробовать MMS на другом языке, найдите другие подходящие контрольные точки `vits` [в 🤗 Hub](https://huggingface.co/models?filter=vits).

Теперь давайте посмотрим, как можно самостоятельно дообучить модель TTS!

