音频课程文档

转录会议

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

转录会议

在本节的最后,我们将使用 Whisper 模型为两个或多个发言者之间的对话或会议生成转录。然后,我们将其与“谁何时发言”的说话人分离模型配对。通过将 Whisper 转录中的时间戳与说话人分离模型中的时间戳进行匹配,我们可以预测一个端到端的会议转录,其中包含每个发言者的完整格式化开始/结束时间。这是您可能在 Otter.ai 等网站上看到的会议转录服务的基本版本。

说话人分离

说话人分离(或 diarisation)的任务是获取未标记的音频输入并预测“谁何时发言”。通过这样做,我们可以预测每个说话人轮次的开始/结束时间戳,对应于每个说话人何时开始说话以及何时结束。

🤗 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 要求音频输入是形状为 (channels, seq_len) 的 PyTorch 张量,因此我们需要在运行模型之前执行此转换。

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 中记住,我们需要传递参数 return_timestamps=True 来激活 Whisper 的时间戳预测任务。

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 秒处发生变化。我们现在可以将此转录与从分离模型获得的发言者时间戳配对,以获得最终转录。

语音盒

为了获得最终的转录,我们将对齐分离模型的时间戳和 Whisper 模型的时间戳。分离模型预测第一个说话者在 14.5 秒结束,第二个说话者在 15.4 秒开始,而 Whisper 预测的段边界分别为 13.88、15.48 和 19.44 秒。由于 Whisper 的时间戳与分离模型的时间戳不完全匹配,我们需要找到最接近 14.5 和 15.4 秒的这些边界,并相应地按说话者对转录进行分段。具体来说,我们将通过最小化两者之间的绝对距离来找到分离和转录时间戳之间的最佳对齐。

幸运的是,我们可以使用 🤗 Speechbox 软件包来执行此对齐。首先,让我们从 main 安装 speechbox

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

我们现在可以通过将分离模型和 ASR 模型传递给 ASRDiarizationPipeline 类来实例化我们组合的分离加转录管道。

from speechbox import ASRDiarizationPipeline

pipeline = ASRDiarizationPipeline(
    asr_pipeline=asr_pipeline, diarization_pipeline=diarization_pipeline
)
您还可以通过指定 Hub 上 ASR 模型的模型 ID,直接从预训练模型实例化 ASRDiarizationPipeline

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 秒说话,并附带了各自的转录。

我们可以通过定义两个辅助函数来更好地格式化时间戳。第一个函数将时间戳元组转换为字符串,并四舍五入到指定的小数位数。第二个函数将说话人 ID、时间戳和文本信息组合到一行中,并将每个说话人分割到单独的行中,以便于阅读。

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

< > 在 GitHub 上更新