Audio Course documentation

Транскрибирование встречи

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Транскрибирование встречи

В этом заключительном разделе мы используем модель Whisper для создания транскрипции разговора или встречи между двумя или более говорящими. Затем мы объединим ее с моделью диаризации диктора для прогнозирования “кто когда говорил”. Сопоставив временные метки из транскрипции Whisper с временными метками от модели диаризации, мы можем спрогнозировать сквозную транскрипцию встречи с полностью отформатированным временем начала и окончания для каждого говорящего. Это базовая версия услуг по транскрибированию совещаний, которую вы могли видеть в интернете от таких компаний, как Otter.ai и др:

Диаризация диктора

Диаризация диктора (или диаризация) - это задача получения немаркированных аудиоданных и прогнозирования того, “кто когда говорил”. При этом мы можем прогнозировать временные метки начала/окончания каждой очереди дикторов, соответствующие моменту начала речи и моменту ее окончания.

🤗 В настоящее время в библиотеке Transformers нет модели для диаризации диктора, но на Hub есть контрольные точки, которые можно использовать с относительной легкостью. В этом примере мы будем использовать предварительно обученную модель диаризации диктора из pyannote.audio. Давайте приступим к работе и установим пакет с помощью pip:

pip install --upgrade pyannote.audio

Отлично! Веса для этой модели размещены на Hugging Face Hub. Чтобы получить к ним доступ, сначала нужно согласиться с условиями использования модели диаризации диктора: pyannote/speaker-diarization. А затем - с условиями использования модели сегментации: pyannote/segmentation.

После завершения работы мы можем загрузить предварительно обученный конвейер диаризации дикторов локально на наше устройство:

from pyannote.audio import Pipeline

diarization_pipeline = Pipeline.from_pretrained(
    "pyannote/speaker-diarization@2.1", use_auth_token=True
)

Давайте опробуем его на примере аудиофайла! Для этого мы загрузим образец из датасета LibriSpeech ASR, содержащий речь двух разных дикторов, который мы объединили в один аудиофайл:

from datasets import load_dataset

concatenated_librispeech = load_dataset(
    "sanchit-gandhi/concatenated_librispeech", split="train", streaming=True
)
sample = next(iter(concatenated_librispeech))

Мы можем прослушать аудиозапись, чтобы понять, как она звучит:

from IPython.display import Audio

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

Класс! Мы отчетливо слышим двух разных дикторов с переходом примерно на 15 секунде звучания. Давайте передадим этот аудиофайл в модель диаризации, чтобы получить время начала и окончания разговора. Заметим, что pyannote.audio ожидает, что входной аудиофайл будет представлять собой тензор PyTorch формы (channels, seq_len), поэтому перед запуском модели нам необходимо выполнить это преобразование:

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"]
[{'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, поскольку она достаточно мала, чтобы обеспечить хорошую скорость инференса при приемлемой точности транскрипции. Как и прежде, вы можете использовать любую контрольную точку распознавания речи с Hub, включая Wav2Vec2, MMS ASR или другие контрольные точки Whisper:

from transformers import pipeline

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

Давайте получим транскрипцию для нашего образца аудиозаписи, возвращая также временные метки на уровне сегментов, чтобы знать время начала и окончания каждого сегмента. Из раздела 5 вы помните, что для активации задачи прогнозирования временных меток в Whisper нам необходимо передать аргумент return_timestamps=True:

asr_pipeline(
    sample["audio"].copy(),
    generate_kwargs={"max_new_tokens": 256},
    return_timestamps=True,
)
{
    "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:

pip install git+https://github.com/huggingface/speechbox

Теперь мы можем инстанцировать наш комбинированный конвейер диаризации и транскрипции, передав модель диаризации и модель ASR в класс ASRDiarizationPipeline:

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")

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

pipeline(sample["audio"].copy())
[{'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 секунды, с соответствующими транскрипциями для каждого из них.

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

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
        ]
    )

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

outputs = pipeline(sample["audio"].copy())

format_as_transcription(outputs)
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