# Перевод Speech-to-speech

Перевод речи в речь (Speech-to-speech, STST или S2ST) - это относительно новая задача обработки устной речи. Она заключается
в переводе [NL] речи с одного языка в речь на **другом** языке:

    

STST можно рассматривать как расширение традиционной задачи машинного перевода (МТ): вместо перевода **текста** с одного языка
на другой мы переводим **речь** с одного языка на другой. STST находит применение в области многоязыковой коммуникации,
позволяя носителям разных языков общаться друг с другом посредством речи.

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

В этом разделе мы рассмотрим *каскадный* подход к STST, объединив знания, полученные в разделах 5 и 6 курса. Мы будем использовать
систему *перевода речи (ST)* для транскрибирования исходной речи в текст на целевом языке, а затем *перевода текста в речь (TTS)* 
для генерации речи на целевом языке из переведенного текста:

    

Можно было бы использовать и трехэтапный подход, когда сначала с помощью системы автоматического распознавания речи (ASR) исходная речь транскрибируется в текст на том же 
языке, затем с помощью машинного перевода транскрибированный текст переводится на целевой язык, и, наконец, с помощью преобразования текста в речь формируется речь 
на целевом языке. Однако добавление большего числа компонентов в конвейер приводит к *распространению ошибок*, когда ошибки, вносимые в одну систему, усугубляются
при прохождении через остальные системы, а также к увеличению задержки, поскольку инференс приходится проводить для большего числа моделей.

Несмотря на то, что такой каскадный подход к STST достаточно прост, он позволяет создавать очень эффективные системы STST. Трехступенчатая каскадная система ASR + MT + TTS
ранее использовалась для работы многих коммерческих продуктов STST, в том числе [Google Translate](https://ai.googleblog.com/2019/05/introducing-translatotron-end-to-end.html).

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

В оставшейся части этого раздела мы сосредоточимся на создании системы STST, которая переводит речь с любого языка X в речь на английском языке. 
Рассмотренные методы могут быть распространены на системы STST, переводящие с любого языка X на любой язык Y, но мы оставляем это на усмотрение читателя и 
указываем, где это возможно.Далее мы разделяем задачу STST на две составные части: ST и TTS. В завершение мы соединим их вместе и создадин демо с помощью Gradio 
для демонстрации нашей системы.

## Перевод речи

Мы будем использовать модель Whisper для нашей системы перевода речи, поскольку эта модель способна переводить с более чем 96 языков на английский. 
В частности, мы загрузим контрольную точку [Whisper Base](https://huggingface.co/openai/whisper-base), которая имеет 74М параметров. Это далеко не самая производительная
модель Whisper, поскольку [наибольшая контрольная точка Whisper](https://huggingface.co/openai/whisper-large-v2) более чем в 20 раз больше, но поскольку мы объединяем две
авторегрессивные системы (ST + TTS), мы хотим, чтобы каждая модель могла работать относительно быстро, чтобы мы получили приемлемую скорость инференса:

```python
import torch
from transformers import pipeline

device = "cuda:0" if torch.cuda.is_available() else "cpu"
pipe = pipeline(
    "automatic-speech-recognition", model="openai/whisper-base", device=device
)
```

Отлично! Для проверки нашей системы STST загрузим аудиопример на неанглийском языке. Загрузим первый пример из итальянской (`it`) части
датасета [VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli):

```python
from datasets import load_dataset

dataset = load_dataset("facebook/voxpopuli", "it", split="validation", streaming=True)
sample = next(iter(dataset))
```

Чтобы прослушать этот пример, мы можем либо воспроизвести его с помощью средства просмотра набора данных на Hub: [facebook/voxpopuli/viewer](https://huggingface.co/datasets/facebook/voxpopuli/viewer/it/validation?row=0)

Или воспроизведение с помощью функции ipynb audio:

```python
from IPython.display import Audio

Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"])
```

Теперь определим функцию, которая принимает этот аудиовход и возвращает переведенный текст. Вы помните, что мы должны передать ключевое слово генерации аргументу `"task"`, 
установив его в значение `"translate"`, чтобы убедиться, что Whisper выполняет перевод речи, а не ее распознавание:

```python
def translate(audio):
    outputs = pipe(audio, max_new_tokens=256, generate_kwargs={"task": "translate"})
    return outputs["text"]
```

    Whisper также можно "обманом" заставить перевести речь на любом языке X на любой язык Y. Просто задайте задачу `"transcribe"`, а `"language"` - целевым языком
    в аргументах ключевых слов генерации, например, для испанского языка можно задать:

	`generate_kwargs={"task": "transcribe", "language": "es"}`

Отлично! Давайте быстро проверим, что мы получаем разумный результат от модели:

```python
translate(sample["audio"].copy())
```
```
' psychological and social. I think that it is a very important step in the construction of a juridical space of freedom, circulation and protection of rights.'
```

Хорошо! Если мы сравним это с исходным текстом:

```python
sample["raw_text"]
```
```
'Penso che questo sia un passo in avanti importante nella costruzione di uno spazio giuridico di libertà di circolazione e di protezione dei diritti per le persone in Europa.'
```

Мы увидим, что перевод более или менее совпадает (вы можете проверить это с помощью Google Translate), за исключением нескольких
лишних слов в начале транскрипции, когда говорящий заканчивал предыдущее предложение.

На этом мы завершили первую половину нашего каскадного конвейера STST, применив на практике навыки, полученные в разделе 5, когда мы учились использовать
модель Whisper для распознавания и перевода речи. Если вы хотите освежить в памяти какие-либо из рассмотренных нами этапов, прочтите
раздел [Предварительно обученные модели для распознавания речи](../chapter5/asr_models) из раздела 5.

## Преобразование текста в речь

Вторая половина нашей каскадной системы STST связана с преобразованием английского текста в английскую речь. Для этого мы
будем использовать предварительно обученную модель [SpeechT5 TTS](https://huggingface.co/microsoft/speecht5_tts) для английского TTS.
🤗 В настоящее время Transformers не имеет TTS `pipeline`, поэтому нам придется использовать модель непосредственно самим.
Ничего страшного, вы же все эксперты по использованию модели для инференса после раздела 6!

Сначала загрузим процессор SpeechT5, модель и вокодер из предварительно обученной контрольной точки:

```python
from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan

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

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

    Здесь мы используем контрольную точку SpeechT5, обученную специально для английского TTS. Если вы хотите перевести
    на язык, отличный от английского, либо замените контрольную точку на модель SpeechT5 TTS, дообученную для выбранного
    вами языка, либо используйте контрольную точку MMS TTS, предварительно обученную для вашего целевого языка.

Как и в случае с моделью Whisper, модель SpeechT5 и вокодер мы поместим на GPU-ускоритель, если он у нас есть:

```python
model.to(device)
vocoder.to(device)
```

Отлично! Давайте загрузим эмбеддинги дикторов:

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

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

```python
def synthesise(text):
    inputs = processor(text=text, return_tensors="pt")
    speech = model.generate_speech(
        inputs["input_ids"].to(device), speaker_embeddings.to(device), vocoder=vocoder
    )
    return speech.cpu()
```

Проверим его работу с помощью фиктивного текстового ввода:

```python
speech = synthesise("Hey there! This is a test!")

Audio(speech, rate=16000)
```

Звучит неплохо! Теперь самое интересное - собрать все воедино.

## Создание демо STST

Перед тем как создать демо [Gradio](https://gradio.app) для демонстрации нашей системы STST, давайте сначала проведем быструю проверку, чтобы убедиться,
что мы можем объединить две модели, подавая аудио пример на вход и получая аудио пример на выходе. Для этого мы объединим две функции, определенные в 
предыдущих двух подразделах: введем исходное аудио и получим переведенный текст, затем синтезируем переведенный текст, чтобы получить переведенную речь.
Наконец, мы преобразуем синтезированную речь в массив `int16`, который является форматом выходного аудиофайла, ожидаемого Gradio. Для этого сначала 
необходимо нормализовать аудио массив по динамическому диапазону целевого dtype (`int16`), а затем преобразовать из стандартного dtype NumPy (`float64`)
в целевой dtype (`int16`):

```python
import numpy as np

target_dtype = np.int16
max_range = np.iinfo(target_dtype).max

def speech_to_speech_translation(audio):
    translated_text = translate(audio)
    synthesised_speech = synthesise(translated_text)
    synthesised_speech = (synthesised_speech.numpy() * max_range).astype(np.int16)
    return 16000, synthesised_speech
```

Проверим, что эта конкатенированная функция дает ожидаемый результат:

```python
sampling_rate, synthesised_speech = speech_to_speech_translation(sample["audio"])

Audio(synthesised_speech, rate=sampling_rate)
```

Отлично! Теперь мы завернем это в красивое демо Gradio, чтобы мы могли записать нашу исходную речь с помощью 
микрофонного или файлового входа и воспроизвести прогноз системы:

```python
import gradio as gr

demo = gr.Blocks()

mic_translate = gr.Interface(
    fn=speech_to_speech_translation,
    inputs=gr.Audio(source="microphone", type="filepath"),
    outputs=gr.Audio(label="Generated Speech", type="numpy"),
)

file_translate = gr.Interface(
    fn=speech_to_speech_translation,
    inputs=gr.Audio(source="upload", type="filepath"),
    outputs=gr.Audio(label="Generated Speech", type="numpy"),
)

with demo:
    gr.TabbedInterface([mic_translate, file_translate], ["Microphone", "Audio File"])

demo.launch(debug=True)
```

В результате будет запущена демо Gradio, аналогичная той, что работает на Hugging Face Space:

Вы можете [дублировать](https://huggingface.co/spaces/course-demos/speech-to-speech-translation?duplicate=true) это демо и адаптировать его для
использования другой контрольной точки Whisper, другой контрольной точки TTS, или отказаться от ограничений по выводу английской речи
и следовать советам по переводу на выбранный вами язык!

## Двигаемся вперед

Хотя каскадная система представляет собой эффективный с точки зрения вычислений и данных способ построения системы STST, она страдает от описанных выше 
проблем распространения ошибок и аддитивной задержки. В последних работах исследовался *прямой* подход к STST, который не прогнозирует промежуточный
текстовый вывод, а напрямую переводит исходную речь в целевую. Эти системы также способны сохранять в целевой речи речевые характеристики 
диктора-источника (такие как просодия, высота тона и интонация). Если вы хотите узнать больше об этих системах, ознакомьтесь с ресурсами,
перечисленными в секции [дополнительные материалы и ресурсы](supplemental_reading).

