diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index caa25875..0ee5caaa 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -57,7 +57,7 @@ - local: chapter4/introduction title: Чему вы научитесь и что создадите - local: chapter4/classification_models - title: Предварительно обученные модели классификации аудио + title: Предварительно обученные модели классификации звука - local: chapter4/fine-tuning title: Дообучение модели классификации музыки - local: chapter4/demo @@ -65,56 +65,56 @@ - local: chapter4/hands_on title: Практическое занятие -- title: Раздел 5. Автоматическое распознавание речи +- title: Раздел 5. Automatic Speech Recognition sections: - - local: chapter5/introduction - title: Чему вы научитесь и что создадите - - local: chapter5/asr_models - title: Предварительно обученные модели для распознавания речи - - local: chapter5/choosing_dataset - title: Выбор набора данных - - local: chapter5/evaluation - title: Оценка и метрики для распознавания речи - - local: chapter5/fine-tuning - title: Как дообучить ASR-систему с помощью Trainer API - - local: chapter5/demo - title: Создание демо - - local: chapter5/hands_on - title: Практическое занятие - - local: chapter5/supplemental_reading - title: Дополнительные материалы и ресурсы + - local: chapter5/introduction + title: Чему вы научитесь и что создадите + - local: chapter5/asr_models + title: Предварительно обученные модели для распознавания речи + - local: chapter5/choosing_dataset + title: Выбор набора данных + - local: chapter5/evaluation + title: Оценка и метрики для распознавания речи + - local: chapter5/fine-tuning + title: Как дообучить ASR-систему с помощью Trainer API + - local: chapter5/demo + title: Создание демо + - local: chapter5/hands_on + title: Практическое занятие + - local: chapter5/supplemental_reading + title: Дополнительные материалы и ресурсы -# - title: Раздел 6. От текста к речи -# sections: -# - local: chapter6/introduction -# title: Чему вы научитесь и что создадите -# - local: chapter6/tts_datasets -# title: Наборы данных Text-to-speech -# - local: chapter6/pre-trained_models -# title: Предварительно обученные модели text-to-speech -# - local: chapter6/fine-tuning -# title: Дообучение SpeechT5 -# - local: chapter6/evaluation -# title: Оценка моделей text-to-speech -# - local: chapter6/hands_on -# title: Практическое занятие -# - local: chapter6/supplemental_reading -# title: Дополнительные материалы и ресурсы +- title: Раздел 6. От текста к речи + sections: + - local: chapter6/introduction + title: Чему вы научитесь и что создадите + - local: chapter6/tts_datasets + title: Наборы данных Text-to-speech + - local: chapter6/pre-trained_models + title: Предварительно обученные модели text-to-speech + - local: chapter6/fine-tuning + title: Дообучение SpeechT5 + - local: chapter6/evaluation + title: Оценка моделей text-to-speech + - local: chapter6/hands_on + title: Практическое занятие + - local: chapter6/supplemental_reading + title: Дополнительные материалы и ресурсы -# - title: Раздел 7. Собираем все воедино -# sections: -# - local: chapter7/introduction -# title: Чему вы научитесь и что создадите -# - local: chapter7/speech-to-speech -# title: Перевод Speech-to-speech -# - local: chapter7/voice-assistant -# title: Создание голосового ассистента -# - local: chapter7/transcribe-meeting -# title: Транскрибирование встречи -# - local: chapter7/hands-on -# title: Практическое занятие -# - local: chapter7/supplemental_reading -# title: Дополнительные материалы и ресурсы +- title: Раздел 7. Собираем все воедино + sections: + - local: chapter7/introduction + title: Чему вы научитесь и что создадите + - local: chapter7/speech-to-speech + title: Перевод Speech-to-speech + - local: chapter7/voice-assistant + title: Создание голосового ассистента + - local: chapter7/transcribe-meeting + title: Транскрибирование встречи + - local: chapter7/hands-on + title: Практическое занятие + - local: chapter7/supplemental_reading + title: Дополнительные материалы и ресурсы - title: Раздел 8. Финишная прямая sections: diff --git a/chapters/ru/chapter6/evaluation.mdx b/chapters/ru/chapter6/evaluation.mdx new file mode 100644 index 00000000..bacb91b4 --- /dev/null +++ b/chapters/ru/chapter6/evaluation.mdx @@ -0,0 +1,24 @@ +# Оценка моделей text-to-speech + +В процессе обучения модели преобразования текста в речь оптимизируются по среднеквадратичной ошибке (mean-square error, MSE) (или средней абсолютной ошибке (mean absolute error, MAE)) между +спрогнозированными значениями спектрограмм и сгенерированными. Как MSE, так и MAE способствуют минимизации разности +между прогнозируемой и целевой спектрограммами. Однако, поскольку TTS - это проблема отображения "один ко многим", т.е. выходная спектрограмма для данного текста может быть представлена множеством +различных способов, оценка полученных моделей преобразования текста в речь (TTS) значительно сложнее. + +В отличие от многих других вычислительных задач, которые могут быть объективно измерены с помощью количественных показателей, +таких как accuracy или precision, оценка TTS в значительной степени зависит от субъективного человеческого анализа. + +Одним из наиболее часто используемых методов оценки систем TTS является качественная оценка с использованием cредней экспертной оценки (Mean Opinion Scores, MOS). +MOS - это субъективная система оценки, которая позволяет людям оценить качество синтезированной речи [NL] по шкале от 1 до 5. +Эти оценки обычно собираются с помощью тестов на прослушивание, в которых участники-люди [NL] прослушивают и оценивают синтезированные образцы речи. + +Одной из основных причин, по которой трудно разработать объективные метрики для оценки TTS, является субъективный характер восприятия +речи. Слушатели имеют различные предпочтения и чувствительность к различным аспектам речи, включая произношение, интонацию, естественность и ясность. +Учесть все эти нюансы восприятия с помощью одного числового значения - сложная задача. +В то же время субъективность человеческой оценки затрудняет сравнение и сопоставление различных систем TTS. + +Кроме того, при такой оценке могут быть упущены некоторые важные аспекты синтеза речи, такие как естественность, выразительность и эмоциональное воздействие. +Эти качества трудно поддаются объективной количественной оценке, но очень важны в приложениях, где синтезированная речь должна передавать человекоподобные качества и вызывать соответствующие эмоциональные реакции. + +В итоге, можно сказать, что оценка моделей преобразования текста в речь является сложной задачей из-за отсутствия единой действительно объективной метрики. Наиболее распространенный метод оценки, +средняя экспертная оценка (MOS), опирается на субъективный человеческий анализ. Хотя MOS дает ценные сведения о качестве синтезированной речи, она также вносит вариативность и субъективность. diff --git a/chapters/ru/chapter6/fine-tuning.mdx b/chapters/ru/chapter6/fine-tuning.mdx new file mode 100644 index 00000000..bf7d805d --- /dev/null +++ b/chapters/ru/chapter6/fine-tuning.mdx @@ -0,0 +1,590 @@ +# Дообучение SpeechT5 + +Теперь, когда вы знакомы с задачей преобразования текста в речь и внутренним устройством модели SpeechT5, которая была предварительно обучена +на англоязычных данных, давайте посмотрим, как мы можем дообучить ее для другого языка. + +## House-keeping + +Если вы хотите воспроизвести этот пример, убедитесь, что у вас есть графический процессор. В блокноте это можно проверить с помощью следующей команды: + +```bash +nvidia-smi +``` + + + +В нашем примере мы будем использовать около 40 часов обучающих данных. Если вы хотите повторить этот процесс, используя бесплатный тарифный план Google Colab, +необходимо уменьшить объем обучающих данных примерно до 10-15 часов и сократить количество шагов обучения. + + + +Вам также понадобятся некоторые дополнительные зависимости: + +```bash +pip install transformers datasets soundfile speechbrain accelerate +``` + +Наконец, не забудьте войти в свою учетную запись Hugging Face, чтобы загрузить свою модель и поделиться ею с сообществом: + +```py +from huggingface_hub import notebook_login + +notebook_login() +``` + +## Набор данных + +В данном примере мы возьмем подмножество голландского (`nl`) языка из датасета [VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli). +[VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli) - это обширный многоязычный речевой корпус, состоящий из данных, +полученных из записей мероприятий Европейского парламента 2009-2020 гг. Он содержит маркированные данные аудио-транскрипций для 15 европейских языков. +Хотя мы будем использовать подмножество голландского языка, вы можете выбрать другое подмножество. + +Это набор данных автоматического распознавания речи (ASR), поэтому, как уже говорилось, он не является наиболее подходящим +вариантом для обучения TTS-моделей. Однако для данного упражнения этого будет вполне достаточно. + +Давайте загрузим данные: + +```python +from datasets import load_dataset, Audio + +dataset = load_dataset("facebook/voxpopuli", "nl", split="train") +len(dataset) +``` + +**Output:** +```out +20968 +``` + +20968 примеров должно быть достаточно для дообучения. Для SpeechT5 требуется, чтобы частота дискретизации аудиоданных составляла 16 кГц, поэтому +убедимся, что примеры в наборе данных соответствуют этому требованию: + +```python +dataset = dataset.cast_column("audio", Audio(sampling_rate=16000)) +``` + +## Препроцессинг данных + +Начнем с определения используемой контрольной точки модели и загрузки соответствующего процессора, содержащего как токенизатор, +так и экстрактор признаков, которые понадобятся нам для подготовки данных к обучению: + +```py +from transformers import SpeechT5Processor + +checkpoint = "microsoft/speecht5_tts" +processor = SpeechT5Processor.from_pretrained(checkpoint) +``` + +### Очистка текста для токенизации SpeechT5 + +Во-первых, для подготовки текста нам понадобится часть процессора - токенизатор, поэтому возьмем его: + +```py +tokenizer = processor.tokenizer +``` + +Рассмотрим пример: + +```python +dataset[0] +``` + +**Output:** +```out +{'audio_id': '20100210-0900-PLENARY-3-nl_20100210-09:06:43_4', + 'language': 9, + 'audio': {'path': '/root/.cache/huggingface/datasets/downloads/extracted/02ec6a19d5b97c03e1379250378454dbf3fa2972943504a91c7da5045aa26a89/train_part_0/20100210-0900-PLENARY-3-nl_20100210-09:06:43_4.wav', + 'array': array([ 4.27246094e-04, 1.31225586e-03, 1.03759766e-03, ..., + -9.15527344e-05, 7.62939453e-04, -2.44140625e-04]), + 'sampling_rate': 16000}, + 'raw_text': 'Dat kan naar mijn gevoel alleen met een brede meerderheid die wij samen zoeken.', + 'normalized_text': 'dat kan naar mijn gevoel alleen met een brede meerderheid die wij samen zoeken.', + 'gender': 'female', + 'speaker_id': '1122', + 'is_gold_transcript': True, + 'accent': 'None'} +``` + +Можно заметить, что примеры из датасета содержат признаки `raw_text` и `normalized_text`. При выборе признака +в качестве входного текста важно знать, что в токенизаторе SpeechT5 нет токенов для чисел. В `normalized_text` +числа записываются в виде текста. Таким образом, он лучше подходит, и в качестве входного текста следует использовать `normalized_text`. + +Поскольку SpeechT5 обучалась на английском языке, она может не распознать некоторые символы в голландском наборе данных. Если +оставить все как есть, то эти символы будут преобразованы в токены ``. Однако в голландском языке некоторые символы, например `à`, используются +для выделения слогов. Чтобы сохранить смысл текста, можно заменить этот символ на обычное `a`. + +Чтобы выявить неподдерживаемые токены, извлечем все уникальные символы из датасета с помощью `SpeechT5Tokenizer`, который +работает с символами как с токенами. Для этого напишем функцию отображения `extract_all_chars`, которая объединяет +транскрипции из всех примеров в одну строку и преобразует ее в набор символов. [NL] +Обязательно задайте `batched=True` и `batch_size=-1` в `dataset.map()`, чтобы все транскрипции были доступны сразу для +функции отображения. + +```py +def extract_all_chars(batch): + all_text = " ".join(batch["normalized_text"]) + vocab = list(set(all_text)) + return {"vocab": [vocab], "all_text": [all_text]} + + +vocabs = dataset.map( + extract_all_chars, + batched=True, + batch_size=-1, + keep_in_memory=True, + remove_columns=dataset.column_names, +) + +dataset_vocab = set(vocabs["vocab"][0]) +tokenizer_vocab = {k for k, _ in tokenizer.get_vocab().items()} +``` + +Теперь у вас есть два набора символов: один со словарем из датасета, другой - со словарем из токенизатора. +Для выявления неподдерживаемых символов в наборе данных можно взять разность между этими двумя наборами. Полученный набор +будет содержать символы, которые есть в наборе данных, но отсутствуют в токенизаторе. + +```py +dataset_vocab - tokenizer_vocab +``` + +**Output:** +```out +{' ', 'à', 'ç', 'è', 'ë', 'í', 'ï', 'ö', 'ü'} +``` + +Для работы с неподдерживаемыми символами, выявленными на предыдущем этапе, можно определить функцию, которая сопоставляет эти символы с допустимыми токенами. +Заметим, что пробелы уже заменены на `▁` в токенизаторе и не нуждаются в отдельной обработке. + +```py +replacements = [ + ("à", "a"), + ("ç", "c"), + ("è", "e"), + ("ë", "e"), + ("í", "i"), + ("ï", "i"), + ("ö", "o"), + ("ü", "u"), +] + + +def cleanup_text(inputs): + for src, dst in replacements: + inputs["normalized_text"] = inputs["normalized_text"].replace(src, dst) + return inputs + + +dataset = dataset.map(cleanup_text) +``` + +Теперь, когда мы разобрались со специальными символами в тексте, пришло время переключить внимание на аудио данные. + +### Дикторы + +Набор данных VoxPopuli включает речь нескольких дикторов, но сколько дикторов представлено в наборе? Чтобы +определить это, мы можем подсчитать количество уникальных дикторов и количество примеров, которые каждый диктор вносит в набор данных. +Учитывая, что всего в наборе данных 20 968 примеров, эта информация позволит нам лучше понять распределение +дикторов и примеров в данных. + +```py +from collections import defaultdict + +speaker_counts = defaultdict(int) + +for speaker_id in dataset["speaker_id"]: + speaker_counts[speaker_id] += 1 +``` + +Построив гистограмму, можно получить представление о том, сколько данных имеется для каждого диктора. + +```py +import matplotlib.pyplot as plt + +plt.figure() +plt.hist(speaker_counts.values(), bins=20) +plt.ylabel("Speakers") +plt.xlabel("Examples") +plt.show() +``` + +
+ Speakers histogram +
+ +Гистограмма показывает, что примерно треть дикторов в наборе данных имеет менее 100 примеров, в то время как +около десяти дикторов имеют более 500 примеров. Чтобы повысить эффективность обучения и сбалансировать набор данных, мы можем ограничить +данные дикторами, имеющими от 100 до 400 примеров. + +```py +def select_speaker(speaker_id): + return 100 <= speaker_counts[speaker_id] <= 400 + + +dataset = dataset.filter(select_speaker, input_columns=["speaker_id"]) +``` + +Проверим, сколько осталось дикторов: + +```py +len(set(dataset["speaker_id"])) +``` + +**Output:** +```out +42 +``` + +Посмотрим, сколько осталось примеров: + +```py +len(dataset) +``` + +**Output:** +```out +9973 +``` + +В результате вы получаете чуть менее 10 000 примеров из примерно 40 уникальных дикторов, что должно быть вполне достаточно. + +Отметим, что некоторые дикторы с небольшим количеством примеров могут иметь больше аудиофайлов, если примеры длинные. Однако +определение общего объема аудиозаписей для каждого диктора требует сканирования всего датасета, что является +трудоемким процессом, включающим загрузку и декодирование каждого аудиофайла. Поэтому в данном случае мы решили пропустить этот этап. + +### Эмбеддинги диктора + +Для того чтобы модель TTS могла различать несколько дикторов, необходимо создать эмбеддинги диктора для каждого примера. +Эмбеддинги дикторов - это дополнительный вход для модели, который фиксирует характеристики голоса конкретного диктора. +Для создания эмбеддингов диктора используется предварительно обученная модель [spkrec-xvect-voxceleb](https://huggingface.co/speechbrain/spkrec-xvect-voxceleb) +от SpeechBrain. + +Создадим функцию `create_speaker_embedding()`, которая принимает входную волновую форму звука и выдает 512-элементный вектор, +содержащий соответствующие эмбеддинги диктора. + +```py +import os +import torch +from speechbrain.pretrained import EncoderClassifier + +spk_model_name = "speechbrain/spkrec-xvect-voxceleb" + +device = "cuda" if torch.cuda.is_available() else "cpu" +speaker_model = EncoderClassifier.from_hparams( + source=spk_model_name, + run_opts={"device": device}, + savedir=os.path.join("/tmp", spk_model_name), +) + + +def create_speaker_embedding(waveform): + with torch.no_grad(): + speaker_embeddings = speaker_model.encode_batch(torch.tensor(waveform)) + speaker_embeddings = torch.nn.functional.normalize(speaker_embeddings, dim=2) + speaker_embeddings = speaker_embeddings.squeeze().cpu().numpy() + return speaker_embeddings +``` + +Важно отметить, что модель `speechbrain/spkrec-xvect-voxceleb` была обучена на английской речи из датасета VoxCeleb, +в то время как учебные примеры в данном руководстве представлены на голландском языке. Хотя мы считаем, что данная модель все равно будет генерировать разумные эмбеддинги диктора +для нашего голландского датасета, это предположение может быть справедливо не во всех случаях. + +Для получения оптимальных результатов необходимо сначала обучить модель X-вектора на целевой речи. Это позволит модели +лучше улавливать уникальные речевые особенности, присущие голландскому языку. Если вы хотите обучить свою собственную X-векторную модель, +то в качестве примера можно использовать [этот скрипт](https://huggingface.co/mechanicalsea/speecht5-vc/blob/main/manifest/utils/prep_cmu_arctic_spkemb.py). + +### Обработка датасета + +Наконец, обработаем данные в тот формат, который ожидает модель. Создадим функцию `prepare_dataset`, которая принимает +один пример и использует объект `SpeechT5Processor` для токенизации входного текста и загрузки целевого аудио в лог-мел спектрограмму. +Она также должна добавлять эмбеддинги диктора в качестве дополнительного входного сигнала. + +```py +def prepare_dataset(example): + audio = example["audio"] + + example = processor( + text=example["normalized_text"], + audio_target=audio["array"], + sampling_rate=audio["sampling_rate"], + return_attention_mask=False, + ) + + # strip off the batch dimension + example["labels"] = example["labels"][0] + + # use SpeechBrain to obtain x-vector + example["speaker_embeddings"] = create_speaker_embedding(audio["array"]) + + return example +``` + +Проверить правильность обработки можно на одном из примеров: + +```py +processed_example = prepare_dataset(dataset[0]) +list(processed_example.keys()) +``` + +**Output:** +```out +['input_ids', 'labels', 'stop_labels', 'speaker_embeddings'] +``` + +Эмбеддинги диктора должны представлять собой 512-элементный вектор: + +```py +processed_example["speaker_embeddings"].shape +``` + +**Output:** +```out +(512,) +``` + +Метки должны представлять собой лог-мел спектрограмму с 80 мел бинами. + +```py +import matplotlib.pyplot as plt + +plt.figure() +plt.imshow(processed_example["labels"].T) +plt.show() +``` + +
+ Log-mel spectrogram with 80 mel bins +
+ +Примечание: Если данная спектрограмма кажется вам непонятной, то это может быть связано с тем, что вы привыкли располагать низкие частоты +внизу, а высокие - вверху графика. Однако при построении спектрограмм в виде изображения с помощью библиотеки matplotlib ось y +переворачивается, и спектрограммы выглядят перевернутыми. + +Теперь необходимо применить функцию препроцессинга ко всему набору данных. Это займет от 5 до 10 минут. + +```py +dataset = dataset.map(prepare_dataset, remove_columns=dataset.column_names) +``` + +Появится предупреждение о том, что длина некоторых примеров в датасете превышает максимальную длину входных данных, которую может обработать модель (600 лексем). +Удалите эти примеры из датасета. Здесь мы идем еще дальше и для того, чтобы увеличить размер батча, удаляем все, что превышает 200 токенов. + +```py +def is_not_too_long(input_ids): + input_length = len(input_ids) + return input_length < 200 + + +dataset = dataset.filter(is_not_too_long, input_columns=["input_ids"]) +len(dataset) +``` + +**Output:** +```out +8259 +``` + +Затем создадим базовое разделение на тренировочную и тестовую части: + +```py +dataset = dataset.train_test_split(test_size=0.1) +``` + +### Коллатор данных + +Для того чтобы объединить несколько примеров в батч, необходимо определить пользовательский коллатор данных. Этот коллатор будет дополнять более короткие последовательности токенами, +гарантируя, что все примеры будут иметь одинаковую длину. Для меток спектрограммы дополняемая части заменяются на специальное значение `-100`. +Это специальное значение указывает модели игнорировать эту часть спектрограммы при расчете потерь спектрограммы. + +```py +from dataclasses import dataclass +from typing import Any, Dict, List, Union + + +@dataclass +class TTSDataCollatorWithPadding: + processor: Any + + def __call__( + self, features: List[Dict[str, Union[List[int], torch.Tensor]]] + ) -> Dict[str, torch.Tensor]: + input_ids = [{"input_ids": feature["input_ids"]} for feature in features] + label_features = [{"input_values": feature["labels"]} for feature in features] + speaker_features = [feature["speaker_embeddings"] for feature in features] + + # collate the inputs and targets into a batch + batch = processor.pad( + input_ids=input_ids, labels=label_features, return_tensors="pt" + ) + + # replace padding with -100 to ignore loss correctly + batch["labels"] = batch["labels"].masked_fill( + batch.decoder_attention_mask.unsqueeze(-1).ne(1), -100 + ) + + # not used during fine-tuning + del batch["decoder_attention_mask"] + + # round down target lengths to multiple of reduction factor + if model.config.reduction_factor > 1: + target_lengths = torch.tensor( + [len(feature["input_values"]) for feature in label_features] + ) + target_lengths = target_lengths.new( + [ + length - length % model.config.reduction_factor + for length in target_lengths + ] + ) + max_length = max(target_lengths) + batch["labels"] = batch["labels"][:, :max_length] + + # also add in the speaker embeddings + batch["speaker_embeddings"] = torch.tensor(speaker_features) + + return batch +``` + +В SpeechT5 входная информация для декодера уменьшается в 2 раза. Другими словами, отбрасывается каждый второй +временной шаг из целевой последовательности.Затем декодер предсказывает последовательность, которая в два раза длиннее. Поскольку исходная длина +целевой последовательности [NL] может быть нечетной, коллатор данных обязательно округляет максимальную длину батча до значения [NL], кратного 2. + +```py +data_collator = TTSDataCollatorWithPadding(processor=processor) +``` + +## Обучение модели + +Загрузите предварительно обученную модель из той же контрольной точки, которая использовалась для загрузки процессора: + +```py +from transformers import SpeechT5ForTextToSpeech + +model = SpeechT5ForTextToSpeech.from_pretrained(checkpoint) +``` + +Опция `use_cache=True` несовместима с использованием градиентных контрольных точек. Отключите ее для обучения и снова включите кэш для генерации, +чтобы ускорить инференс: + +```py +from functools import partial + +# отключить кэш во время обучения, так как он несовместим с градиентными контрольными точками +model.config.use_cache = False + +# заданим язык и задачу для генерации и снова включим кэш +model.generate = partial(model.generate, use_cache=True) +``` + +Определим аргументы обучения. Здесь мы не вычисляем никаких оценочных метрик в процессе обучения, +мы поговорим об оценке позже в этой главе. Вместо этого мы будем рассматривать только потери: + +```python +from transformers import Seq2SeqTrainingArguments + +training_args = Seq2SeqTrainingArguments( + output_dir="speecht5_finetuned_voxpopuli_nl", # change to a repo name of your choice + per_device_train_batch_size=4, + gradient_accumulation_steps=8, + learning_rate=1e-5, + warmup_steps=500, + max_steps=4000, + gradient_checkpointing=True, + fp16=True, + evaluation_strategy="steps", + per_device_eval_batch_size=2, + save_steps=1000, + eval_steps=1000, + logging_steps=25, + report_to=["tensorboard"], + load_best_model_at_end=True, + greater_is_better=False, + label_names=["labels"], + push_to_hub=True, +) +``` + +Инстанцируем объект `Trainer` и передаем ему модель, набор данных и коллатор данных. + +```py +from transformers import Seq2SeqTrainer + +trainer = Seq2SeqTrainer( + args=training_args, + model=model, + train_dataset=dataset["train"], + eval_dataset=dataset["test"], + data_collator=data_collator, + tokenizer=processor, +) +``` + +И с этим мы готовы приступить к обучению! Обучение займет несколько часов. В зависимости от используемого GPU +возможно, что при начале обучения возникнет ошибка CUDA "out-of-memory". В этом случае можно уменьшить +размер `per_device_train_batch_size` постепенно в 2 раза и увеличить `gradient_accumulation_steps` в 2 раза, чтобы компенсировать это. + +```py +trainer.train() +``` + +Push the final model to the 🤗 Hub: + +```py +trainer.push_to_hub() +``` + +## Инференс + +После того как модель дообучена, ее можно использовать для инференса! Загрузите модель из 🤗 Hub (убедитесь, что в +следующем фрагменте кода используется имя вашей учетной записи): + +```py +model = SpeechT5ForTextToSpeech.from_pretrained( + "YOUR_ACCOUNT/speecht5_finetuned_voxpopuli_nl" +) +``` + +Выберем пример, здесь мы возьмем пример из тестового набора данных. Получаем эмбеддинги диктора. + +```py +example = dataset["test"][304] +speaker_embeddings = torch.tensor(example["speaker_embeddings"]).unsqueeze(0) +``` + +Определим некоторый входной текст и токенизируем его. + +```py +text = "hallo allemaal, ik praat nederlands. groetjes aan iedereen!" +``` + +Выполним препроцессинг входного текста: + +```py +inputs = processor(text=text, return_tensors="pt") +``` + +Инстанцируем вокодер и сгенерируем речь: + +```py +from transformers import SpeechT5HifiGan + +vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan") +speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder) +``` + +Готовы послушать результат? + +```py +from IPython.display import Audio + +Audio(speech.numpy(), rate=16000) +``` + +Получение удовлетворительных результатов с помощью этой модели на новом языке может оказаться непростой задачей. Качество эмбеддингов диктора +может быть существенным фактором. Поскольку SpeechT5 была предварительно обучена на английских x-векторах, она показывает наилучшие результаты +при использовании эмбеддингов английских дикторов. Если синтезированная речь звучит плохо, попробуйте использовать другие эмбеддинги диктора. + +Увеличение продолжительности обучения, вероятно, также повысит качество результатов. Несмотря на это, речь явно голландская, а не английская, и в ней +передаются особенности голоса говорящего (сравните с оригинальным аудио в примере). +Еще один момент, с которым можно поэкспериментировать, - это настройка модели. Например, попробуйте использовать `config.reduction_factor = 1`, чтобы +посмотреть, улучшит ли это результаты. + +В следующем разделе мы расскажем о том, как мы оцениваем модели преобразования текста в речь. diff --git a/chapters/ru/chapter6/hands_on.mdx b/chapters/ru/chapter6/hands_on.mdx new file mode 100644 index 00000000..59690ef5 --- /dev/null +++ b/chapters/ru/chapter6/hands_on.mdx @@ -0,0 +1,21 @@ +# Практическое занятие + +В этом разделе мы рассмотрели аудиозадачу преобразования текста в речь, рассказали о существующих наборах данных, предварительно обученных +моделях и нюансах дообучения SpeechT5 для нового языка. + +Как вы убедились, дообучение моделей для задач преобразования текста в речь может быть сложной задачей в условиях ограниченных ресурсов. В то же время +оценивать модели преобразования текста в речь также нелегко. + +По этим причинам данное практическое занятие будет направлено на отработку навыков, а не на достижение определенного значения метрики. + +Ваша задача - провести дообучение SpeechT5 на выбранном вами наборе данных. Вы можете выбрать +другой язык из того же набора данных `voxpopuli`, либо выбрать любой другой набор данных, приведенный в этом разделе. + +Помните о размере обучающих данных! Для обучения на GPU бесплатного уровня в Google Colab мы рекомендуем ограничить объем обучающих +данных примерно до 10-15 часов. + +После завершения процесса дообучения поделитесь своей моделью, загрузив ее в Hub. Обязательно пометьте модель +как модель `text-to-speech` либо соответствующими параметрами kwargs, либо через графический интерфейс Hub. + +Помните, что основная цель этого упражнения - предоставить вам обширную практику, которая позволит вам отточить свои навыки и +получить более глубокое представление об аудиозадачах преобразования текста в речь. diff --git a/chapters/ru/chapter6/introduction.mdx b/chapters/ru/chapter6/introduction.mdx new file mode 100644 index 00000000..86806abc --- /dev/null +++ b/chapters/ru/chapter6/introduction.mdx @@ -0,0 +1,29 @@ +# Раздел 6. От текста к речи + +В предыдущем разделе вы узнали, как использовать трансформеры для преобразования устной речи в текст. Теперь давайте перевернем сценарий +и посмотрим, как можно преобразовать заданный входной текст в аудио вывод, звучащий как человеческая речь. + +Задача, которую мы будем изучать в этом блоке, называется "Преобразование текста в речь " (Text-to-speech, TTS). Модели, способные преобразовывать текст в слышимую +человеческую речь, имеют широкий спектр потенциальных применений: + +* Вспомогательные приложения: подумайте об инструментах, которые могут использовать эти модели для обеспечения доступа людей с ослабленным зрением к цифровому контенту с помощью звука. +* Озвучивание аудиокниг: перевод письменных книг в аудиоформат делает литературу более доступной для тех, кто предпочитает слушать или испытывает трудности с чтением. +* Виртуальные помощники: TTS-модели являются фундаментальным компонентом виртуальных помощников, таких как Siri, Google Assistant или Amazon Alexa. После того как они с помощью классификационной модели поймали слово "пробуждение" и использовали ASR-модель для обработки запроса, они могут использовать TTS-модель для ответа на ваш запрос. +* Развлечения, игры и изучение языков: озвучивайте персонажей NPC, рассказывайте об игровых событиях или помогайте изучающим язык примерами правильного произношения и интонации слов и фраз. + +Это лишь некоторые примеры, и я уверен, что вы можете придумать множество других! Однако с такой мощью приходит и ответственность +,важно подчеркнуть, что модели TTS потенциально могут быть использованы в злонамеренных целях. +Например, имея достаточное количество образцов голоса, злоумышленники могут создавать убедительные поддельные аудиозаписи, что приводит к +несанкционированному использованию голоса человека в мошеннических целях или для манипуляций. Если вы планируете собирать данные для дообучения +собственных систем, тщательно продумайте вопросы конфиденциальности и информационного согласия. Получение голосовых данных должно осуществляться с явного согласия +людей, при этом они должны понимать цель, объем и потенциальные риски, связанные с использованием их голоса +в системе TTS. Пожалуйста, используйте преобразование текста в речь ответственно. + +## Чему вы научитесь и что создадите + +В этом разделе мы поговорим о: + +* [Наборах данных, пригодных для обучения Text-to-speech](tts_datasets) +* [Предварительно обученных моделях для преобразования текста в речь](pre-trained_models) +* [Дообучение SpeechT5 на новом языке](fine-tuning) +* [Оценке моделей TTS](evaluation) diff --git a/chapters/ru/chapter6/pre-trained_models.mdx b/chapters/ru/chapter6/pre-trained_models.mdx new file mode 100644 index 00000000..dcf7e10a --- /dev/null +++ b/chapters/ru/chapter6/pre-trained_models.mdx @@ -0,0 +1,258 @@ +# Предварительно обученные модели 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 architecture from the original paper +
+ +SpeechT5 сначала проходит предварительное обучение на больших объемах немаркированных речевых и текстовых данных, чтобы получить единое представление +различных модальностей. На этапе предварительного обучения все предварительные и последующие сети используются одновременно. + +После предварительного обучения вся структура энкодера-декодера настраивается для каждой конкретной задачи. На этом этапе используются только те +пред-сети и пост-сети, которые имеют отношение к конкретной задаче. Например, чтобы использовать SpeechT5 для преобразования текста в речь, необходимо +использовать предварительную сеть энкодера текста для текстовых входов и предварительную и пост-сети декодера речи для речевых выходов. + +Такой подход позволяет получить несколько моделей, дообученных для различных речевых задач, все они выигрывают от первоначального +предварительного обучения на немаркированных данных. + + + +Несмотря на то что в начале работы дообученные модели используют один и тот же набор весов из общей предварительно обученной модели, конечные версии +в итоге оказываются совершенно разными. Например, вы не можете взять дообученную ASR-модель и поменять местами пред-сети и пост-сети, +чтобы получить рабочую TTS-модель. SpeechT5 гибкая, но не настолько ;) + + + +Посмотрим, какие пред- и пост-сети использует SpeechT5 для решения задачи TTS: + +* Предварительная сеть энкодера текста: Слой эмбедингов текста, который сопоставляет текстовые токены со скрытыми представлениями, ожидаемыми энкодером. Это аналогично тому, что происходит в NLP-модели, такой как BERT. +* Предварительная сеть декодера речи: На вход подается лог мел спектрограммы, и с помощью последовательности линейных слоев спектрограмма сжимается в скрытые представления. +* Пост-сеть декодера речи: Здесь прогнозируется остаток, который добавляется к выходной спектрограмме и используется для уточнения результатов. + +В совокупности именно так выглядит архитектура SpeechT5 для преобразования текста в речь: + +
+ SpeechT5 architecture for TTS +
+ +Как видите, на выходе получается лог-мел спектрограмма, а не конечная форма волны. Если вы помните, мы вкратце касались +этой темы в [Разделе 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, изучайте другие голоса, экспериментируйте с вводом. Обратите внимание, что эта +предварительно обученная контрольная точка поддерживает только английский язык: + + + +## 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("Matthijs/mms-tts-deu") +tokenizer = VitsTokenizer.from_pretrained("Matthijs/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! diff --git a/chapters/ru/chapter6/supplemental_reading.mdx b/chapters/ru/chapter6/supplemental_reading.mdx new file mode 100644 index 00000000..0d79a901 --- /dev/null +++ b/chapters/ru/chapter6/supplemental_reading.mdx @@ -0,0 +1,10 @@ +# Дополнительные материалы и ресурсы + +В этом разделе была представлена задача преобразования текста в речь. +Хотите узнать больше? Здесь вы найдете дополнительные ресурсы, которые помогут вам углубить понимание рассматриваемых тем +и повысить эффективность обучения. + +* [HiFi-GAN: генеративные состязательные сети для эффективного и высококачественного синтеза речи](https://arxiv.org/pdf/2010.05646.pdf): статья, в которой представлена HiFi-GAN для синтеза речи. +* [Х-Векторы: Надежные DNN-Эмбединги для распознавания дикторов](https://www.danielpovey.com/files/2018_icassp_xvectors.pdf): статья, в которой представлен метод Х-Векторов для эмбеддингов дикторов. +* [FastSpeech 2: быстрое и высококачественное преобразование текста в речь](https://arxiv.org/pdf/2006.04558.pdf): статья, в которой представлена FastSpeech 2 - еще одна популярная модель преобразования текста в речь, использующая неавторегрессионный TTS метод. +* [Векторно-квантованный подход для синтеза текста в речь на основе спонтанной речи в реальном мире](https://arxiv.org/pdf/2302.04215v1.pdf): статья, посвященная MQTTS - авторегрессионной системе TTS, в которой мел-спектрограммы заменены квантованным дискретным представлением. diff --git a/chapters/ru/chapter6/tts_datasets.mdx b/chapters/ru/chapter6/tts_datasets.mdx new file mode 100644 index 00000000..9b0be552 --- /dev/null +++ b/chapters/ru/chapter6/tts_datasets.mdx @@ -0,0 +1,76 @@ +# Наборах данных Text-to-speech + +Задача преобразования текста в речь (называемая также _синтезом речи_) сопряжена с целым рядом трудностей. + +Во-первых, как и в ранее рассмотренном случае автоматического распознавания речи, согласование текста и речи может быть затруднено. +Однако, в отличие от ASR, TTS - это проблема отображения **одного ко многим**, т.е. один и тот же текст может быть синтезирован множеством различных способов. Подумайте о разнообразии голосов и стилей речи, +которые вы слышите ежедневно - каждый человек по-своему произносит одно и то же предложение, но все они правильные и верные! Даже разные выходные данные (спектрограммы или формы волны звука) +могут соответствовать одной и той же истине. Модель должна научиться генерировать правильную длительность и время для каждой фонемы, слова или предложения, что может оказаться непростой задачей, +особенно для длинных и сложных предложений. + +Далее, существует проблема дальних зависимостей: язык имеет временной аспект, и понимание смысла предложения +часто требует учета контекста окружающих слов. Убедиться в том, что модель TTS улавливает и сохраняет контекстную информацию +в длинных последовательностях, очень важно для создания связной и естественно звучащей речи. + +Наконец, для обучения TTS-моделей обычно требуются пары из текста и соответствующих записей речи. Кроме того, для того чтобы +модель могла генерировать речь, звучащую естественно для различных дикторов и стилей речи, данные должны содержать разнообразные и +репрезентативные образцы речи от различных дикторов. Сбор таких данных является дорогостоящим, трудоемким и для некоторых языков +нецелесообразным. Вы можете подумать, почему бы просто не взять набор данных, предназначенный для ASR (автоматического распознавания речи), и не использовать его для +обучения модели TTS? К сожалению, наборы данных автоматического распознавания речи (ASR) - не самый лучший вариант. Особенности, которые +делают его полезным для ASR, например, чрезмерный фоновый шум, обычно нежелательны в TTS. Очень хорошо, если вы можете +выделить речь из шумной уличной записи, но не очень хорошо, если ваш голосовой помощник отвечает вам на фоне гудка машин +и бурного строительства на заднем плане. Тем не менее, некоторые наборы данных ASR иногда могут быть полезны для дообучения, +так как найти высококачественные, многоязычные и многоголосые наборы данных TTS может быть довольно сложно. + +Рассмотрим несколько наборов данных, подходящих для TTS, которые можно найти на 🤗 Hub. + +## LJSpeech + +[LJSpeech](https://huggingface.co/datasets/lj_speech) представляет собой набор данных, состоящий из 13 100 англоязычных аудиоклипов, +сопоставленных с соответствующими транскрипциями. Набор содержит запись чтения одним диктором предложений +из 7 нехудожественных книг на английском языке. LJSpeech часто используется в качестве эталона для оценки моделей TTS +благодаря высокому качеству звука и разнообразию лингвистического контента. + +## Multilingual LibriSpeech + +[Multilingual LibriSpeech](https://huggingface.co/datasets/facebook/multilingual_librispeech) является многоязычным расширением +набора данных LibriSpeech, представляющего собой крупномасштабную коллекцию прочитанных англоязычных аудиокниг. Многоязычный LibriSpeech +расширяется за счет включения дополнительных языков, таких как немецкий, голландский, испанский, французский, итальянский, португальский и польский. +Он предлагает аудиозаписи вместе с выверенными транскрипциями для каждого языка. Этот набор данных представляет собой ценный ресурс +для разработки многоязычных систем TTS и изучения методов межъязыкового синтеза речи. + +## VCTK (Voice Cloning Toolkit) + +[VCTK](https://huggingface.co/datasets/vctk) - это набор данных, специально разработанный для исследований и разработок в области преобразования текста в речь. +Он содержит аудиозаписи 110 дикторов английского языка с различными акцентами. Каждый диктор зачитывает около 400 предложений, +которые были выбраны из газеты, [радужного отрывка](https://www.dialectsarchive.com/the-rainbow-passage)* и элективного абзаца, использованного для архива акцентов речи. +VCTK представляет собой ценный ресурс для обучения TTS-моделей с различными голосами и акцентами, что позволяет осуществлять более естественный и разнообразный +синтез речи. + +## Libri-TTS/ LibriTTS-R + +[Libri-TTS/ LibriTTS-R](https://huggingface.co/datasets/cdminix/libritts-r-aligned) это многоголосный корпус английской речи, +включающий около 585 часов чтения английской речи с частотой дискретизации 24 кГц, подготовленный компанией Heiga Zen при содействии членов команд Google Speech +и Google Brain. Корпус LibriTTS предназначен для исследования TTS. Он создан на основе оригинальных материалов +(аудиофайлов mp3 из LibriVox и текстовых файлов из Project Gutenberg) корпуса LibriSpeech. Основные отличия +от корпуса LibriSpeech перечислены ниже: + +* Аудиофайлы имеют частоту дискретизации 24 кГц. +* Речь разбита на фрагменты. +* Включены как оригинальные, так и нормализованные тексты. +* Контекстная информация (например, соседние предложения) может быть извлечена. +* Исключены фразы со значительным фоновым шумом. + +Собрать хороший набор данных для TTS - задача не из легких, поскольку такой набор должен обладать несколькими ключевыми характеристиками: + +* Качественные и разнообразные записи, охватывающие широкий спектр речевых паттернов, акцентов, языков и эмоций. Записи должны быть чистыми, без фоновых шумов и демонстрировать естественные характеристики речи. +* Транскрипция: Каждая аудиозапись должна сопровождаться соответствующей текстовой транскрипцией. +* Разнообразие лингвистического контента: Набор данных должен содержать разнообразный лингвистический контент, включая различные типы предложений, фраз и слов. Он должен охватывать различные темы, жанры и области, +чтобы обеспечить способность модели работать с различными языковыми контекстами. + +Хорошая новость заключается в том, что вряд ли вам придется обучать TTS-модель с нуля. В следующем разделе мы рассмотрим +предварительно обученные модели, доступные на 🤗 Hub. + +----- +* - радужный отрывок - это конкретный фрагмент текста, который часто используется в англоязычных исследованиях речи и голоса для оценки различных аспектов речи. Он включает в себя различные фонетические звуки и лингвистические паттерны, которые могут помочь исследователям понять, +как звуки речи произносятся людьми с различными акцентами или особенностями речи. diff --git a/chapters/ru/chapter7/hands-on.mdx b/chapters/ru/chapter7/hands-on.mdx new file mode 100644 index 00000000..b4410094 --- /dev/null +++ b/chapters/ru/chapter7/hands-on.mdx @@ -0,0 +1,45 @@ +# Практическое занятие + +В этом разделе мы объединили материал, рассмотренный в предыдущих шести разделах курса, для создания трех интегрированных +аудио приложений. Как вы убедились, создание более сложных аудио инструментов вполне достижимо при использовании базовых навыков работы +приобретенных в рамках данного курса. + +В практическом занятии используется одно из приложений, рассматриваемых в данном разделе, которое расширяется с помощью нескольких многоязычных +функций 🌍. Ваша задача - взять [каскадный перевод речи в речь из Gradio демо](https://huggingface.co/spaces/course-demos/speech-to-speech-translation) +из первого урока данного раздела и модернизировать его для перевода на любой **неанглийский** язык. То есть демо +должно принимать речь на языке X и переводить ее в речь на языке Y, где целевой язык Y не является английским. +Начать следует с [дублирования](https://huggingface.co/spaces/course-demos/speech-to-speech-translation?duplicate=true) шаблона в вашем пространстве +имен Hugging Face. Нет необходимости использовать GPU-ускоритель - бесплатный уровень подписки с CPU отлично справится с этой задачей 🤗. +Однако следует убедиться, что видимость вашего демо установлена в **public**. Это необходимо для того, чтобы ваше демо было доступно для нас +и могло быть проверено на корректность. + +Советы по обновлению функции перевода речи для выполнения многоязычного перевода приведены в разделе [перевод речи в речь](speech-to-speech). +Следуя этим инструкциям, вы сможете обновить демо версию для перевода с речи на языке X в текст на языке Y, а это уже половина задачи! + +Для синтеза из текста на языке Y в речь на языке Y, где Y - многоязычный язык, вам потребуется [NL] использовать контрольную точку многоязычной модели TTS. + +Для этого можно использовать либо контрольную точку SpeechT5 TTS, которую вы дообучали на предыдущем практическом занятии, либо предварительно +обученную контрольную точку многоязычной TTS. Существует два варианта предварительно обученных контрольных точек: либо контрольная точка +[sanchit-gandhi/speecht5_tts_vox_nl](https://huggingface.co/sanchit-gandhi/speecht5_tts_vox_nl), которая представляет собой контрольную точку SpeechT5, +дообученную на голландском фрагменте набора данных [VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli) [NL], либо контрольная точка MMS TTS +(смотрите раздел [предварительно обученные модели text-to-speech](../chapter6/pre-trained_models)). + + + По нашему опыту экспериментов с голландским языком, использование контрольной точки MMS TTS дает лучшую производительность, чем + с дообученной SpeechT5, но вы можете обнаружить, что ваша дообученная контрольная точка TTS предпочтительнее для вашего языка. + Если вы решили использовать контрольную точку MMS TTS, вам необходимо обновить requirements.txt + файл вашей демонстрации для установки transformers из ветки PR: +

git+https://github.com/hollance/transformers.git@6900e8ba6532162a8613d2270ec2286c3f58f57b

+
+ +Ваше демо должно принимать на вход аудиофайл, а на выходе возвращать другой аудиофайл, соответствующий сигнатуре функции +[`speech_to_speech_translation`](https://huggingface.co/spaces/course-demos/speech-to-speech-translation/blob/3946ba6705a6632a63de8672ac52a482ab74b3fc/app.py#L35) [NL] в шаблоне демо. + +Поэтому мы рекомендуем оставить основную функцию `speech_to_speech_translation` как есть, и обновлять лишь функции [`translate`](https://huggingface.co/spaces/course-demos/speech-to-speech-translation/blob/a03175878f522df7445290d5508bfb5c5178f787/app.py#L24) + и [`synthesise`](https://huggingface.co/spaces/course-demos/speech-to-speech-translation/blob/a03175878f522df7445290d5508bfb5c5178f787/app.py#L29) по мере необходимости. + +После того как вы создали своё демо в виде приложения Gradio на Hugging Face Hub, вы можете отправить его на оценку. Перейдите в пространство +[audio-course-u7-assessment](https://huggingface.co/spaces/huggingface-course/audio-course-u7-assessment) и при появлении запроса укажите идентификатор репозитория вашего демо. +Этот пространство проверяет правильность сборки демо-версии, посылая [NL] образец аудиофайла в демо и проверяя, что возвращаемый аудиофайл действительно неанглийский. + +Если ваше демо работает корректно, вы получите зеленую галочку рядом с вашим именем в общем [пространстве прогресса](https://huggingface.co/spaces/MariaK/Check-my-progress-Audio-Course) ✅. diff --git a/chapters/ru/chapter7/introduction.mdx b/chapters/ru/chapter7/introduction.mdx new file mode 100644 index 00000000..0d3d916b --- /dev/null +++ b/chapters/ru/chapter7/introduction.mdx @@ -0,0 +1,16 @@ +# Раздел 7. Собираем все воедино 🪢 + +Молодцы, что добрались до 7-го раздела 7 🥳 Вы находитесь всего в нескольких шагах от завершения курса и приобретения нескольких последних +навыков, необходимых для работы в области Аудио ML. Что касается понимания, то вы уже знаете все, что нужно знать! +Вместе мы всесторонне рассмотрели основные темы, составляющие аудио домен, и сопутствующую им теорию +(аудио данные, классификацию аудиоданных, распознавание речи и преобразование текста в речь). Целью данного раздела является создание основы +для **сочетания всего этого вместе**: теперь, когда вы знаете, как работает каждая из этих задач в отдельности, мы рассмотрим, как +вы можете объединить их вместе для создания некоторых реальных приложений. + +## Чему вы научитесь и что создадите + +В этом разделе мы рассмотрим следующие три темы: + +* [Перевод речи в речь](speech-to-speech): перевод речи с одного языка в речь на другом языке +* [Создание голосового ассистента](voice-assistant): создание собственного голосового помощника, работающего аналогично Alexa или Siri +* [Транскрибирование встреч](transcribe-meeting): транскрибация встречи и маркировка транскрипции с указанием того, кто когда выступал diff --git a/chapters/ru/chapter7/speech-to-speech.mdx b/chapters/ru/chapter7/speech-to-speech.mdx new file mode 100644 index 00000000..39039d63 --- /dev/null +++ b/chapters/ru/chapter7/speech-to-speech.mdx @@ -0,0 +1,256 @@ +# Перевод Speech-to-speech + +Перевод речи в речь (Speech-to-speech, STST или S2ST) - это относительно новая задача обработки устной речи. Она заключается +в переводе [NL] речи с одного языка в речь на **другом** языке: + +
+ Diagram of speech to speech translation +
+ +STST можно рассматривать как расширение традиционной задачи машинного перевода (МТ): вместо перевода **текста** с одного языка +на другой мы переводим **речь** с одного языка на другой. STST находит применение в области многоязыковой коммуникации, +позволяя носителям разных языков общаться друг с другом посредством речи. + +Предположим, вы хотите общаться с другим человеком, преодолевая языковой барьер. Вместо того чтобы писать информацию, которую вы хотите +передать, а затем переводить ее в текст на целевом языке, вы можете говорить напрямую, а система STST преобразует вашу устную речь +в целевой язык. Получатель может ответить, обратившись к системе STST, а вы можете прослушать его ответ. Это более естественный +способ общения по сравнению с машинным переводом текста. + +В этом разделе мы рассмотрим *каскадный* подход к STST, объединив знания, полученные в разделах 5 и 6 курса. Мы будем использовать +систему *перевода речи (ST)* для транскрибирования исходной речи в текст на целевом языке, а затем *перевода текста в речь (TTS)* +для генерации речи на целевом языке из переведенного текста: + +
+ Diagram of cascaded speech to speech translation +
+ +Можно было бы использовать и трехэтапный подход, когда сначала с помощью системы автоматического распознавания речи (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). diff --git a/chapters/ru/chapter7/supplemental_reading.mdx b/chapters/ru/chapter7/supplemental_reading.mdx new file mode 100644 index 00000000..030295be --- /dev/null +++ b/chapters/ru/chapter7/supplemental_reading.mdx @@ -0,0 +1,18 @@ +# Дополнительные материалы и ресурсы + +В этом разделе объединены многие компоненты из предыдущих разделов, представлены задачи перевода речи в речь, +голосовые помощники и диаризация диктора. Для удобства чтения дополнительный материал разбит на эти три новые задачи: + +Перевод речи в речь: +* [STST с дискретными блоками](https://ai.facebook.com/blog/advancing-direct-speech-to-speech-modeling-with-discrete-units/) от Meta AI: прямой подход к STST через модели энкодер-декодер +* [Hokkien прямой перевод речи в речь](https://ai.facebook.com/blog/ai-translation-hokkien/) от Meta AI: прямой подход к STST с использованием моделей энкодер-декодер с двухступенчатым декодером +* [Использование неконтролируемых и слабоконтролируемых данных для улучшения прямой STST](https://arxiv.org/abs/2203.13339) от Google: предлагает новые подходы к использованию неконтролируемых (unsupervised) и слабоконтролируемых (weakly supervised) данных для обучения прямых STST-моделей и небольшие изменения в архитектуре Transformer +* [Translatotron-2](https://google-research.github.io/lingvo-lab/translatotron2/) от Google: система, способная сохранять характеристики диктора в переведенной речи + +Голосовой ассистент: +* [Точное обнаружение пробуждающих слов (wakeword)](https://www.amazon.science/publications/accurate-detection-of-wake-word-start-and-end-using-a-cnn) от Amazon: подход с низкой задержкой для обнаружения пробуждающих слов (wakeword) для приложений на устройствах +* [RNN-Transducer Архитектура](https://arxiv.org/pdf/1811.06621.pdf) от Google: модификация архитектуры CTC для потокового ASR на устройствах + +Транскрипция встреч: +* [pyannote.audio Технический отчет](https://huggingface.co/pyannote/speaker-diarization/blob/main/technical_report_2.1.pdf) Эрве Бредин: в этом докладе описываются основные принципы, лежащие в основе конвейера диаризации дикторов `pyannote.audio +* [Whisper X](https://arxiv.org/pdf/2303.00747.pdf) by Max Bain et al.: усовершенствованный подход к вычислению временных меток на уровне слов с использованием модели Whisper \ No newline at end of file diff --git a/chapters/ru/chapter7/transcribe-meeting.mdx b/chapters/ru/chapter7/transcribe-meeting.mdx new file mode 100644 index 00000000..ccc83d20 --- /dev/null +++ b/chapters/ru/chapter7/transcribe-meeting.mdx @@ -0,0 +1,223 @@ +# Транскрибирование встречи + +В этом заключительном разделе мы используем модель Whisper для создания транскрипции разговора или встречи между двумя или более говорящими. Затем мы объединим +ее с моделью *диаризации диктора* для прогнозирования "кто когда говорил". Сопоставив временные метки из транскрипции Whisper с временными метками от модели диаризации, +мы можем спрогнозировать сквозную транскрипцию встречи с полностью отформатированным временем начала и окончания для каждого говорящего. Это базовая версия услуг по +транскрибированию совещаний, которую вы могли видеть в интернете от таких компаний, как [Otter.ai](https://otter.ai) и др: + +
+ +
+ +## Диаризация диктора + +Диаризация диктора (или диаризация) - это задача получения немаркированных аудиоданных и прогнозирования того, "кто когда говорил". При этом мы можем +прогнозировать временные метки начала/окончания каждой очереди дикторов, соответствующие моменту начала речи и моменту ее окончания. + +🤗 В настоящее время в библиотеке Transformers нет модели для диаризации диктора, но на Hub есть контрольные точки, которые можно использовать +с относительной легкостью. В этом примере мы будем использовать предварительно обученную модель диаризации диктора из [pyannote.audio](https://github.com/pyannote/pyannote-audio). +Давайте приступим к работе и установим пакет с помощью pip: + +```bash +pip install --upgrade pyannote.audio +``` + +Отлично! Веса для этой модели размещены на Hugging Face Hub. Чтобы получить к ним доступ, сначала нужно согласиться с условиями использования модели диаризации +диктора: [pyannote/speaker-diarization](https://huggingface.co/pyannote/speaker-diarization). А затем - с условиями использования модели +сегментации: [pyannote/segmentation](https://huggingface.co/pyannote/segmentation). + +После завершения работы мы можем загрузить предварительно обученный конвейер диаризации дикторов локально на наше устройство: + +```python +from pyannote.audio import Pipeline + +diarization_pipeline = Pipeline.from_pretrained( + "pyannote/speaker-diarization@2.1", use_auth_token=True +) +``` + +Давайте опробуем его на примере аудиофайла! Для этого мы загрузим образец из датасета [LibriSpeech ASR](https://huggingface.co/datasets/librispeech_asr), содержащий речь +двух разных дикторов, который мы объединили в один аудиофайл: + +```python +from datasets import load_dataset + +concatenated_librispeech = load_dataset( + "sanchit-gandhi/concatenated_librispeech", split="train", streaming=True +) +sample = next(iter(concatenated_librispeech)) +``` + +Мы можем прослушать аудиозапись, чтобы понять, как она звучит: + +```python +from IPython.display import Audio + +Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"]) +``` + +Класс! Мы отчетливо слышим двух разных дикторов с переходом примерно на 15 секунде звучания. Давайте передадим этот аудиофайл в модель диаризации, чтобы получить +время начала и окончания разговора. Заметим, что pyannote.audio ожидает, что входной аудиофайл будет представлять собой тензор PyTorch формы `(channels, seq_len)`, +поэтому перед запуском модели нам необходимо выполнить это преобразование: + +```python +import torch + +input_tensor = torch.from_numpy(sample["audio"]["array"][None, :]).float() +outputs = diarization_pipeline( + {"waveform": input_tensor, "sample_rate": sample["audio"]["sampling_rate"]} +) + +outputs.for_json()["content"] +``` + +```text +[{'segment': {'start': 0.4978125, 'end': 14.520937500000002}, + 'track': 'B', + 'label': 'SPEAKER_01'}, + {'segment': {'start': 15.364687500000002, 'end': 21.3721875}, + 'track': 'A', + 'label': 'SPEAKER_00'}] +``` + +Выглядит это довольно неплохо! Видно, что первый диктор говорит до отметки 14,5 секунды, а второй - с 15,4 секунды. +Теперь нам нужно получить транскрипцию! + +## Транскрибирование речи + +В третий раз в этом блоке мы будем использовать модель Whisper для нашей системы транскрипции речи. В частности, мы загрузим контрольную точку [Whisper Base](https://huggingface.co/openai/whisper-base), +поскольку она достаточно мала, чтобы обеспечить хорошую скорость инференса при приемлемой точности транскрипции. Как и прежде, вы можете использовать любую контрольную точку распознавания речи с +[Hub](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition&library=transformers&sort=trending), включая Wav2Vec2, MMS ASR или другие контрольные точки Whisper: + +```python +from transformers import pipeline + +asr_pipeline = pipeline( + "automatic-speech-recognition", + model="openai/whisper-base", +) +``` + +Давайте получим транскрипцию для нашего образца аудиозаписи, возвращая также временные метки на уровне сегментов, чтобы знать время начала и окончания каждого сегмента. +Из раздела 5 вы помните, что для активации задачи прогнозирования временных меток в Whisper нам необходимо передать аргумент `return_timestamps=True`: + +```python +asr_pipeline( + sample["audio"].copy(), + generate_kwargs={"max_new_tokens": 256}, + return_timestamps=True, +) +``` + +```text +{ + "text": " The second and importance is as follows. Sovereignty may be defined to be the right of making laws. In France, the king really exercises a portion of the sovereign power, since the laws have no weight. He was in a favored state of mind, owing to the blight his wife's action threatened to cast upon his entire future.", + "chunks": [ + {"timestamp": (0.0, 3.56), "text": " The second and importance is as follows."}, + { + "timestamp": (3.56, 7.84), + "text": " Sovereignty may be defined to be the right of making laws.", + }, + { + "timestamp": (7.84, 13.88), + "text": " In France, the king really exercises a portion of the sovereign power, since the laws have", + }, + {"timestamp": (13.88, 15.48), "text": " no weight."}, + { + "timestamp": (15.48, 19.44), + "text": " He was in a favored state of mind, owing to the blight his wife's action threatened to", + }, + {"timestamp": (19.44, 21.28), "text": " cast upon his entire future."}, + ], +} +``` + +Отлично! Мы видим, что каждый сегмент транскрипции имеет начальное и конечное время, причем смена дикторов происходит на отметке 15,48 секунды. Теперь мы можем сопоставить +эту транскрипцию с временными метками дикторов, полученными с помощью модели диаризации, и получить окончательную транскрипцию. + +## Speechbox + +Чтобы получить окончательную транскрипцию, совместим временные метки, полученные с помощью модели диаризации, с временными метками, полученными с помощью модели Whisper. +Модель диаризации предсказала окончание речи первого диктора на 14,5 с, а второго - на 15,4 с, в то время как Whisper предсказал границы сегментов на 13,88, 15,48 и 19,44 с соответственно. +Поскольку временные метки, полученные с помощью Whisper, не полностью совпадают с данными модели диаризации, нам необходимо найти, какие из этих границ ближе всего к 14,5 и 15,4 с, и +соответствующим образом сегментировать транскрипцию по дикторам. В частности, мы найдем наиболее близкое совпадение между временными метками диаризации и транскрипции, +минимизировав абсолютное расстояние между ними. + +К счастью для нас, мы можем использовать пакет 🤗 Speechbox для выполнения этого выравнивания. Сначала давайте установим пакет `speechbox` из main: + +```bash +pip install git+https://github.com/huggingface/speechbox +``` + +Теперь мы можем инстанцировать наш комбинированный конвейер диаризации и транскрипции, передав модель диаризации и +модель ASR в класс [`ASRDiarizationPipeline`](https://github.com/huggingface/speechbox/tree/main#asr-with-speaker-diarization): + +```python +from speechbox import ASRDiarizationPipeline + +pipeline = ASRDiarizationPipeline( + asr_pipeline=asr_pipeline, diarization_pipeline=diarization_pipeline +) +``` + + + Вы также можете инстанцировать ASRDiarizationPipeline directly непосредственно из предварительно обученных моделей, указав идентификатор + модели ASR на Hub: +

pipeline = ASRDiarizationPipeline.from_pretrained("openai/whisper-base")

+
+ +Передадим аудиофайл в композитный конвейер и посмотрим, что получится в результате: + +```python +pipeline(sample["audio"].copy()) +``` + +```text +[{'speaker': 'SPEAKER_01', + 'text': ' The second and importance is as follows. Sovereignty may be defined to be the right of making laws. In France, the king really exercises a portion of the sovereign power, since the laws have no weight.', + 'timestamp': (0.0, 15.48)}, + {'speaker': 'SPEAKER_00', + 'text': " He was in a favored state of mind, owing to the blight his wife's action threatened to cast upon his entire future.", + 'timestamp': (15.48, 21.28)}] +``` + +Отлично! Первый диктор сегментирован как говорящий с 0 до 15,48 секунды, а второй - с 15,48 до 21,28 секунды, +с соответствующими транскрипциями для каждого из них. + +Для более удобного форматирования временных меток можно определить две вспомогательные функции. Первая преобразует кортеж временных меток в строку, округленную +до заданного количества знаков после запятой. Вторая объединяет идентификатор диктора, временную метку и текстовую информацию в одну строку, а для удобства +чтения разбивает каждого диктора на отдельные строки: + +```python +def tuple_to_string(start_end_tuple, ndigits=1): + return str((round(start_end_tuple[0], ndigits), round(start_end_tuple[1], ndigits))) + + +def format_as_transcription(raw_segments): + return "\n\n".join( + [ + chunk["speaker"] + " " + tuple_to_string(chunk["timestamp"]) + chunk["text"] + for chunk in raw_segments + ] + ) +``` + +Повторно запустим конвейер, на этот раз форматируя транскрипцию в соответствии с функцией, которую мы только что определили: + +```python +outputs = pipeline(sample["audio"].copy()) + +format_as_transcription(outputs) +``` + +```text +SPEAKER_01 (0.0, 15.5) The second and importance is as follows. Sovereignty may be defined to be the right of making laws. +In France, the king really exercises a portion of the sovereign power, since the laws have no weight. + +SPEAKER_00 (15.5, 21.3) He was in a favored state of mind, owing to the blight his wife's action threatened to cast upon +his entire future. +``` + +Вот так! Таким образом, мы провели диарирование и транскрибацию входного аудиосигнала и получили транскрибации с сегментацией дикторов. Хотя алгоритм минимального расстояния для +выравнивания временных меток диаризации и транскрибации прост, он хорошо работает на практике. Если вы хотите изучить более сложные методы совмещения временных меток, то исходный +код `ASRDiarizationPipeline` является хорошей отправной точкой: [speechbox/diarize.py](https://github.com/huggingface/speechbox/blob/96d2d1a180252d92263f862a1cd25a48860f1aed/src/speechbox/diarize.py#L12) diff --git a/chapters/ru/chapter7/voice-assistant.mdx b/chapters/ru/chapter7/voice-assistant.mdx new file mode 100644 index 00000000..09de5e77 --- /dev/null +++ b/chapters/ru/chapter7/voice-assistant.mdx @@ -0,0 +1,458 @@ +# Создание голосового ассистента + +В этом разделе мы объединим три модели, с которыми уже имели практический опыт работы, и создадим полноценный голосовой помощник под названием **Marvin** 🤖. +Подобно Amazon Alexa или Apple Siri, Marvin - это виртуальный голосовой помощник, который реагирует на определенное "слово активации", затем слушает голосовой +запрос и, наконец, отвечает на него. + +Мы можем разбить конвейер голосового помощника на четыре этапа, каждый из которых требует отдельной модели: + +
+ +
+ +### 1. Обнаружение слова активации + +Голосовые помощники постоянно прослушивают аудиосигналы, поступающие через микрофон вашего устройства, но включаются +в работу только после произнесения определенного 'слова активации' или 'триггерного слова'. + +Задачу обнаружения слов активации решает небольшая модель классификации звука на устройстве, которая значительно меньше и легче модели +распознавания речи - часто всего несколько миллионов параметров по сравнению с несколькими сотнями миллионов для распознавания речи. Таким +образом, она может постоянно работать на устройстве, не разряжая аккумулятор. Только при обнаружении "слова активации" запускается более +крупная модель распознавания речи, после чего она снова отключается. + +### 2. Транскрибирование речи + +Следующий этап - транскрибация произнесенного запроса в текст. На практике передача аудиофайлов с локального устройства в облако происходит +медленно из-за большого размера аудиофайлов, поэтому эффективнее транскрибировать их напрямую с помощью модели автоматического распознавания речи (ASR) +на устройстве, а не использовать модель в облаке. Модель на устройстве может быть меньше и, следовательно, менее точной, чем модель, размещенная в облаке, +но более высокая скорость инференса оправдывает себя, поскольку мы можем работать с распознаванием речи практически в реальном времени, транскрибируя +произнесенные нами фразы по мере их произнесения. + +Мы уже хорошо знакомы с процессом распознавания речи, так что это должно быть проще простого! + +### 3. Запрос к языковой модели + +Теперь, когда мы знаем, что спросил пользователь, нам нужно сгенерировать ответ! Лучшими моделями-кандидатами для решения этой задачи являются +*большие языковые модели (Large Language Models, LLM)*, поскольку они способны эффективно понять семантику текстового запроса +и сгенерировать подходящий ответ. + +Поскольку наш текстовый запрос невелик (всего несколько текстовых токенов), а языковые модели велики (многие миллиарды параметров), наиболее эффективным +способом проведения инференса LLM является отправка текстового запроса с устройства на LLM, запущенную в облаке, генерация текстового ответа и возврат +ответа обратно на устройство. + +### 4. Синтез речи + +Наконец, мы используем модель преобразования текста в речь (TTS) для синтеза текстового ответа в устную речь. Это делается на устройстве, но можно запустить +модель TTS в облаке, генерируя аудио вывод и передавая его обратно на устройство. + +Опять же, мы делали это уже несколько раз, так что процесс будет очень знакомым! + +## Обнаружение слова активации + +Первым этапом работы голосового помощника является определение того, было ли произнесено слово активации, для решения этой задачи нам необходимо найти подходящую +предварительно обученную модель! Из раздела [Предварительно обученные модели классификации звука](../chapter4/classification_models) вы помните, что +[Speech Commands](https://huggingface.co/datasets/speech_commands) - это набор устных слов, предназначенный для оценки моделей классификации звука на 15+ простых +командных словах, таких как `"вверх"`, `"вниз"`, `"да"` и `"нет"`, а также метка `"тишина"` для классификации отсутствия речи. Уделите минутку прослушиванию +образцов в программе просмотра наборов данных на Hub и заново познакомиться с набором данных Speech Commands: [datasets viewer](https://huggingface.co/datasets/speech_commands/viewer/v0.01/train). + +Мы можем взять модель классификации звука, предварительно обученную на наборе данных Speech Commands, и выбрать одно из этих простых командных слов +в качестве слова активации. Если из 15 с лишним возможных командных слов модель предсказывает выбранное нами слово активации с наибольшей +вероятностью, мы можем быть уверены, что оно было произнесено". + +Давайте зайдем в Hugging Face Hub и перейдем на вкладку "Models": https://huggingface.co/models. + +В результате будут отображены все модели на Hugging Face Hub, отсортированные по количеству загрузок за последние 30 дней: + +
+ +
+ +С левой стороны вы заметите, что у нас есть ряд вкладок, которые мы можем выбрать для фильтрации моделей по задачам, библиотекам, набору данных и т.д. +Прокрутите страницу вниз и выберите задачу " Audio Classification " из списка задач аудио: + +
+ +
+ +Теперь нам представлено подмножество из 500+ моделей классификации звука на Hub. Для дальнейшего уточнения этой выборки мы можем +отфильтровать модели по датасету. Перейдите на вкладку "Datasets" и в строке поиска введите "speech_commands". При вводе текста +под вкладкой поиска появится выделение `speech_commands. Нажав на эту кнопку, можно отфильтровать все модели классификации звука на те, +которые были дообучены на датасете Speech Commands: + +
+ +
+ +Отлично! Мы видим, что для данного датасета и задачи нам доступны шесть предварительно обученных моделей (хотя, если вы +читаете этот материал позднее, могут быть добавлены новые модели!) Первую из этих моделей вы узнаете как [Audio Spectrogram Transformer checkpoint](https://huggingface.co/MIT/ast-finetuned-speech-commands-v2) +которую мы использовали в примере 4-го раздела. Мы снова будем использовать эту контрольную точку для задачи определения слова активации. + +Перейдем к загрузке контрольной точки с помощью класса `pipeline`: + +```python +from transformers import pipeline +import torch + +device = "cuda:0" if torch.cuda.is_available() else "cpu" + +classifier = pipeline( + "audio-classification", model="MIT/ast-finetuned-speech-commands-v2", device=device +) +``` + +Мы можем проверить, на каких метках обучалась модель, проверив атрибут `id2label` в конфигурации модели: + +```python +classifier.model.config.id2label +``` + +Отлично! Мы видим, что модель была обучена на 35 метках классов, включая некоторые простые командные слова, которые мы описали выше, а +также некоторые конкретные объекты, такие как `"bed"`, `"house"` и `"cat"`. Мы видим, что в этих метках класса есть одно имя: +id 27 соответствует метке **"marvin "**: + +```python +classifier.model.config.id2label[27] +``` + +``` +'marvin' +``` + +Отлично! Мы можем использовать это имя в качестве слова активации для нашего голосового помощника, подобно тому, как используется +"Alexa" для Amazon Alexa или "Hey Siri" для Apple Siri. Если из всех возможных меток модель с наибольшей вероятностью предсказывает +`"marvin"`, мы можем быть уверены, что выбранное нами слово активации было произнесено. + +Теперь нам необходимо определить функцию, которая будет постоянно прослушивать микрофонный вход нашего устройства и непрерывно передавать +звук в модель классификации для проведения инференса. Для этого мы воспользуемся удобной вспомогательной функцией, входящей +в состав 🤗 Transformers, под названием [`ffmpeg_microphone_live`](https://github.com/huggingface/transformers/blob/fb78769b9c053876ed7ae152ee995b0439a4462a/src/transformers/pipelines/audio_utils.py#L98). + +Эта функция направляет в модель для классификации небольшие фрагменты звука заданной длины `chunk_length_s`. Для обеспечения плавных +границ между фрагментами звука мы используем скользящее окно с шагом `chunk_length_s / 6`. Чтобы не ждать, пока запишется весь первый фрагмент, +прежде чем приступить к инференсу, мы также определяем минимальную продолжительность по времени аудио входа `stream_chunk_s`, +который передается в модель до достижения времени `chunk_length_s`. + +Функция `ffmpeg_microphone_live` возвращает объект *generator*, создающий последовательность аудиофрагментов, каждый из которых может быть +передан модели классификации для предсказания. Мы можем передать этот генератор непосредственно в `pipeline`, который, в свою очередь, +возвращает на выходе последовательность прогнозов, по одному для каждого фрагмента входного аудиосигнала. Мы можем просмотреть вероятности +меток классов для каждого фрагмента и остановить цикл обнаружения слов активации, когда обнаружим, что слово активации было произнесено. + +Для классификации произнесения слова активации мы будем использовать очень простой критерий: если метка класса с наибольшей вероятностью является +словом активации и эта вероятность превышает порог `prob_threshold`, то мы объявляем, что слово активации было произнесено. Использование порога +вероятности для управления классификатором таким образом гарантирует, что слово активации не будет ошибочно предсказано, если аудиосигнал является +шумом, что обычно происходит, когда модель очень неопределенна и все вероятности меток классов низки. Возможно, вы захотите настроить этот порог +вероятности или использовать более сложные средства для принятия решения о слове активации с помощью метрики [*entropy*](https://en.wikipedia.org/wiki/Entropy_(information_theory)) +(или метрики, основанной на неопределенности). + +```python +from transformers.pipelines.audio_utils import ffmpeg_microphone_live + + +def launch_fn( + wake_word="marvin", + prob_threshold=0.5, + chunk_length_s=2.0, + stream_chunk_s=0.25, + debug=False, +): + if wake_word not in classifier.model.config.label2id.keys(): + raise ValueError( + f"Wake word {wake_word} not in set of valid class labels, pick a wake word in the set {classifier.model.config.label2id.keys()}." + ) + + sampling_rate = classifier.feature_extractor.sampling_rate + + mic = ffmpeg_microphone_live( + sampling_rate=sampling_rate, + chunk_length_s=chunk_length_s, + stream_chunk_s=stream_chunk_s, + ) + + print("Listening for wake word...") + for prediction in classifier(mic): + prediction = prediction[0] + if debug: + print(prediction) + if prediction["label"] == wake_word: + if prediction["score"] > prob_threshold: + return True +``` + +Давайте опробуем эту функцию и посмотрим, как она работает! Установим флаг `debug=True`, чтобы выводить прогнозы для каждого фрагмента звука. Пусть модель +поработает несколько секунд, чтобы увидеть, какие предсказания она делает при отсутствии речевого ввода, затем четко произнесем слово активации `"marvin"` +и увидим, как предсказание метки класса для `"marvin"` подскочит почти до 1: + +```python +launch_fn(debug=True) +``` + +```text +Listening for wake word... +{'score': 0.055326107889413834, 'label': 'one'} +{'score': 0.05999856814742088, 'label': 'off'} +{'score': 0.1282748430967331, 'label': 'five'} +{'score': 0.07310110330581665, 'label': 'follow'} +{'score': 0.06634809821844101, 'label': 'follow'} +{'score': 0.05992642417550087, 'label': 'tree'} +{'score': 0.05992642417550087, 'label': 'tree'} +{'score': 0.999913215637207, 'label': 'marvin'} +``` + +Потрясающе! Как мы и ожидали, в течение первых нескольких секунд модель генерирует "мусорные" предсказания. Речевой ввод отсутствует, поэтому модель +делает прогнозы, близкие к случайным, но с очень низкой вероятностью. Как только мы произносим слово активации, модель прогнозирует `"marvin"` +с вероятностью, близкой к 1, и завершает цикл, сигнализируя о том, что слово активации обнаружено и система ASR должна быть активирована! + +## Транскрибирование речи + +И снова мы будем использовать модель Whisper для нашей системы транскрипции речи. В частности, мы загрузим контрольную точку +[Whisper Base English](https://huggingface.co/openai/whisper-base.en), поскольку она достаточно мала, чтобы обеспечить хорошую скорость инференса при приемлемой +точности транскрипции. Мы будем использовать трюк, позволяющий получить транскрипцию практически в реальном времени за счет умного подхода к передаче аудиосигнала +в модель. Как и прежде, можно использовать любую контрольную точку распознавания речи на [Hub](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition&library=transformers&sort=trending), +включая Wav2Vec2, MMS ASR или другие контрольные точки Whisper: + +```python +transcriber = pipeline( + "automatic-speech-recognition", model="openai/whisper-base.en", device=device +) +``` + + + Если вы используете GPU, вы можете увеличить размер контрольной точки, чтобы использовать контрольную точку Whisper Small English, + которая обеспечит более высокую точность транскрипции и при этом не превысит требуемый порог задержки. + Просто поменяйте id модели на: "openai/whisper-small.en". + + +Теперь мы можем определить функцию для записи сигнала с микрофона и транскрипции соответствующего текста. С помощью вспомогательной +функции `ffmpeg_microphone_live` мы можем управлять тем, насколько `в реальном времени` работает наша модель распознавания речи. +Использование меньшего `stream_chunk_s` позволяет распознавать речь в реальном времени, поскольку мы делим входной звук на более +мелкие фрагменты и транскрибируем их на лету. Однако за счет этого снижается точность, поскольку модель получает меньше контекста для инференса. + +В процессе транскрибации речи нам также необходимо знать, когда пользователь **прекращает** говорить, чтобы можно было прервать запись. +Для простоты мы будем прекращать запись с микрофона после первого `chunk_length_s` (по умолчанию это 5 секунд), но вы можете +поэкспериментировать с использованием модели [voice activity detection (VAD)](https://huggingface.co/models?pipeline_tag=voice-activity-detection&sort=trending), +чтобы предсказать, когда пользователь прекращает говорить. + +```python +import sys + + +def transcribe(chunk_length_s=5.0, stream_chunk_s=1.0): + sampling_rate = transcriber.feature_extractor.sampling_rate + + mic = ffmpeg_microphone_live( + sampling_rate=sampling_rate, + chunk_length_s=chunk_length_s, + stream_chunk_s=stream_chunk_s, + ) + + print("Start speaking...") + for item in transcriber(mic, generate_kwargs={"max_new_tokens": 128}): + sys.stdout.write("\033[K") + print(item["text"], end="\r") + if not item["partial"][0]: + break + + return item["text"] +``` + +Давайте попробуем и посмотрим, что у нас получится! Как только микрофон заработает, начинайте говорить и наблюдайте, +как ваша транскрипция появляется в полуреальном времени: + +```python +transcribe() +``` + +```text +Start speaking... + Hey, this is a test with the whisper model. +``` + +Отлично! Вы можете регулировать максимальную длину звука `chunk_length_s` в зависимости от того, насколько быстро или медленно +вы говорите (увеличить, если вам показалось, что вы не успели договорить, уменьшить, если вы были вынуждены ждать в конце), и +`stream_chunk_s` для фактора реального времени. Просто передайте их в качестве аргументов функции `transcribe`. + +## Запрос к языковой модели + +Теперь, когда мы получили транскрибацию нашего запроса, мы хотим сгенерировать осмысленный ответ. Для этого мы воспользуемся LLM, размещенным в облаке. +В частности, мы выберем LLM на Hugging Face Hub и воспользуемся [Inference API](https://huggingface.co/inference-api), чтобы легко +передать запрос модели. + +Для начала перейдём на хаб Hugging Face. Для выбора нашей модели LLM мы воспользуемся [🤗 Open LLM Leaderboard](https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard) +пространством, которое ранжирует модели LLM по производительности в четырех задачах генерации. Мы будем искать по "instruct", чтобы отфильтровать модели, которые были дообучены +на инструкциях, так как они должны лучше работать для нашей задачи передачи запроса (querying task): + +
+ +
+ +Мы будем использовать контрольную точку [tiiuae/falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct) от [TII](https://www.tii.ae/) - LM с декодером только на 7B параметров, +которая дообучена на смеси датасетов чатов и инструкций. Вы можете использовать любую LLM на Hugging Face Hub, у которой активирован параметр "Hosted inference API", +просто обратите внимание на виджет в правой части карточки модели: + +
+ +
+ +Inference API позволяет отправить HTTP-запрос с локальной машины на LLM, размещенную на Hub, и возвращает ответ в виде файла `json`. +Все, что нам нужно, - это указать наш токен Hugging Face Hub (который мы получаем непосредственно из нашей папки Hugging Face Hub) +и идентификатор модели LLM, которой мы хотим передать запрос: + +```python +from huggingface_hub import HfFolder +import requests + + +def query(text, model_id="tiiuae/falcon-7b-instruct"): + api_url = f"https://api-inference.huggingface.co/models/{model_id}" + headers = {"Authorization": f"Bearer {HfFolder().get_token()}"} + payload = {"inputs": text} + + print(f"Querying...: {text}") + response = requests.post(api_url, headers=headers, json=payload) + return response.json()[0]["generated_text"][len(text) + 1 :] +``` + +Давайте попробуем это сделать с помощью тестового ввода! + +```python +query("What does Hugging Face do?") +``` + +``` +'Hugging Face is a company that provides natural language processing and machine learning tools for developers. They' +``` + +Вы можете заметить, насколько быстро выполняется инференс с помощью Inference API - нам нужно отправить лишь небольшое количество текстовых токенов +с нашей локальной машины на размещенную на сервере модель, поэтому затраты на связь очень малы. LLM размещается на GPU-ускорителях, поэтому инференс +выполняется очень быстро. Наконец, сгенерированный ответ передается обратно от модели на нашу локальную машину, +что также не требует больших коммуникационных затрат. + +## Синтез речи + +Теперь мы готовы к получению окончательного речевого вывода! В очередной раз мы будем использовать модель Microsoft [SpeechT5 TTS](https://huggingface.co/microsoft/speecht5_tts) +для TTS на английском языке, но вы можете использовать любую модель TTS по своему усмотрению. Давайте загрузим процессор и модель: + +```python +from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan + +processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts") + +model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts").to(device) +vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan").to(device) +``` + +А также эбеддинги диктора: + +```python +from datasets import load_dataset + +embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation") +speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0) +``` + +Мы повторно используем функцию `synthesise`, которую мы определили в предыдущей главе [Перевод речи в речь] (speech-to-speech): + +```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 +from IPython.display import Audio + +audio = synthesise( + "Hugging Face is a company that provides natural language processing and machine learning tools for developers." +) + +Audio(audio, rate=16000) +``` + +Отличная работа 👍 + +## Марвин 🤖 + +Теперь, когда мы определили функцию для каждого из четырех этапов конвейера голосового помощника, осталось только собрать их вместе, +чтобы получить готовый голосовой помощник. Мы просто объединим все четыре этапа, начиная с обнаружения слов активации (`launch_fn`), +транскрипции речи, передачи запроса LLM и заканчивая синтезом речи. + +```python +launch_fn() +transcription = transcribe() +response = query(transcription) +audio = synthesise(response) + +Audio(audio, rate=16000, autoplay=True) +``` + +Попробуйте сделать это с помощью нескольких запросов! Вот несколько примеров для начала: +* Какая самая жаркая страна в мире? +* Как работают модели-трансформеры? +* Знаешь ли ты испанский язык? + +Вот и все, у нас есть готовый голосовой помощник, созданный с использованием 🤗 аудио инструментов, которые вы изучили в этом курсе, с добавлением в конце волшебства LLM. +Есть несколько расширений, которые мы могли бы сделать для улучшения голосового помощника. Во-первых, модель классификации звука классифицирует 35 различных меток. +Мы могли бы использовать более компактную и легкую модель бинарной классификации, которая прогнозирует только то, было ли произнесено слово активации или нет. +Во-вторых, мы заранее загружаем все модели и держим их запущенными на нашем устройстве. Если бы мы хотели сэкономить электроэнергию, то загружали бы каждую модель +только в тот момент, когда она необходима, а затем выгружали бы ее. В-третьих, в нашей функции транскрибации отсутствует модель определения активности голоса, +транскрибация осуществляется в течение фиксированного времени, которое в одних случаях слишком длинное, а в других - слишком короткое. + +## Обобщаем всё 🪄 + +До сих пор мы видели, как можно генерировать речевой вывод с помощью нашего голосового помощника Marvin. +В заключение мы продемонстрируем, как можно обобщить этот речевой вывод на текст, аудио и изображение. + +Для построения нашего помощника мы будем использовать [Transformers Agents](https://huggingface.co/docs/transformers/transformers_agents). Transformers Agents +предоставляет API для работы с естественным языком поверх библиотек 🤗 Transformers и Diffusers, интерпретирует входной сигнал на естественном языке с помощью LLM +с тщательно продуманными подсказками и использует набор курируемых инструментов для обеспечения мультимодального вывода. + +Давайте перейдем к инстанцированию агента. Для агентов-трансформеров существует [три LLM](https://huggingface.co/docs/transformers/transformers_agents#quickstart), две из которых с открытым исходным кодом +и бесплатно доступны на Hugging Face Hub. Третья - модель от OpenAI, требующая ключа OpenAI API. В данном примере мы будем использовать бесплатную модель [Bigcode Starcoder](https://huggingface.co/bigcode/starcoder), +но вы также можете попробовать любую из других доступных LLM: + +```python +from transformers import HfAgent + +agent = HfAgent( + url_endpoint="https://api-inference.huggingface.co/models/bigcode/starcoder" +) +``` + +Чтобы воспользоваться агентом, достаточно вызвать `agent.run` с нашим текстовым приглашением. В качестве примера мы попросим +его сгенерировать изображение кота 🐈 (которое, надеюсь, выглядит немного лучше, чем этот эмоджи): + +```python +agent.run("Generate an image of a cat") +``` + +
+ +
+ + + Обратите внимание, что при первом вызове будет произведена загрузка весов модели, что может занять некоторое время + в зависимости от скорости загрузки. + + +Все просто! Агент интерпретировал наш запрос и, используя [Stable Diffusion](https://huggingface.co/docs/diffusers/using-diffusers/conditional_image_generation) под капотом, +сгенерировал изображение, при этом нам не пришлось беспокоиться о загрузке модели, написании функции или выполнении кода. + +Теперь мы можем заменить функцию передачи запроса LLM и шаг синтеза текста нашим агентом Transformers Agent в голосовом помощнике, +поскольку агент будет выполнять оба этих действия за нас: + +```python +launch_fn() +transcription = transcribe() +agent.run(transcription) +``` + +Попробуйте произнести тот же запрос " Generate an image of a cat" и посмотрите, как справится система. Если задать Агенту простой запрос "вопрос/ответ", он ответит текстовым ответом. +Можно побудить его генерировать мультимодальный вывод, попросив вернуть изображение или речь. Например, вы можете попросить его: "Generate an image of a cat, caption it, and speak the caption". + +Хотя агент является более гибким, чем наш первый итерационный ассистент Marvin 🤖, обобщение задачи голосового помощника таким образом может привести к снижению производительности при выполнении +стандартных запросов к голосовому помощнику. Для восстановления производительности можно попробовать использовать более производительную контрольную точку LLM, например, от OpenAI, или определить +набор [custom tools](https://huggingface.co/docs/transformers/transformers_agents#custom-tools), специфичный для задачи голосового помощника. diff --git a/chapters/ru/translation_agreements.txt b/chapters/ru/translation_agreements.txt index 02756b15..5004e11d 100644 --- a/chapters/ru/translation_agreements.txt +++ b/chapters/ru/translation_agreements.txt @@ -65,10 +65,15 @@ alignment выравнивание beam search лучевой поиск (https://en.wikipedia.org/wiki/Beam_search) Mean opinion score Средняя экспертная оценка image patche фрагмент изображения +Gaussian mixture model Смешанная модель Гаусса +dropout исключение (обязательно с указанием англ. формы - dropout) https://ru.wikipedia.org/wiki/%D0%98%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BD%D0%B5%D0%B9%D1%80%D0%BE%D0%BD%D0%BD%D1%8B%D0%B5_%D1%81%D0%B5%D1%82%D0%B8) +Mean opinion score Средняя экспертная оценка +wake word "слово пробуждения" (слово, благодаря анличию которого голосовой ассистент понимает что обращаются к нему) chank фрагмент (напр. фрагмент аудиообразца) chanking фрагментирование (процесс дробления чего-либо на множество мелких разрозненных фрагментов) + Примечание: * - сокращение или аббревиатура, не переводится. Либо заменяется на соответствующий русскоязычный аналог. Можно найти в википедии сначало английский вариант, затем переключиться в русскоязычную википедию. Так удасться получить общепринятый перевод термина. ** - правильный выбор варианта перевода на основе контекста