lrn-oai-whisper-merge-1

83 阅读1小时+

OpenAI Whisper 学习指南(二)

原文:annas-archive.org/md5/498a61d068550a5ec9498fc70995a63b

译者:飞龙

协议:CC BY-NC-SA 4.0

第五章:在各种环境中应用 Whisper

欢迎来到 第五章,在这里我们探索 OpenAI 的 Whisper 在将口语转化为书面文本方面的卓越能力。在探讨包括转录服务、语音助手、聊天机器人和辅助功能等多个应用时,你将深入了解 Whisper 在这些领域中的关键作用。

首先,我们将探讨转录服务,并研究 Whisper 如何简化音频文件(如会议和采访)的文本转换。它的准确性和效率减少了手动转录的需求,使其成为一项不可或缺的工具。

此外,我们将深入探讨 Whisper 在语音助手和聊天机器人中的集成,提升它们的响应能力和用户互动。通过将语音命令转换为文本,Whisper 将这些技术提升到新的互动水平。

关于辅助功能,本章突出了 Whisper 对听力或语言障碍人士工具的贡献。其 语音转文本 功能不仅提供了实用的解决方案,还丰富了用户体验。

本章将涵盖以下主题:

  • 探索转录服务

  • 将 Whisper 集成到语音助手和聊天机器人中

  • 使用 Whisper 增强辅助功能

本章结束时,你将全面了解如何在各种环境中有效应用 Whisper。你将学习最佳的设置和优化实践,发现创新的使用案例,并理解实施这项技术时的伦理考量。有了这些知识,你将能够充分利用 Whisper 的潜力,在不同领域提升数字体验。

让我们从深入探索通过 Whisper 进行转录的创新世界开始,揭示这项前沿技术如何重塑我们将口语转化为书面文本的方式,提高效率和准确性,适用于各种专业和个人环境。

技术要求

为了利用 OpenAI 的 Whisper 实现高级应用,本章采用 Python 和 Google Colab,以便于使用和提高可访问性。Python 环境设置包括用于转录任务的 Whisper 库。

关键要求:

  • Google Colab 笔记本:这些笔记本设置为使用最低要求的内存和容量运行我们的 Python 代码。如果可用,选择 T4 GPU 运行时类型以获得更好的性能。

  • Python 环境:每个笔记本都包含加载所需 Python 库的指令,包括 Whisper 和 Gradio。

  • Hugging Face 账户:一些笔记本需要 Hugging Face 账户和登录 API 密钥。Colab 笔记本中包含了关于这一主题的信息。

  • 麦克风和扬声器:一些笔记本实现了一个带有语音录制和音频播放功能的 Gradio 应用程序。连接到您计算机的麦克风和扬声器可能有助于您体验互动语音功能。另一种选择是通过 Gradio 在运行时提供的 URL 链接在手机上打开;在该链接中,您可能可以使用手机的麦克风录制您的声音。

  • GitHub 仓库访问:所有 Python 代码,包括示例,均可在本章的 GitHub 仓库中找到(github.com/PacktPublishing/Learn-OpenAI-Whisper/tree/main/Chapter05)。这些 Colab 笔记本可以直接运行,为学习提供了实用的动手实践方式。

通过满足这些技术要求,您将为在不同环境中探索 Whisper 做好准备,同时享受 Google Colab 提供的流畅体验以及 GitHub 上的全面资源。

探索转录服务

从捕捉头脑风暴会议的微妙差异到记录关键访谈,转录服务架起了语言的短暂性与文字的永久性之间的桥梁。在本节中,我们将揭示 Whisper 的先进技术与日益增长的转录需求之间复杂的互动。这一部分为您奠定了基础知识,展示了 Whisper 如何利用其编码器-解码器变换器模型,以卓越的精度应对各种音响环境、口音和方言。然而,它也不回避讨论当前的局限性以及充满活力的社区努力,以推动其进一步发展。

我们还将从理论过渡到实践。从安装依赖项到运行模型,本章将使您掌握将音频文件转化为准确文本转录的知识,确保 Whisper 的表现得到优化,确保转录内容准确无误,并无缝整合到各种应用程序中,从字幕生成到详细内容分析。

本节结束时,您将掌握 Whisper 在转录服务中的重要作用,并具备有效利用其功能的知识。这段旅程是开启数字领域中声音潜力的道路,使信息更易获取,并在各个领域提升沟通效率。

理解 Whisper 在转录服务中的作用

理解 Whisper 在转录服务中的作用,需要深入探索其能力、局限性以及在各类应用中的整合潜力。在这一探索过程中,我们不仅会欣赏 Whisper 的技术实力,还会考虑其在转录领域的实际应用影响。

Whisper 的架构是一个编码器-解码器变压器模型,擅长处理各种音频输入。Whisper 通过将音频转换为 log-Mel 频谱图并按 30 秒的时间段处理,确保每个语音片段都得到关注。这种细致的音频处理方法是 Whisper 在转录中高准确率的原因之一。

Whisper 对口音、背景噪声和技术性语言的强大适应性尤为值得注意。在转录服务中,这些因素通常是影响准确性和可靠性的“祸根”。Whisper 在这些领域的抗干扰能力意味着它能够在多种声学条件下提供高质量的转录,对于需要精确口语内容文档的企业和个人来说具有不可估量的价值。

尽管 Whisper 在转录方面表现出色,但需要注意的是它在讲话者分离(即区分音频文件中的不同说话者)方面的局限性。然而,Whisper 的社区正在积极探索增强其功能的方法,例如将其与其他模型(如Pyannote)结合进行说话人识别。在接下来的章节中,我们将进一步了解讲话者分离和 Pyannote。此外,Whisper 的单词级时间戳功能是一个重要的进步,允许用户将转录文本与音频同步,这对于字幕制作和详细内容分析等应用至关重要。

Pyannote 简介

Pyannote 是一个开源工具包,专为讲话者分离设计,这一过程对于通过识别每个发言的时间和发言者来分析对话至关重要。Pyannote 由 Hervé Bredin 开发,利用 PyTorch 机器学习框架提供可训练的端到端神经组件。这些组件可以组合并联合优化,以构建讲话者分离流水线。pyannote.audio是该工具包的一个组成部分,提供了包括语音活动检测 (VAD)、讲话者分割、重叠语音检测和讲话者嵌入等多个领域的预训练模型和流水线。在大多数这些领域,它都达到了最先进的性能。

在讲话者分离的背景下,Pyannote 与 OpenAI Whisper 的关系是互补的。Pyannote 可以执行讲话者分离任务,识别音频文件中的不同说话者,而 Whisper 可以进行转录。这种协同作用使得创建更详细且有价值的转录成为可能,其中包含了讲话者标签,从而增强了对话分析。然而,整合这两个系统可能比较复杂,且并非总能产生理想的结果,正如一些用户所指出的。

尽管存在这些挑战,将 Pyannote 的讲话者分离能力与 Whisper 的转录能力相结合,代表了语音分析的强大工具,特别是在需要准确识别讲话者的情况下。

从商业角度来看,转录服务的成本是一个关键因素。如果使用 OpenAI 的 API,Whisper 每分钟音频的定价为 0.006 美元,使其成为企业在不承担过高成本的情况下引入转录服务的一个有吸引力的选择。当然,Whisper 也可以通过开源获得。这种价格实惠和高准确性的结合,使 Whisper 成为转录市场中的颠覆性力量。

Whisper API 的文件大小限制为 25 MB,这是开发者在将模型集成到应用程序时需要考虑的因素。尽管这对于较长的音频文件可能带来挑战,但社区已经提出了绕过这一限制的策略,例如拆分音频文件和使用压缩格式。API 的易用性以及实时转录的潜力,进一步增强了 Whisper 作为开发者工具的吸引力。

OpenAI 决定开源 Whisper,催生了创新和定制化的进程。通过提供模型代码和权重的访问权限,OpenAI 使得开发者社区能够调整和扩展 Whisper 的功能。这引领了人工智能的模块化未来,像 Whisper 这样的工具将成为许多应用的基础构件。

展望未来,Whisper 在转录服务中的角色将变得更加重要。随着模型的不断演进以及其周围社区的成长,我们可以预见在说话人分离、语言支持以及其他领域的进展。Whisper 的开源性质确保它将始终处于创新的前沿,由一个协作努力推动,不断完善其转录能力。这为我们接下来的讨论主题奠定了基础:设置 Whisper 用于转录任务,在这里我们将深入探讨如何利用 Whisper 的能力,满足转录需求的实际步骤和注意事项。

设置 Whisper 用于转录任务

设置 Whisper 用于转录任务包括多个步骤,其中包括安装依赖项、安装 Whisper 和运行模型。可以使用书籍 GitHub 仓库中的 LOAIW_ch05_1_setting_up_Whisper_for_transcription.ipynb Google Colab 笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter05/LOAIW_ch05_1_setting_up_Whisper_for_transcription.ipynb) 获取更全面的实践实现。在该笔记本中,我们将逐步讲解从准备环境、下载示例音频到使用 Whisper 进行转录的全过程。下图描述了整体步骤:

图 5.1 – 设置 Whisper 用于转录任务

图 5.1 – 设置 Whisper 用于转录任务

图 5.1 描述了笔记本中的逐步方法,确保你在使用 Whisper 时建立了扎实的基础,从基本设置到探索高级转录技术。我鼓励你从 GitHub 仓库中找到并运行整个笔记本。以下是一些高层步骤和部分代码片段,供你参考:

  1. 安装必要的依赖项:我们首先设置环境并安装关键包:

    !sudo apt install ffmpeg
    !pip install -q cohere openai tiktoken
    ffmpeg is used for audio file manipulation. The cohere and openai Python libraries offer various AI models for tiktoken is required as a supporting library for authentication or token handling in the context of API requests. We also installed the latest Whisper files from the official OpenAI GitHub repository. These steps ensure we have all the tools ready for our transcription tasks.
    
  2. 下载音频样本:接下来,我们从 GitHub 仓库和 OpenAI 的 内容分发网络(CDN)下载多种音频样本,包括英语和西班牙语。这些样本将作为我们的测试用例,帮助我们探索 Whisper 在不同语言中的转录能力。

  3. 验证计算资源:我们检查 GPU 的可用性,以确保高效处理。Whisper 的性能显著受益于 GPU 加速,因此我们配置环境以在 GPU 可用时使用它:

    import numpy as np
    import torch
    torch.cuda.is_available()
    DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
    print(f"Using torch {torch.__version__} ({DEVICE})")
    
  4. "medium" 大小的多语言模型,选择适合我们需求的特定配置:

    import whisper
    model = whisper.load_model("medium", device=DEVICE)
    print(
        f"Model is {'multilingual' if model.is_multilingual else 'English-only'} "
        f"and has {sum(np.prod(p.shape) for p in model.parameters()):,} parameters."
    )
    
  5. 设置自然语言工具包 (NLTK) 进行文本处理:我们安装并配置 NLTK 以增强转录的可读性。NLTK 帮助将转录文本分割,使其更易阅读和理解。

  6. OpenAI 的 whisper.DecodingOptions() 函数用于指定控制解码过程行为的各种选项,当转录音频时使用。DecodingOptions 函数中的参数允许用户指定诸如转录语言、是否包含时间戳,以及是否将 DecodingOptionswhisper.decode() 函数结合使用等选项:

    for audiofile in audiofiles:
        # Load audio and pad/trim it to fit 30 seconds
        audio = whisper.load_audio(audiofile)
        audio = whisper.pad_or_trim(audio)
        # Make log-Mel spectrogram and move to the same device as the model
        mel = whisper.log_mel_spectrogram(audio).to(model.device)
        #Next we detect the language of your audio file
        _, probs = model.detect_language(mel)
        detected_language = max(probs, key=probs.get)
        print(f"----\nDetected language: {detected_language}")
        # Set up the decoding options
        options = whisper.DecodingOptions(language=detected_language, without_timestamps=True, fp16=(DEVICE == "cuda"))
        # Decode the audio and print the recognized text
        result = whisper.decode(model, mel, options)
    

    在这个例子中,DecodingOptions 函数设置了三个选项:

    • language=detected_language:此选项指定转录的语言。如果你提前知道语言并希望依赖其他方式而非模型的自动语言检测,设置语言可以提高转录准确性。

    • without_timestamps=True:当设置为 True 时,表示转录不包括时间戳。如果需要每个单词或句子的时间戳,则应将此选项设置为 False

    • fp16=(DEVICE == "cuda"):此选项决定是否使用 FP16(16 位浮动精度)进行解码。(DEVICE == "cuda") 评估检查 CUDA 是否可用。在笔记本的早期,我们使用 DEVICE = "cuda" if torch.cuda.is_available() else "cpu" 来设置 DEVICE。然后,如果 DEVICE"cuda",则将 fp16 设置为 True,表示计划在 GPU 上运行模型。如果 DEVICE"cpu",则将 fp16 设置为 False,以确保兼容性并避免不必要的警告或错误。

    这些选项可以根据你的转录任务的具体要求进行调整。例如,如果你转录的是另一种语言的音频,你会相应地更改语言选项。如果你需要优化性能,且你的硬件支持,你可以启用 fp16 来使用半精度。FP16(16 位浮动点数)计算在兼容的 GPU 上非常有利,因为它可以显著减少内存使用,并且可能提高计算速度,而不会对模型的准确性造成实质性影响。然而,并非所有 CPU 都支持 FP16 计算,尝试在 CPU 上使用它可能会导致错误或回退到 FP32(单精度浮动点数)计算。

  7. 定义一个简化转录的函数:我们介绍了一个自定义函数来简化转录过程。这个函数简化了处理多个文件的流程,并且我们探索了如何在其中加入翻译选项,从而增强其功能:

    def process_file(audiofile, model, w_options, w_translate=False):
        # Load audio
        audio = whisper.load_audio(audiofile)
        transcribe_options = dict(task="transcribe", **w_options)
        translate_options = dict(task="translate", **w_options)
        transcription = model.transcribe(audiofile, **transcribe_options)["text"]
        if w_translate:
            translation = model.transcribe(audiofile, **translate_options)["text"]
        else:
            translation = "N/A"
        return transcription, translation
    
  8. process_file() 函数来转录非英语音频样本。这个示例展示了 Whisper 在全球范围内对多语言的强大支持,展示了其在全球化环境中的有效性。

    w_options = dict(without_timestamps=True, fp16=(DEVICE == "cuda"))
    audiofile = 'Learn_OAI_Whisper_Spanish_Sample_Audio01.mp3'
    transcription, translation = process_file(audiofile, model, w_options, False)
    print("------\nTranscription of file '" + audiofile + "':")
    for sent in sent_tokenize(transcription):
        print(sent)
    print("------\nTranslation of file '" + audiofile + "':")
    for sent in sent_tokenize(translation):
        print(sent)
    import ipywidgets as widgets
    widgets.Audio.from_file(audiofile, autoplay=False, loop=False)
    
  9. initial_prompt 参数以及调整设置如温度。我们将研究两种方法,通过使用 initial_prompt 来优化转录输出,特别是针对那些拼写模糊或具有专门术语的音频:

    • initial_prompt 参数。在面对一个常见挑战时,这种方法非常有用:准确转录不常见的专有名词,如产品名称、公司名称或个人姓名。这些元素常常会让即便是最先进的转录工具也犯错,导致拼写错误。如果没有 initial_prompt 值的简单转录,结果如下:

      ------
      Transcription of file 'product_names.wav':
      Welcome to Quirk, Quid, Quill, Inc., where finance meets innovation.
      Explore diverse offerings from the P3 Quattro, a unique investment portfolio quadrant to the O3 Omni, a platform for intricate derivative trading strategies.
      Delve into unconventional bond markets with our B3 Bond X and experience non-standard equity trading with E3 Equity.
      Surpass your wealth management with W3 Rap Z and anticipate market trends with the O2 Outlier, our forward-thinking financial forecasting tool.
      Explore venture capital world with U3 Unifund or move your money with the M3 Mover, our sophisticated monetary transfer module.
      At Quirk, Quid, Quill, Inc., we turn complex finance into creative solutions.
      Join us in redefining financial services.
      
    This results in the following:
    
    

    转录文件 'product_names.wav':

    欢迎来到 Quirk Quid Quill Inc.,在这里,金融与创新交汇。

    探索多样化的产品,包括 P3-Quattro,一个独特的投资组合象限,和 O3-Omni,一个复杂衍生品交易策略平台。

    深入探索非常规债券市场,使用我们的 B3-BondX,并体验 E3-Equity 的非标准股票交易。

    超越财富管理,使用 W3-WrapZ,并通过我们的前瞻性金融预测工具 O2-Outlier 预判市场趋势。

    探索风险投资世界,使用 U3-UniFund,或通过我们的 M3-Mover 模块转移资金,这是一个精密的货币转移工具。

    在 Quirk Quid Quill Inc.,我们将复杂的金融问题转化为创造性的解决方案。

    initial_prompt参数非常重要。如果没有initial_prompt,Whisper 会在处理专有名词时遇到困难,导致拼写错误,例如“Quirk, Quid, Quill, Inc.”,“P3 Quattro”,“O3 Omni”,“B3 Bond X”,“E3 Equity”,“W3 Rap Z”,“O2 Outlier”,“U3 Unifund”和“M3 Mover”。然而,在initial_prompt参数中包含正确的拼写后,Whisper 成功地将这些术语转录为“Quirk Quid Quill Inc.”,“P3-Quattro”,“O3-Omni”,“B3-BondX”,“E3-Equity”,“W3-WrapZ”,“O2-Outlier”,“U3-UniFund”和“M3-Mover”。这展示了initial_prompt参数的强大作用,能够引导 Whisper 产生更准确的转录,特别是在处理不常见或复杂术语时。* initial_prompt参数。最有效的方法是创建并提供一个实际的或虚构的提示,以通过确保拼写、风格或术语来引导 Whisper。为了说明第二种方法,我们将转向为本练习专门制作的另一个音频片段。场景是一次不同寻常的烧烤活动。我们的第一步是使用 Whisper 生成一个基准转录,以评估其初步准确性。没有initial_prompt值的简单转录结果如下:

    ```py
    ------
    Transcription of file 'bbq_plans.wav':
    Hello, my name is Preston Tuggle.
    I am based in New York City.
    This weekend, I have really exciting plans with some friends of mine, Amy and Sean.
    We're going to a barbecue here in Brooklyn.
    Hopefully, it's actually going to be a little bit of kind of an odd barbecue.
    We're going to have donuts, omelets.
    It's kind of like a breakfast as well as whiskey.
    So that should be fun.
    And I'm really looking forward to spending time with my friends, Amy and Sean.
    ```
    
    This results in the following:
    
    

    文件'bqq_plans.wav'的转录:

    你好,我叫普雷斯顿·塔格尔。

    我住在纽约市。

    这个周末我有一些非常令人兴奋的计划,要和我的朋友 Aimee 和 Shawn 一起度过。

    我们要去布鲁克林的烧烤聚会。

    希望这实际上会是一场有点奇怪的烧烤聚会。

    我们要吃甜甜圈,煎蛋卷。

    它有点像早餐,也像威士忌。

    所以那应该会很有趣。

    在提供虚构的提示后,initial_prompt和第二次输出,我们得到了更精确的结果(例如,“Aimee 和 Shawn”而不是“Amy 和 Sean”,“doughnuts”而不是“donuts”,“BBQ”而不是“barbeque”,“whisky”而不是“whiskey”)。

当你在笔记本中运行单元时,每个部分都会在前一个部分的基础上构建,逐步介绍使用 Whisper 的更复杂功能和技术。这种结构化的方式有助于为转录任务设置 Whisper,并探索提高转录准确度的策略,以适应各种音频内容。

理解 Whisper 的initial_prompt的超能力和局限性

OpenAI 的 Whisper 中的initial_prompt参数是一个可选的文本提示,用于在转录第一个音频窗口时为模型提供上下文。以下是关于initial_prompt需要理解的关键内容:

initial_prompt用于在模型开始转录音频之前,为其提供相关的上下文。这有助于提高转录的准确性,特别是在涉及专业词汇或特定写作风格时。

initial_prompt 只影响正在转录的音频的第一个片段。对于较长的音频文件,如果被拆分成多个片段,那么在音频的前 30-90 秒之后,它的影响可能会减弱。对于较短的音频,手动分割或拆分音频并应用 initial_prompt 参数是一种克服这一限制的选择。对于较大的脚本,分割过程可以自动化。也可以选择进行一些后处理调整,包括将整个转录本传递给一个更复杂提示的 LLM。

initial_prompt。文档中似乎对使用前 224 个令牌还是后 224 个令牌存在不一致的描述,但无论哪种情况,超出该限制的部分都会被忽略。

initial_prompt 不一定要是一个实际的转录文本。可以创建虚构的提示来引导 Whisper,使用准确的拼写、风格或术语等。包括拼写指南或通过 GPT-3 生成提示等技术都可以有效地发挥作用。

initial_prompt 参数不同于 prompt 参数,后者为当前片段提供之前转录片段的上下文,有助于在较长的音频文件中保持一致性。

initial_prompt 参数是一种将相关上下文提前提供给 Whisper 以提高转录准确性的方法。然而,它的影响仅限于音频的开始部分,并且受限于令牌数量。因此,它是一个有用但有限的工具,用于提升 Whisper 在特定音频内容上的表现。

现在,让我们深入了解转录技巧,以更全面地理解 Whisper 中可用的选项。应用这些技巧,你将能够为各种音频处理任务做好充分准备,从简单的转录到更复杂的多语言项目。

使用 Whisper 高效转录音频文件

在深入探讨相关参数之前,先来考虑一下模型大小的选择:tiny、base、small、medium 或 large。这个选择直接影响转录速度和准确性之间的平衡。例如,尽管 medium 模型提供了更快的转录速度,但 large 模型在准确性方面表现出色,因此在需要精度的应用中,它是首选。随着模型大小的增加,其准确性也随之提升,使得 large 模型成为精度的巅峰。large 模型是文献中报告准确性的基准(《心理健康研究中的高效和准确转录——使用 Whisper AI 进行音频文件转录的教程——2023 年 11 月 10 日——osf.io/preprints/osf/9fue8),这也凸显了它在需要高精度任务中的重要性。

我的实际经验强调了选择适当的模型大小和计算资源的必要性。特别是在运行 Whisper 时,尤其是其更大的变体,需要 GPU 加速以显著减少转录时间。例如,测试表明使用 GPU 可以显著缩短转录一分钟音频所需的时间。此外,在选择模型大小时,考虑速度和准确性之间的权衡是至关重要的。例如,虽然中等模型的速度是大模型的两倍,但大模型提供了更高的准确性。

选择优化转录的关键推理参数

配置 OpenAI 的 Whisper 中的推理参数和解码选项对于实现准确的转录至关重要,因为这些设置可以显著影响转录过程的性能和精度。这种探索增强了转录的准确性并优化了性能,充分发挥了 Whisper 的能力。根据我的经验,参数如 temperaturebeam_sizebest_of 在微调 Whisper 的转录能力中显得至关重要。

  • temperature 参数控制生成文本中的变化水平,这可以导致更准确的转录。

  • beam_size 参数在解码中至关重要,影响潜在转录的搜索广度。较大的 beam_size 值可以通过考虑更全面的可能性来提高转录准确性。

  • 同样,best_of 允许我们控制解码过程的多样性,从多次尝试中选择最佳结果。这在实现转录的最高可能准确性方面特别有用。

理解 temperaturebeam_sizebest_of 推理参数之间的关系

Whisper 模型中的 beam_size 参数指的是在解码过程中使用的束搜索中的束数量。束搜索是一种启发式搜索算法,通过扩展有限集中最有前途的节点来探索图。在 Whisper 的背景下,束搜索用于在给定音频输入时找到最可能的单词序列。

temperature 参数控制抽样过程中输出的随机性。较高的温度会产生更随机的输出,而较低的温度会使模型的输出更为确定性。当温度设置为零时,模型采用贪婪解码策略,总是选择最可能的下一个词。

beam_sizetemperature 影响解码策略以及生成文本的多样性。较大的 beam_size 值可以通过考虑更多的替代单词序列来提高转录的准确性,但它也需要更多的计算资源,并可能导致推理过程变慢。另一方面,temperature 影响输出的可变性;非零温度允许从可能的后续单词分布中进行采样,这可以引入可变性并潜在地捕捉到语音中的更多细微差别。

在实践中,当温度设置为零时,使用 beam_size 参数,表示应该使用束搜索。如果温度非零,则使用 best_of 参数来确定要从中采样的候选项数量。Whisper 模型使用动态温度设置,初始温度为 0,在满足特定条件时(例如生成的标记的平均对数概率低于阈值,或生成的文本的 gzip 压缩率高于特定值),会将温度提高 0.2,直到达到 1.0

总结来说,beam_size 控制了束搜索解码中的搜索范围,而 --temperature 控制了采样过程中输出的随机性。它们是解码策略的一部分,影响最终由 Whisper 模型生成的转录或翻译结果。

在 Whisper 中配置参数和解码选项是一个微妙的过程,需要深入理解模型及其功能。通过仔细调整这些设置,用户可以优化转录的准确性和性能,使 Whisper 成为一个适用于广泛应用的强大工具。与任何 AI 模型一样,必须在特定使用场景下彻底测试和验证结果,确保它们满足要求。以下部分将更深入地介绍一个专门设计的实践笔记本,旨在展示 Whisper 解码过程中运行时参数的强大功能。

在实践中应用 Whisper 的运行时参数

本节将探索 LOAIW_ch05_2_transcribing_and_translating_with_Whisper.ipynb Colab 笔记本(github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter05/LOAIW_ch05_2_transcribing_and_translating_with_Whisper.ipynb)以进行更全面的实践操作。我鼓励你在本书的 GitHub 仓库中找到该笔记本,并在 Google Colab 中运行。该笔记本旨在展示如何在 Python 环境中安装和使用 Whisper,展示其处理多语言 ASR 和翻译任务的能力。具体而言,它利用 FLEURS 数据集展示了 Whisper 在处理多语言音频数据方面的高效性。FLEURS 代表 少量学习评估通用语音表示,这是一个用于评估通用语音表示在少量学习场景中的性能的基准,少量学习指的是模型能够在仅有少量数据的情况下学习或适应新任务或新语言。这对于那些没有大量数据集可供训练模型的语言尤其重要。以下图示展示了笔记本的高级结构:

图 5.2 – 使用 Whisper 进行转录和翻译

图 5.2 – 使用 Whisper 进行转录和翻译

图 5.2所示,笔记本还集成了一个交互式 Gradio 界面,供用户进行 Whisper 转录和翻译功能的实地实验,使用选定的音频样本。以下是一些高级步骤和代码片段,展示了相关操作:

  1. librosagradiokaleido。这些库能够显著增强基于 Whisper 的项目的功能和应用。librosa 可以预处理音频文件以满足 Whisper 的要求,gradio 可以创建交互式演示以展示 Whisper 的功能,而 kaleido 则可以生成可视化内容以补充音频处理任务。它们共同为即将进行的任务准备了 Python 环境,解决了潜在的兼容性问题,并设置了计算设备:

    !pip install -q cohere openai tiktoken
    !pip install -q librosa
    !pip install git+https://github.com/openai/whisper.git
    Fleurs(torch.utils.data.Dataset) custom class is implemented to download, extract, and preprocess audio files from the selected language dataset, preparing the dataset for processing with Whisper. We extract 5% of the dataset for the selected language using that class. Notice that we are removing only a few records from the FLEURS dataset for a given language. For example, if we choose the Korean language as the dataset, we must download about 840 records. Thus, downloading just 5% (77 records) is more manageable and runs the demo code faster. Feel free to experiment with other percentage values:
    
    

    dataset = Fleurs(lang, subsample_rate=5)

  2. temperaturebeam_sizebest_of 推理参数:

    options = dict(language=language, beam_size=5, best_of=5, temperature=0)
    transcribe_options = dict(task="transcribe", **options)
    translate_options = dict(task="translate", **options)
    
  3. 启动与 Gradio 的交互式探索:一个交互式 Gradio 界面允许用户选择音频样本,调整推理参数,并查看 ASR 和翻译结果,同时显示原始音频。本节旨在提供实时体验,通过更改推理参数并观察转录结果。

  4. 探索用于单词级时间戳的高级技术:本节展示了如何通过 Whisper 的交叉注意力权重,从音频转录中提取单词级时间戳。这涉及到动态时间规整、注意力权重处理和可视化技术,将转录中的单词与音频录音中的特定时间对齐,适用于字幕生成和详细音频分析等应用。

本 Colab 笔记本是一个结构良好的指南,介绍了 Whisper 及其多语言功能,并提供了关于模型推理参数的实践操作经验。它涵盖了从数据准备到模型推理和结果可视化的整个工作流程,为任何对语音处理和机器学习感兴趣的人提供了宝贵的见解。这种全面的方法确保你能掌握使用现有最先进的自动语音识别(ASR)和翻译模型之一的复杂性,为语音技术的进一步探索和应用开发铺平道路。

在确立了 Whisper 在转录音频文件方面的高效性后,我们现在将重点放在下一个前沿:将这一先进的语音识别技术集成到语音助手和聊天机器人中。这一整合有望彻底改变我们与人工智能的互动,提供无缝且直观的沟通,能够准确理解并响应我们的口头请求。让我们探索如何利用 Whisper 的功能来提升这些交互式应用中的用户体验。

将 Whisper 集成到语音助手和聊天机器人中

将 Whisper 的先进语音识别功能融入语音助手和聊天机器人中,可以显著提升用户体验。这涉及到理解口语,并用更高的准确性和上下文意识进行解释。目标是创造能够听懂和理解的系统,使互动更加自然和类人化。

在这一部分,我们将通过实践的方式学习和理解 Whisper 如何补充和增强现有结构。这一整合并不是要替代现有系统,而是通过 Whisper 强大的功能对其进行增强。它涉及到对 Whisper 与助手或聊天机器人之间互动的微调,以确保无缝的沟通。这种协同作用对于释放语音技术的全部潜力至关重要。

优化 Whisper 以提高效率和用户体验对这一整合至关重要。效率不仅仅是速度,还包括回应的准确性和相关性。Whisper 准确地转录和理解各种口音、方言和语言的能力,是其实用性的基石。此外,当技术能够处理自发的、日常的语言交流时,用户体验会大大增强,使互动更加生动、自然,而不那么机械化。因此,重点是创建技术熟练和以用户为中心的设计之间的和谐平衡。

Whisper 在转录服务中的角色是多方面且重要的。其技术的复杂性、对复杂音频条件的鲁棒性以及成本效益,使其成为企业和开发者的重要工具。所以,让我们深入了解一下!

认识到 Whisper 在语音助手和聊天机器人中的潜力

在我们这个数字化驱动的时代,智能个人助手IPAs)如 Siri、Google Assistant 和 Alexa,已经无处不在,帮助完成购物、播放音乐和管理日程等任务。语音助手和聊天机器人,作为数字互动的重要组成部分,正在迅速发展。尽管它们的架构根据使用场景和需求有所不同,但它们的潜力巨大,尤其是在引入像 Whisper 这样的技术时。

聊天机器人和语音助手正日益成为我们数字互动的重要组成部分,提供客户支持、虚拟助手等服务。虽然根据具体的使用场景和需求有所不同,但它们的架构通常遵循类似的结构。

向着更复杂的聊天机器人发展

聊天机器人可以大致分为两类:基于规则的和基于 AI 的。基于规则的聊天机器人根据预定义的规则和模式进行操作,通过简单的真/假算法提供回应。而基于 AI 的聊天机器人则利用机器学习和自然语言处理(NLP)来理解和回应用户查询。一个典型的聊天机器人架构由几个关键组件组成:

  • 自然语言理解引擎(NLU):这个组件解析用户输入,利用机器学习和 NLP 理解信息的上下文和意图。

  • 知识库:这是聊天机器人用来回应的一个信息库。它可以包括常见问题、关于公司产品或服务的信息以及其他相关数据。

  • 数据存储:聊天机器人存储对话历史和分析数据。

  • 问答系统:该系统回答客户的常见问题。问题由问答系统进行解析,随后从知识库中提供合适的回答。

在数字通信中弥合语音助手的空白

语音助手,如亚马逊 Alexa 或 Google Assistant,具有稍微不同的架构。语音助手的一般流程从客户端设备的麦克风录制用户的原始音频开始。然后使用语音活动检测(VAD)系统处理这些音频,将其分离成短语。这些短语被转录成文本,并发送到服务器进行进一步处理。语音助手的架构通常分为两个主要组件:

  • 客户端-服务器:客户端处理音频信息并将其转换为文本短语。然后将信息发送到服务器进行进一步处理。

  • 技能:这些独立应用程序在客户端处理的文本/音频上运行。它们处理信息并返回结果。在像亚马逊 Alexa 或 Google Assistant 这样的语音助手的上下文中,技能指的是扩展语音助手平台功能的第三方应用程序。这些技能由第三方创作者使用亚马逊提供的 Alexa 技能套件(www.amazon.science/blog/the-scalable-neural-architecture-behind-alexas-ability-to-select-skills)开发。它们使语音助手能够执行广泛的功能,超越内置特性,如玩游戏、提供新闻更新、控制智能家居设备等。语音助手的架构允许这些技能与用户的语音命令互动,并提供量身定制的响应或服务。

目前,智能个人助理(IPA)缺乏互操作性,尤其是在交换用户行为学习方面。IPA 的架构高度定制化,以适应商业操作和客户需求的可用性和上下文。这一局限性突显了 IPA 架构标准化的必要性,尤其是以语音为主要交互方式。然而,这一概念不仅限于语音,还包括基于文本的聊天机器人和多模态交互。例如,在多模态场景中,组件可能包括语音识别、自然语言处理(NLP)甚至环境动作执行,如控制工业机械。

随着人工智能和机器学习技术的不断发展,特别是像 OpenAI 的 Whisper 这样的进展,我们预期将出现更加复杂、具有上下文感知能力的聊天机器人和语音助手。这些进展有望提升用户体验和数字互动的可能性。这一演变对企业和组织中的专业虚拟助手至关重要,因为它要求与通用助手进行互操作,以避免重复实现。Whisper 在这个领域的潜力体现在其先进的语音处理能力上,树立了智能个人助理(IPA)的新标准,并革新了用户与数字平台的互动方式。

当我们将注意力转向下一个部分时,理解为何我们专门讨论聊天机器人,而不涉及语音助手领域,显得尤为重要。这一战略决策与 OpenAI 开发 ChatGPT 的方法一致,ChatGPT 代表了 AI 聊天机器人技术的一个里程碑。ChatGPT 的设计理念和实现方式为如何将先进技术如 Whisper 集成到聊天机器人架构中提供了关键的见解。以下部分将探讨 Whisper 如何无缝地融入现有的聊天机器人框架,增强其功能和智能。

将 Whisper 集成到聊天机器人架构中

在本节中,我们将踏上探索 OpenAI Whisper 在聊天机器人架构中的实际应用之旅。聊天机器人架构指的是聊天机器人系统的基本结构和设计。它包括使聊天机器人能够理解用户输入、提供准确回应并提供无缝对话体验的组件和流程。聊天机器人的架构对于其有效性至关重要,并由具体的使用案例、用户互动、集成需求、可扩展性要求、可用资源以及预算限制等因素决定。

Whisper 的架构旨在将口语语言转换为文本,这一过程被称为转录。这个能力对于基于语音的聊天机器人至关重要,因为聊天机器人必须理解并响应口头的用户输入。

为 Whisper 选择合适的聊天机器人架构

选择 Whisper 聊天机器人架构时需要考虑具体的使用案例和需求。架构应能够处理聊天机器人将执行的任务、目标受众和所需功能。例如,如果聊天机器人用于回答常见问题,那么架构可能会包含一个问答系统,用于解读问题并从知识库中提供适当的回应。

通过调整其神经网络架构,Whisper 模型可以针对特定的使用场景进行优化。例如,一家聊天机器人开发公司可能会使用 Whisper 来构建实时转录服务。相反,一家拥有智能助手和物联网设备的公司可能会将 Whisper 与语言模型结合,以处理转录后的语音并根据用户命令执行任务。

将 Whisper 聊天机器人架构应用于行业中的使用案例

Whisper 的聊天机器人架构可以应用于各种消费者、商业和工业领域的使用案例。例如,使用 Whisper 的聊天机器人可以通过语音理解客户查询,并生成详细的、具备上下文意识的书面或口头回应,用于客户服务。这可以通过提供快速、准确且个性化的回应来增强客户体验。

在商业领域,Whisper 可以自动化诸如会议记录、访谈转录、以及将讲座和播客转换为文本以便进行分析和记录的任务。自动化日常任务并方便获取信息可以提升效率和生产力。

Whisper 可以在工业领域的智能助手和物联网设备中集成,提供更自然、高效和准确的语音交互。例如,智能助手可以处理转录后的语音,执行任务、回答问题或根据用户命令控制智能设备。

实现基于 Whisper 的聊天机器人需要将 Whisper API 集成到您的应用程序中,这可以通过 Python 实现。Whisper API 是 open/open-python 的一部分,允许您访问各种 OpenAI 服务和模型。实现过程还涉及定义使用场景、选择合适的聊天机器人架构以及设置用户界面。

作为起点,让我们通过一个实际的编码示例来了解如何构建一个基本的语音助手,使用 Whisper 进行演示。我们将深入探讨的完整编码示例可以在我们的 GitHub 仓库中找到,格式为 LOAIW_ch05_3_Whisper_and_Stable_LM_Zephyr_3B_voice_assistant_GPU.ipynb Colab 笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter05/LOAIW_ch05_3_Whisper_and_Stable_LM_Zephyr_3B_voice_assistant_GPU.ipynb)。

下图提供了一个高层次的逐步说明,展示了笔记本如何设置一个简单的语音助手,利用 Whisper 的能力:

图 5.3 – 使用 Whisper 创建语音助手

图 5.3 – 使用 Whisper 创建语音助手

图 5.3 展示了加载 Whisper 模型、将音频输入转录为文本并使用 StableLM Zephyr 3B – GGUF 生成响应的步骤。StableLM Zephyr 3B – GGUF 是一个拥有 30 亿参数的量化 GGUFv2 模型,继 Stability AI 的 StableLM Zephyr 3B 后开发。该模型文件与 llama.cpp 兼容。随后,使用 Google 文本转语音 (gTTS) 服务将响应转换为语音,实现完整的语音对话交互。

介绍 StableLM Zephyr 3B – GGUF

StableLM Zephyr 3B – GGUF 是由 Stability AI 开发的语言模型。以下是一些关于该模型的详细信息:

模型描述:StableLM Zephyr 3B 是一个拥有 30 亿参数的指令调优模型,灵感来自 Hugging Face 的 Zephyr 7B 训练管道。它使用 直接偏好优化 (DPO) 在公开可用和合成数据集的混合上进行了训练。该模型的评估基于 MT Bench 和 Alpaca Benchmark。

目的和能力:StableLM Zephyr 3B 高效地满足各种文本生成需求,从简单查询到复杂的指导性文本。它可用于多种任务,包括自然语言理解(NLU)、文本补全等。

Meta 的llama.cpp团队。GGUF 代表“Georgi Gervanov 的统一格式”,是 GGML 的替代品,GGML 是一个专注于机器学习的 C 语言库。GGUF 被各种客户端和库支持,包括llama.cpptext-generation-webuikoboldcppgpt4all等。

量化级别:模型文件有不同的量化级别:

Q5_0:遗留版;中等,平衡质量。

Q5_K_S:大,低质量损失(推荐)。

Q5_K_M:大,低质量损失(推荐)。

从 2023 年 8 月 27 日起,llama.cpp以及许多第三方 UI 和库。

本节不仅仅是理解代码,更重要的是欣赏将 Whisper 集成到聊天机器人架构中的潜力。它让我们设想,这项技术如何革新我们与聊天机器人互动的方式,使这些互动更加自然和直观。它让我们认识到语音启用的聊天机器人在各种应用中的潜力,从客户服务到个人助手,乃至更广泛的领域。

当我们深入探讨编码示例的细节时,请记住我们的目标是理解技术的更广泛影响。Whisper 集成到聊天机器人架构中如何提升我们的 AI 解决方案?它如何在市场上提供竞争优势?这些是我们在本节中应考虑的问题。

我鼓励你打开 Colab Notebook 并跟着一起操作。这里是一些高层次步骤,并附有部分代码片段供参考:

  1. 对于stablelm-zephyr-3b-GGUF stablelm-zephyr-3b.Q5_K_S.gguf模型,我们需要安装并编译llama-cpp-python包,同时安装whispergradiogTTS。为了利用 NVIDIA CUDA 加速,我们必须先设置CMAKE_ARGS="-DLLAMA_CUBLAS=on"环境变量:

    import os
    os.environ["CMAKE_ARGS"] = "-DLLAMA_CUBLAS=on"
    print(os.getenv("CMAKE_ARGS"))
    !pip install llama-cpp-python==0.2.34
    !huggingface-cli download TheBloke/stablelm-zephyr-3b-GGUF stablelm-zephyr-3b.Q5_K_S.gguf --local-dir . --local-dir-use-symlinks False
    !pip install -q git+https://github.com/openai/whisper.git
    !pip install -q gradio
    !pip install -q gTTS
    !ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono -t 10 -q:a 9 -acodec libmp3lame Temp.
    
  2. 初始化 Python 库:我们现在导入必要的库,并设置一个日志记录器,用于记录在 Notebook 执行期间的事件和输出:

    import datetime
    import os
    from rich.console import Console
    console = Console(width=110)
    ## Logger file
    tstamp = datetime.datetime.now()
    tstamp = str(tstamp).replace(' ','_')
    logfile = f'{tstamp}_log.txt'
    def writehistory(text):
        with open(logfile, 'a', encoding='utf-8') as f:
            f.write(text)
            f.write('\n')
        f.close()
    
  3. llama.cpp,如果有 GPU 可用,则进行配置。它指定了诸如最大序列长度、CPU 线程数和要卸载到 GPU 的层数等参数:

    warnings.filterwarnings("ignore")
    with console.status("Loading...",spinner="dots12"):
      llm_gpu = Llama(
        model_path="/content/stablelm-zephyr-3b.Q5_K_S.gguf",  # Download the model file first
        n_ctx=4096,  # The max sequence length to use - note that longer sequence lengths require much more resources
        n_threads=8,            # The number of CPU threads to use, tailor to your system, and the resulting performance
        n_gpu_layers=35         # The number of layers to offload to GPU if you have GPU acceleration available
    )
    
  4. 探索推理示例:一个简单的示例演示了如何根据文本提示从 StableLM Zephyr 3B 模型生成响应:

    prompt="In a short response, what is the capital of France?"
    template = f"<|user|>\n{prompt}<|endoftext|>\n<|assistant|>"
    start = datetime.datetime.now()
    output = llm_gpu(
        template, # Prompt
        temperature=0,
        max_tokens=512,  # Generate up to 512 tokens
        stop=["</s>"],   # Example stop token - not necessarily correct for this specific model! Please check before using.
        echo=False        # Whether to echo the prompt
    )
    console.print(output['choices'][0]['text'])
    
  5. 定义 LLM 的支持函数:在这里,我们创建并测试一个与 StableLM 模型交互的函数:

    import re
    def llm_call(input_text):
        prompt = """Act as Tatianna, a junior-level assistant characterized by your cheerful demeanor and unwavering helpfulness. \
        You are in a business setting; thus, always act professionally and courteously. \
        Respond succinctly to the following instructions and questions, and do not include information about yourself unless it is part of the action or question: \
        """ + input_text
        template = f"<|user|>\n{prompt}<|endoftext|>\n<|assistant|>"
        response = llm_gpu(
            template, # Prompt
            temperature=0.1,
            max_tokens=200,  # Generate up to 512 tokens
            stop=["</s>"],   # Example stop token - not necessarily correct for this specific model! Please check before using.
            echo=False        # Whether to echo the prompt
        )
        if response is not None:
            match = re.search(r':\s*(.*)', response['choices'][0]['text'])
            if match:
                reply = match.group(1).strip()
            reply = response['choices'][0]['text']
        else:
            reply = "No response generated."
        return reply
    
  6. transcribe(audio) 函数是语音助手系统的关键组件。它无缝集成了 Whisper 的转录能力与 StableLM Zephyr 3B 模型和 gTTS,能够让语音助手以自然、对话的方式理解并回应用户的查询:

    import whisper
    model = whisper.load_model("medium", device=DEVICE)
    def transcribe(audio):
        if audio is None or audio == '':
            return ('','',None)  # Return empty strings and None audio file
        language = 'en'
        audio = whisper.load_audio(audio)
        audio = whisper.pad_or_trim(audio)
        mel = whisper.log_mel_spectrogram(audio).to(model.device)
        _, probs = model.detect_language(mel)
        options = whisper.DecodingOptions()
        result = whisper.decode(model, mel, options)
        result_text = result.text
        out_result = llm_call(result_text)
        audioobj = gTTS(text = out_result,
                        lang = language,
                        slow = False)
        audioobj.save("Temp.mp3")
        return [result_text, out_result, "Temp.mp3"]
    
  7. 创建用户界面:这段 Python 代码使用 Gradio 库创建了一个用户界面,允许用户与语音助手系统进行交互。该界面包括一个麦克风输入用于捕捉音频,两个文本框分别显示转录的文本和生成的响应,以及一个音频播放器播放语音响应:

    gr.Interface(
        title = 'Learn OpenAI Whisper: Voice Assistance',
        fn=transcribe,
        inputs = gr.Audio(sources=["microphone"], type="filepath"),
        outputs=[
            gr.Textbox(label="Speech to Text"),
            gr.Textbox(label="ChatGPT Output"),
            gr.Audio("Temp.mp3")
        ],
        live=True).launch(debug=True)
    

    这个单元使用 Gradio 创建了一个用户界面。界面包括一个麦克风输入用于接收用户的声音,一个文本框显示转录的文本,一个文本框显示 GPT-3 模型的响应,以及一个音频播放器播放模型的音频响应:

图 5.4 – Whisper 语音助手

图 5.4 – Whisper 语音助手

Python 代码审查展示了如何将 OpenAI 的 Whisper 集成到聊天机器人架构中。我们学习了如何安装和导入必要的库,设置 OpenAI API 身份验证的环境变量,加载 Whisper 模型,并创建用于交互的用户界面。我们还看到如何定义与免费模型交互的函数,例如 Stability AI 的 StableLM Zephyr 3B,Google 的 gTTS,以及如何使用 Whisper 将音频输入转录为文本。这种动手实践让我们对如何利用 Whisper 构建语音助手有了实际的理解,展示了它在增强聊天机器人架构中的潜力。

在接下来的部分,我们将深入探讨 为聊天机器人效率和用户体验量化 Whisper,我们将探索如何微调 Whisper 在聊天机器人中的集成,以提升其性能,使用户体验更加流畅和有趣。我们将关注优化转录过程、处理不同语言和口音,以及提升聊天机器人响应速度的技术。所以,让我们继续前行,发现如何释放 Whisper 在创建高效且用户友好的聊天机器人系统中的全部潜力。

为了提高聊天机器人的效率和用户体验,对 Whisper 进行量化

对效率和性能优化的追求是一个持续的努力。近年来,量化模型技术在 ASR(自动语音识别)系统中,特别是在 OpenAI 的 Whisper 中,得到了广泛关注。

量化是一系列旨在减少模型大小和预测延迟的技术,主要通过降低模型权重的精度来实现。例如,这可能涉及将精度从 16 位小数点降至 8 位小数点,或将浮点数转换为整数表示。这一过程可以显著减少内存需求,从而实现高效的部署在边缘设备和嵌入式平台上,支持实时应用。

对 Whisper 进行量化可以带来多个好处,特别是在聊天机器人和语音助手的应用中:

  • 性能提升:量化可以显著加速 Whisper 模型的推理时间,特别是在基于 CPU 的部署中。这对于计算资源有限的应用非常有益,比如笔记本电脑或移动设备。例如,将 PyTorch 中包含的简单后训练动态量化过程应用于 OpenAI Whisper,可以为基于 CPU 的部署提供最多 3 倍的加速。

  • 模型尺寸缩减:量化还可以减少模型的大小,使其存储和传输更加高效。这对于在存储容量有限的边缘设备上部署模型尤为有用。

  • 保持准确性:根据经验结果,较小模型的准确性在量化后保持不变,甚至略有提高。然而,最大的模型的准确性可能会略微降低。

然而,值得注意的是,量化的好处可能会根据具体的模型和部署的硬件有所不同。因此,在您的特定环境中,必须仔细评估量化的影响。下一章将更详细地探讨 Whisper 的量化,并结合实际编程示范。

在探讨了 Whisper 在聊天机器人和语音助手中的应用后,我们现在将注意力转向另一个至关重要的应用领域。接下来的部分将深入探讨 Whisper 如何增强辅助功能,从识别 Whisper 在辅助工具中的需求开始,并评估其对用户体验的影响。

使用 Whisper 增强辅助功能

在前面的章节中,我们探讨了 Whisper 如何用于转录服务,并与语音助手和聊天机器人相结合。现在,我们将关注这种技术的另一种同样重要的应用:增强辅助功能。

第一小节将深入探讨当前辅助工具的现状,并识别 Whisper 能够填补的空白。为什么在这个领域需要 Whisper?它带来了哪些独特的能力,能够增强现有工具的功能?这些问题是我们将要探讨的内容,旨在全面了解 Whisper 在该领域的必要性和潜力。

接下来,我们将评估 Whisper 对用户体验的实际影响。Whisper 在辅助工具中的集成如何影响最终用户?能观察到哪些改进?这些改进对依赖这些工具的个人有哪些意义?本节将提供详细的评估,深入分析 Whisper 集成的实际影响。

当我们展开这次探索时,重要的是要记住,我们的旅程不仅仅是理解 Whisper 的技术方面。更重要的是认识到它的变革性潜力,以及它如何改善听力或语言障碍者的生活。

那么,你准备好深入探索 Whisper 及其在提升可访问性方面的潜力了吗?让我们开始这段令人兴奋的探索之旅,记住——理解的过程与最终的目标同样重要。

识别在辅助工具中需要 Whisper 的地方

随着世界数字化连接的加深,对更具包容性和可访问性技术的需求也在增加。对于听力或语言障碍的人群,与数字设备的互动可能是一个挑战。传统的输入方式,如打字或触控,可能对这些用户来说更加可行和高效。这正是 Whisper 发挥作用的地方。

Whisper 的 ASR 技术可以将口语转录为书面文本,使听力障碍者能够更轻松地访问数字内容。它还可以将书面命令转化为行动,为语言障碍者提供一种替代输入方式。通过将 Whisper 集成到辅助工具中,我们可以改善这些用户的体验,使数字设备变得更加包容和易于使用。

利用 Whisper 的独特能力

Whisper 提供了几个独特的功能,可以增强现有工具的功能。Whisper 的一个关键优势是其卓越的准确性。在与多种语音识别系统的测试中,Whisper 展现了令人印象深刻的准确率。这种高准确度可以显著提高转录服务的可靠性,使其对听力障碍者更加有用。

Whisper 还能够理解和转录多种语言。这种多语言能力可以使数字内容对更广泛的用户更具可访问性,打破语言障碍,促进更加高效和包容的沟通。

Whisper 的另一个独特特点是其开源性质。OpenAI 已将 Whisper 提供给公众使用,鼓励开发者将其集成到各种应用中,并探索新的可能性。这种开源方法促进了创新,并使技术得以不断改进,扩大了 Whisper 的影响力和覆盖范围。

使用 Whisper 增强现有的辅助工具

Whisper 的功能可以用于提升现有辅助工具的功能。例如,Whisper 可以集成到转录服务中,以提供更准确和可靠的转录结果。这将改善听力障碍者对音频内容的可访问性,使他们更容易理解和参与这些内容。

Whisper 还可以集成到语音助手和聊天机器人中,提升其功能。通过将口语命令转录为书面文本,Whisper 可以使这些工具更具互动性和用户友好性,特别是对于有语言障碍的用户。

此外,Whisper 的多语言能力可以用于增强语言学习工具。通过几乎实时地转录和翻译口语,Whisper 可以为学习者提供即时反馈,帮助他们更有效地提高语言技能。

Whisper 融入辅助工具的整合仅仅是个开始。随着 Whisper 的持续发展,我们期待在用户体验方面看到更多的改进。例如,Whisper 扩展到更多语言的可能性,可能会使其成为真正全球化的转录工具。

此外,将 Whisper 与其他 AI 模型整合,可以创造出更强大、更多样化的系统。例如,将 Whisper 与 OpenAI 的语言预测模型 GPT-3 结合,可以实现理解口语并预测生成类人文本的系统。

因此,让我们深入探讨 Whisper 对用户体验的实际影响,探索它带来的改进以及这些增强对依赖这些工具的个人的影响。

Whisper 的主要功能是将口语转换为书面文本,这一功能在增强辅助工具功能方面被证明是非常宝贵的。例如,它已经被整合到转录服务、语音助手和聊天机器人中,使得这些技术更加互动和用户友好。

Whisper 的最显著影响之一是它有潜力弥合沟通鸿沟,让世界变得更加包容。它改善了诸如 On Wheels 应用(dataroots.io/blog/on-wheels)中的包容性,这是一款为轮椅使用者、行动不便人士和推婴儿车或手推车的父母重新定义城市环境无障碍的移动应用。该应用提供一个地图,显示一系列实用信息,例如无障碍餐厅、酒吧、博物馆、厕所、商店、停车位、医院、药店和加油站的位置。例如,用户可能会说:“在 123 主街添加一家新的无障碍餐厅。入口宽度为 32 英寸,并有一条坡道通向门口。厕所也可通行,门宽为 36 英寸。”该应用由 Whisper 提供支持,将这段语音输入转录为文本,然后提取相关信息,如餐厅地址、入口宽度、是否有坡道以及厕所的无障碍详情。这些数据会被添加到应用的数据库中,使其他搜索该地区无障碍位置的用户可以使用。Whisper AI 的整合显著改善了语音或听力障碍者的用户体验。Whisper 还被用来开发该应用的语音助手功能。这个语音功能特别适合那些有打字或视力障碍的用户,使他们可以通过语音命令与应用互动,更全面地参与其中。通过自然语言,语音助手使用户能够提供他们想添加到应用中的地点信息,例如建筑物的功能、地址、入口或厕所。这增加了包容性,让那些可能无法通过传统方式使用或贡献无障碍信息的用户,能够通过语音实现这一目标。该应用还将根据用户的轮椅宽度和可管理的门口高度,个性化其体验,显示仅对他们容易到达的地点。用户也可以通过测量自己喜欢的城市地点来贡献,帮助他人未来也能享受这些地方。

Whisper 技术的整合到辅助工具中,带来了用户体验的几项显著改善。例如,Whisper 替代了键盘,允许用户通过语音输入,这对运动障碍者尤其有益。

在教育领域,WhisperPhone(whisperphone.com/)作为一种学习工具,利用 Whisper 技术将学习者的声音直接传递到耳朵,增强听觉反馈回路,帮助学习者听到、产生和纠正语言的正确发音。这个工具对有学习和发育障碍的学习者以及自闭症谱系的个体尤其有益。

此外,Whisper 的鲁棒性和通用性使得集成现有的产品或服务变得更加容易,从而提高了它们的可用性。它的高准确性和速度也有助于提供更流畅的用户体验。

例如,On Wheels 应用程序的语音驱动功能使得有打字或视觉障碍的用户能够为应用程序的数据库贡献内容,从而提高他们的参与度和互动性。同样,WhisperPhone 增强听觉反馈回路的能力也能改善有学习和发育障碍的个体的语言学习成果。

从概念到实践的过渡,我们现在集中于一个实际应用,利用 Whisper 与视觉转文本生成 AI 模型以及 Google 的 gTTS 服务相结合。接下来的部分展示了如何将这些技术集成,以开发一个互动的图像到文本应用,展示了 Whisper 的多功能性及其在推动无障碍和用户互动中的作用。让我们一起探索这个实现的逐步过程和收获的见解。

使用 Whisper 构建互动的图像到文本应用

从评估 Whisper 对无障碍工具中用户体验的影响过渡到实际应用,让我们深入探讨一个结合 Whisper、GPT-4 Vision 和 Google 的 gTTS 服务的应用。该应用将接收图像和音频输入,转录音频,描述图像,然后将描述转回语音。

我鼓励你访问本书的 GitHub 仓库,找到 LOAIW_ch05_4_Whisper_img2txt_LlaVa_image_assistant.ipynb 笔记本(github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter05/LOAIW_ch05_4_Whisper_img2txt_LlaVa_image_assistant.ipynb),亲自尝试这个应用。下图描述了该笔记本如何作为实际示例,展示如何结合使用这些模型来处理和解释音频与视觉数据:

图 5.5 – Whisper img2txt LlaVa 图像助手

图 5.5 – Whisper img2txt LlaVa 图像助手

图 5.5 说明了本笔记本的主要目标:展示LlaVa作为一个多模态图像文本转文本模型的能力,它被描述为GPT-4-vision 的开源版本,并展示了如何将其与 Whisper 的音频处理结合,构建一个全面的多模态 AI 系统。以下是高层步骤,并附有一些选定的代码片段以进行说明:

  1. transformersbitsandbytesacceleratewhispergradiogTTS。还使用ffmpeg创建一个临时音频文件以便音频处理:

    !pip install -q -U transformers==4.37.2
    !pip install -q bitsandbytes==0.41.3 accelerate==0.25.0
    !pip install -q git+https://github.com/openai/whisper.git
    !pip install -q gradio
    !pip install -q gTTS
    !ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono -t 10 -q:a 9 -acodec libmp3lame Temp.mp3
    
  2. 配置量化:本节包括准备量化配置的代码,这对于加载具有 4 位精度的 LlaVa 模型至关重要。这一步骤对优化模型的内存和速度性能至关重要:

    import torch
    from transformers import BitsAndBytesConfig
    quantization_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_compute_dtype=torch.float16
    )
    
  3. 初始化 LlaVa 模型:我们登录 Hugging Face Hub 并初始化图像到文本的管道,使用先前的量化配置。此管道处理图像并生成描述性文本:

    from huggingface_hub import notebook_login
    notebook_login()
    from huggingface_hub import whoami
    whoami()
    # you should see something like {'type': 'user',  'id': '...',  'name': 'Wauplin', ...}
    from transformers import pipeline
    model_id = "llava-hf/llava-1.5-7b-hf"
    pipe = pipeline("image-to-text", model=model_id, model_kwargs={"quantization_config": quantization_config})
    
  4. PIL库:

    import whisper
    import gradio as gr
    import time
    import warnings
    import os
    from gtts import gTTS
    for i in range(1, 11):
        !wget -nv https://github.com/PacktPublishing/Learn-OpenAI-Whisper/raw/main/Chapter05/images/LOAIW_ch05_image_{str(i).zfill(2)}.jpg
    from PIL import Image
    image_path = "/content/LOAIW_ch05_image_03.jpg"
    image = Image.open((image_path))
    image
    
  5. 从图像生成文本:本节提示 LlaVa 模型详细描述加载的图像。它使用特定格式的提示,并处理输出以提取并打印生成的文本:

    max_new_tokens = 200
    prompt_instructions = """
    Describe the image using as much detail as possible. Is it a painting or a photograph? What colors are predominant? What is the image about?
    """
    prompt = "USER: <image>\n" + prompt_instructions + "\nASSISTANT:"
    outputs = pipe(image, prompt=prompt, generate_kwargs={"max_new_tokens": 200})
    # outputs
    # print(outputs[0]["generated_text"])
    for sent in sent_tokenize(outputs[0]["generated_text"]):
        print(sent)
    
  6. 将语音转为文本:加载 Whisper 模型,并定义一个函数将音频输入转录为文本。本节还包括检查 GPU 可用性的代码,这对于运行 Whisper 是首选的:

    import warnings
    from gtts import gTTS
    import numpy as np
    import torch
    torch.cuda.is_available()
    DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
    print(f"Using torch {torch.__version__} ({DEVICE})")
    import whisper
    model = whisper.load_model("medium", device=DEVICE)
    print(
        f"Model is {'multilingual' if model.is_multilingual else 'English-only'} "
        f"and has {sum(np.prod(p.shape) for p in model.parameters()):,} parameters."
    )
    import requests
    import re
    from PIL import Image
    input_text = 'What color is the flag in the image?'
    input_image = '/content/LOAIW_ch05_image_10.jpg'
    # load the image
    image = Image.open(input_image)
    # print(input_text)
    prompt_instructions = """
    Act as an expert in imagery descriptive analysis, using as much detail as possible from the image, respond to the following prompt:
    """ + input_text
    prompt = "USER: <image>\n" + prompt_instructions + "\nASSISTANT:"
    img2txt() function in charge of converting image-to-text output using LlaVa; transcribe() does speech-to-text using Whisper, and text_to_speech() uses gTTS to convert text to speech. The result is saved as an audio file:
    
    

    导入 re

    导入 requests

    从 PIL 导入 Image

    定义 img2txt(input_text, input_image):

    加载图像

    image = Image.open(input_image)

    写入历史记录(f"输入文本: {input_text} - 类型: {type(input_text)} - 目录: {dir(input_text)}")

    如果 type(input_text) == tuple:

    prompt_instructions = """

    使用尽可能多的细节描述图像,它是画作、照片吗?有哪些主色调?图像的内容是什么?

    """

    否则:

    prompt_instructions = """

    作为影像描述分析专家,使用尽可能多的细节从图像中提取信息,回答以下提示:

    """ + input_text

    prompt = "USER: \n" + prompt_instructions + "\nASSISTANT:"

    outputs = pipe(image, prompt=prompt, generate_kwargs={"max_new_tokens": 200})

    正确提取响应文本

    如果 outputs 不为空且 len(outputs[0]["generated_text"]) > 0:

    match = re.search(r'ASSISTANT:\s*(.*)', outputs[0]["generated_text"])

    如果匹配成功:

    提取"ASSISTANT:"后的文本

    reply = match.group(1)

    否则:

    reply = "未找到响应。"

    否则:

    reply = "未生成响应。"

    返回回复

    定义转录(audio):

    检查音频输入是否为 None 或为空

    如果音频为 None 或为空:

    返回 ('','',None) # 返回空字符串和 None 音频文件

    语言 = 'en'

    audio = whisper.load_audio(audio)

    audio = whisper.pad_or_trim(audio)

    mel = whisper.log_mel_spectrogram(audio).to(model.device)

    _, probs = model.detect_language(mel)

    options = whisper.DecodingOptions()

    result = whisper.decode(model, mel, options)

    result_text = result.text

    return result_text

    def text_to_speech(text, file_path):

    language = 'en'

    audioobj = gTTS(text = text,

    lang = language,

    slow = False)

    audioobj.save(file_path)

    return file_path

  7. 运行 Gradio 界面:本笔记本的最后一部分设置了一个 Gradio 界面,允许用户通过上传图像和提供语音输入与系统进行交互。该界面使用定义的函数处理输入,进行图像描述和音频转录,并提供音频和文本输出。有关实现,请参阅笔记本:

图 5.6 – 本应用演示了结合 Whisper、LlaVa 和 gTTS 的强大功能;它提供了一个基于音频输入描述图像的实用工具,对于无障碍应用尤其有用

图 5.6 – 本应用演示了结合 Whisper、LlaVa 和 gTTS 的强大功能;它提供了一个基于音频输入描述图像的实用工具,对于无障碍应用尤其有用

小结

在本章中,我们开始了一段启发性的旅程,探索了 OpenAI 的 Whisper 的广泛功能。我们深入了解了 Whisper 如何革新语音技术,特别是在转录服务、语音助手、聊天机器人以及增强无障碍功能方面的应用。

我们首先探讨了转录服务,在这方面 Whisper 擅长将口语转化为书面文字。其编码器-解码器 Transformer 模型确保了即使在复杂的音频条件下也能提供高准确性。我们还讨论了 Whisper 的局限性,如说话人分离问题,并强调了社区在提升其能力方面的努力。

接下来,我们探讨了如何设置 Whisper 进行转录任务,并提供了一个涵盖安装和配置步骤的全面实践指南。本章强调了理解并调整 Whisper 参数(如DecodingOptions)以实现最佳性能的重要性。

在语音助手和聊天机器人部分,我们探讨了 Whisper 集成如何提升用户体验。我们讨论了聊天机器人和语音助手的架构,解释了 Whisper 如何与现有结构相辅相成。本部分的重点在于平衡技术能力和以用户为中心的设计。

然后,我们将注意力转向了如何利用 Whisper 增强无障碍功能。我们评估了 Whisper 对用户体验的影响,特别是对于听力或语言障碍的个体。Whisper 的高准确性、多语言能力以及开源特性使其成为无障碍工具的革命性改变者。

最后,我们通过第二个实践编码示例来总结本章,演示了 Whisper 如何集成到语音助手中。我们提供了逐步的指南,展示了 Whisper 在聊天机器人架构中的实际应用。

在本章结束时,我们展望第六章使用 Whisper 扩展应用。在这一章中,我们将深入探讨 Whisper 在各个行业中的多种应用。从转录服务到基于语音的搜索,我们将探索如何利用 Whisper 的变革性潜力,提升各个领域的专业和消费者体验。加入我们,一起继续揭开 Whisper 带来无限可能的面纱。

第六章:扩展 Whisper 的应用

本章将继续深入 OpenAI 的 Whisper 广泛应用领域。我们将探讨这项创新技术如何转变和提升各种应用,从精确的转录到跨多个语言和平台创建可访问且可搜索的内容。我们将探索如何在不同语言环境中实现高转录准确度,如何将 Whisper 与 YouTube 等平台集成以处理多语言内容,并使用OpenVINO等工具优化 ASR 模型部署。本章还将介绍如何利用 Whisper 将音频和视频内容转化为可搜索的文本,并与FeedParser结合使用,以便转录播客内容,提升 SEO 效果。通过实践示例和 Python 笔记本,你将获得实际经验,学习如何利用 Whisper 的功能克服自动语音识别中的挑战,并使多媒体内容更易访问且具有全球观众的吸引力。

本章将涵盖以下主要内容:

  • 精确转录

  • 提升与 Whisper 的互动和学习

  • 优化环境以部署基于 Whisper 的 ASR 解决方案

这些部分旨在为你提供全面的理解和实际技能,帮助你在各种环境中有效地使用 Whisper,提高数字内容的价值和影响力。

到本章结束时,你将获得实践经验,并深入了解如何利用 Whisper 的功能解决来自音频和视频服务的自动转录挑战,同时处理多语言内容。你将学习如何将 Whisper 与 YouTube 等平台集成,并利用转录功能进行 SEO 优化,使你的内容更易被发现和更具吸引力。

技术要求

为了充分利用 OpenAI 的 Whisper 进行高级应用,本章将结合 Python、OpenVINO1(用于优化模型性能)以及 Google Colab(便于使用和访问)来讲解。Python 环境的设置包括 Whisper 库用于转录和翻译任务,OpenVINO 用于提升模型推理速度,以及其他特定应用的库,如 PyTube 和 FeedParser。

1 OpenVINO 是英特尔公司拥有的商标。

关键要求

  • Python 环境:确保已安装 Whisper 和 OpenVINO。OpenVINO 对于优化 Whisper 在不同硬件上的性能至关重要。

  • Google Colab 笔记本:使用本书 GitHub 仓库中提供的 Google Colab 笔记本。这些笔记本已设置为运行我们的 Python 代码,所需的内存和容量最小。如果可用,选择T4 GPU运行时类型,以获得更好的性能。

  • GitHub 仓库访问:所有 Python 代码,包括集成 Whisper 与 OpenVINO 的示例,都可以在本章的 GitHub 仓库中找到:(github.com/PacktPublishing/Learn-OpenAI-Whisper/tree/main/Chapter06)。这些 Colab 笔记本已经可以直接运行,提供了一种实用且动手实践的学习方式。

通过满足这些技术要求,读者将为探索多语言转录、提升内容可发现性以及高效部署基于 Whisper 的自动语音识别(ASR)解决方案做好准备,同时享受 Google Colab 提供的简化体验和 GitHub 上提供的丰富资源。

在打下技术基础并准备好工具后,我们将转向深入探索 Whisper 的核心功能。精准转录是我们的下一个目标,我们将深入探讨如何在多语言和方言之间实现高准确度的转录。这一部分将是一次充实的旅程,旨在完善转录艺术,充分发挥 Whisper 的先进技术潜力。

精准转录

在本节中,我们将把 OpenAI 的 Whisper 的实用性提升到新的高度,展示它在处理各种语言挑战方面的多样性和强大能力。本部分将引导你了解如何利用 Whisper 进行转录,并真正理解和解读多语言内容,确保出色的准确性。从方言的细微差别到不同语言的节奏,Whisper 在转录方面的高效性为解锁内容的全球潜力提供了门户。

我们首先探索如何利用 Whisper 进行多语言转录。我们演示了 Whisper 的复杂算法如何应对多语言的复杂性,确保你的转录准确且在文化和语境上相关。这一点尤为重要,因为我们生活在一个以多样性和包容性为基础的世界中。

接下来,我们将把重点转向为提升内容可发现性而进行的索引处理。在这个数字化时代,信息的可访问性至关重要,而 Whisper 提供了一种创新的方法,使音频和视频内容能够被搜索。通过将口语转录为文本,Whisper 扩大了内容的传播范围,并增强了其在互联网上的可见性和互动性。

最后,我们将使用 FeedParser 和 Whisper 创建可搜索的文本。本节内容阐明了从 RSS 源中检索音频内容并将其转化为可搜索文本之间的协同作用,从而显著提升 SEO 和内容营销效果。通过实际示例和动手实践,你将学会如何利用这些工具扩大内容的数字足迹,使其更易被发现,并为更广泛的受众提供访问。

利用 Whisper 进行多语言转录

在全球沟通的丰富多彩的画卷中,我们无缝过渡到为多种语言配置 Whisper 的实际操作。这一步至关重要,是理论与实践的结合,使 Whisper 能轻松跨越语言障碍。在这里,我们将学习如何配置 Whisper,确保它成为你工具库中捕捉人类语言多样性的多功能工具。这一基础将为进一步探索 Whisper 在多语种环境中理解并准确转录内容的能力铺平道路。

为不同语言设置 Whisper

Whisper 支持多种语言,包括但不限于英语、印地语、西班牙语等。要为不同语言设置 Whisper,你可以使用 Whisper API,提供两个端点:转录和翻译。

对于仅支持英语的模型,可以手动将语言设置为 en(英语)。然而,多语种模型可以自动检测语言。可以使用命令 whisper.load_model("base") 加载 Whisper 模型,音频的语言可以通过 model.detect_language(mel) 方法检测。

比如,如果你想转录一份西班牙语的音频文件,你可以在进行转录时指定语言:whisper japanese.wav --``language Spanish

在本书的 GitHub 仓库中 (github.com/PacktPublishing/Learn-OpenAI-Whisper/tree/main/Chapter06),你会找到一个名为 LOAIW_ch06_1_Transcripting_translating_YouTube_with_Whisper.ipynb 的笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter06/LOAIW_ch06_1_Transcripting_translating_YouTube_with_Whisper.ipynb),其中包含了转录和翻译音频文件的示例。以下是来自该笔记本的代码片段,展示了如何使用 Whisper 进行语言检测,而不进行转录:


Import whisper
import torch
model = whisper.load_model("small")
audio = whisper.load_audio(source_audio)
audio = whisper.pad_or_trim(audio)
mel = whisper.log_mel_spectrogram(audio).to(model.device)
# detect the spoken language
_, probs = model.detect_language(mel)
audio_lang = max(probs, key=probs.get)
print(f"Detected language: {audio_lang}")

下面是代码的逐步讲解,帮助我们更好地理解基础设置和交付流程:

  1. whisper 模块,包含 Whisper 模型、相关函数,以及用于处理张量的 torch 库(PyTorch)。

  2. whisper.load_model("small") 函数加载 Whisper 模型的 "small" 版本。Whisper 提供了不同的模型大小,"small" 模型是性能和资源使用之间的权衡。

  3. whisper.load_audio(source_audio) 函数加载由 source_audio 指定的音频文件。然后,使用 whisper.pad_or_trim(audio) 对音频进行填充或裁剪,以适应合适的长度。

  4. whisper.log_mel_spectrogram(audio) 函数将音频转换为对数 Mel 频谱图,这是 Whisper 模型用作输入的时频表示。然后,使用 .to(model.device) 将频谱图移到与模型相同的设备上,以确保兼容性。

  5. model.detect_language(mel) 函数用于检测音频中所说的语言。该函数返回一个元组,其中第二个元素是一个字典类型的对象,包含不同语言的概率值。max(probs, key=probs.get) 表达式用来找到概率最高的语言,假设它就是音频中所说的语言。

  6. 输出:最后,检测到的语言将被打印出来。

通过回顾并在 第四章 中获得的见解,针对特定领域和语言的微调 Whisper,我们确定了微调 Whisper 提供了一种定制的方法,旨在解决特定口音和方言的细微挑战。这种定制使 Whisper 能够适应地区性语音模式的独特语音和节奏特征,从而提高转录准确性。在进入下一小节时,必须记住,微调不仅仅是一种策略,而是那些希望提升 Whisper 在多样化语言环境中表现的用户所必须采取的步骤。本节将深入探讨微调 Whisper 的实际操作和优势,确保它能满足您转录任务的具体需求。

克服口音和方言的挑战

像 Whisper 这样的 ASR 系统面临着理解和转录各种口音和方言的复杂任务。这些语音模式的变化由于其独特的发音、语调和重音模式而构成了显著的挑战。然而,Whisper 配备了处理这种多样性的能力,这得益于它在庞大的数据集上的广泛训练,涵盖了各种语言的细微差别。

正如我们在 第四章 中学到的,针对特定领域和语言的微调 Whisper,微调 Whisper 以适应特定的口音和方言需要采取量身定制的方法,考虑到地区性语音模式的独特语音和节奏特征。这种定制对于提高转录准确性至关重要,因为它使 Whisper 能够适应不同语言和方言的语音特征中的微小变化。

要微调 Whisper,必须深入研究目标口音或方言的语言细节。这涉及分析和理解定义口音的三个基本元素:语调节奏重音模式

语调指的是讲话时声音的升降;节奏指的是声音和静默的模式,重音模式则表明某些音节或单词的强调。通过理解这些元素,可以调整 Whisper 的转录参数,更好地捕捉口语的本质。

例如,某种特定的方言可能有独特的语调模式,而 Whisper 的通用模型可能无法准确识别。通过对模型进行微调,使其适应这一特定的语调模式,Whisper 可以学习到这些细微差别,从而提高转录的准确性。同样,理解方言的节奏和重音模式,可以帮助 Whisper 区分不同方言中可能发音不同的同音词,从而减少转录错误。

微调可能需要通过精心策划的数据集来重新训练 Whisper,该数据集能显著代表目标口音或方言。该数据集应包含各种语音样本,捕捉方言中所有语言特征的全貌。通过将 Whisper 暴露于这种定向训练,模型可以更精确地识别和转录该方言。

此外,针对口音和方言对 Whisper 进行微调,不仅仅是提高单词识别率;它还涉及理解单词被说出的语境。口音和方言可以影响语言所传达的意义,微调后的 Whisper 模型可以更好地解读单词背后的意图。

在实践中,针对特定口音或方言对 Whisper 进行微调可能涉及以下步骤:

  1. 数据收集:收集一个全面的音频录音数据集,准确地代表目标口音或方言

  2. 模型训练:使用该数据集重新训练或调整 Whisper 的现有模型,重点关注口音或方言的独特特征

  3. 参数调整:修改 Whisper 的解码参数,如语言和语音模型,以更好地适应目标语音模式

  4. 测试和评估:在单独的验证集上评估微调后的模型表现,以确保目标口音或方言的转录准确性得到提升

  5. 迭代优化:通过整合反馈和额外数据,持续优化模型,以进一步提高其准确性

通过采用这种量身定制的方法,Whisper 成为一个更强大的转录工具,能够从音频中提供准确可靠的文本,覆盖更广泛的语言和方言范围。这提升了与 ASR 系统交互的用户体验,并为在全球多元文化环境中应用语音识别技术开辟了新的可能性。

在深入探讨如何微调 Whisper,以巧妙应对各种口音和方言的挑战之后,我们现在将注意力转向旅程中的下一个重要步骤。将 PyTube 与 Whisper 集成进行多语言转录,为将 Whisper 的转录能力扩展到 YouTube 内容的广阔宝库提供了创新的路径。这一集成不仅拓宽了可访问信息的范围,还增强了多语言转录工作的丰富性。

将 PyTube 与 Whisper 集成进行多语言转录

YouTube 在数字内容生态系统中的重要性不容小觑。作为全球第二大搜索引擎和领先的视频内容平台,YouTube 是内容创作者接触广泛、不同观众的关键渠道。该平台承载了从教育讲座、操作指南到娱乐节目和公司通讯等各类内容。然而,内容的价值不仅仅体现在其视觉和听觉的吸引力上;视频中的口语内容是一个宝贵的信息宝库,一旦被转录,就能提高其可发现性和可访问性。

对 YouTube 视频进行转录有多重目的。它将视听内容转化为文本,使搜索引擎可以对其进行索引。这样的文本格式允许用户通过关键词搜索定位到特定内容,而光靠音频和视频是无法做到的。此外,转录文本还可以用于生成字幕和闭路字幕,进一步扩大内容的覆盖范围,帮助非母语观众和听力障碍人士获取信息。

要转录 YouTube 内容,首先必须提取音频。这时,Python 库 PyTube 就成为了一个至关重要的工具。PyTube 使得下载 YouTube 视频成为可能,为转录提供所需的原始音频。在本书的 GitHub 仓库中,你会找到名为 LOAIW_ch06_1_Transcripting_translating_YouTube_with_Whisper.ipynb 的笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter06/LOAIW_ch06_1_Transcripting_translating_YouTube_with_Whisper.ipynb),其中包含了一个实用的、基础的 Python 代码示例,展示了如何使用 PyTube 下载 YouTube 视频的音频。以下是关键代码片段:


import re
from pytube import YouTube
video_url = "<Place video URL here>" #@param {type:"string"}
drive_folder = "" #@param {type:"string"}
yt = YouTube(video_url)
episode_date = yt.publish_date.strftime('%Y%m%d-')
source_audio = drive_folder + episode_date + (re.sub('[^A-Za-z0-9 ]+', '', yt.title).replace(' ', '_')) + ".mp4"
audio_file = YouTube(video_url).streams.filter(only_audio=True).first().download(filename=source_audio)
print(f"Downloaded '{source_audio}")

这段代码片段实现了多个任务:

  • 导入必要的 "pytube" 库,以便与 YouTube 内容进行交互

  • 定义要下载的 YouTube 视频的 URL

  • 根据视频的标题和发布日期创建下载音频的文件名,确保文件管理方法系统化

  • 下载指定 YouTube 视频的音频流,使其可供转录使用

一旦获得音频,就可以使用 Whisper 进行转录。Whisper 能够处理各种语言和方言,使其成为转录 YouTube 多样化内容的理想工具。转录后的文本可以创建可搜索的索引,提高内容在搜索引擎中的可见性,并增强 YouTube 搜索算法中的曝光度。

转录文本不仅对索引有益,而且对 SEO 和内容营销策略也有帮助。从转录文本中提取的关键词可以用于优化网页、博客文章和社交媒体更新,从而提升内容在搜索引擎中的排名。此外,转录后的文本还可以重新用于不同的格式,如文章、信息图表和电子书,扩展内容的传播范围和互动潜力。

YouTube、PyTube 和 Whisper 之间的协同作用,代表了内容可发现性的未来的一个实际示例。随着视频内容继续主导数字领域,将这些内容转化为可搜索的文本将变得越来越重要。这个过程不仅通过提高内容的可访问性来增强用户体验,还为内容创作者提供了强大的工具,帮助他们优化内容以便搜索引擎抓取,并接触到更广泛的受众。

随着我们从 PyTube 与 Whisper 创新的整合中向前迈进,提升我们的多语言转录工具包,我们将注意力转向加强转录内容的可见性和可访问性。为提高可发现性而对内容进行索引,成为了一项关键策略,架起了未被充分利用的音频资源和可搜索的网络生态系统之间的桥梁。接下来的部分将指导我们优化转录内容,确保它被听到、轻松找到,并且能够被全球受众参与。

为提高可发现性而对内容进行索引

在这个时代,我们都面临着一个重大挑战:海量的在线内容令人震惊。为了在这片信息的浩瀚海洋中航行,搜索引擎使用了一种叫做索引的过程。索引是搜索引擎收集、评估和组织海量互联网信息的方式,包括网页、文档、图像、视频和其他类型的内容。这个过程使搜索引擎能够高效地检索并展示与用户查询相关的信息。其工作原理如下:

  1. 爬行:搜索引擎部署了被称为爬虫或蜘蛛的机器人,用来发现互联网内容。这些机器人系统地浏览网页,按照链接从一个页面跳转到另一个页面。它们仔细检查每个 URL 的内容和代码,包括网页、图像、视频和 PDF 文件。

  2. 索引:爬取之后,内容将被索引。这意味着爬虫发现的信息会存储并组织在一个庞大的数据库中,这个数据库被称为搜索引擎的索引。索引类似于一个巨大的在线文件管理系统,包含搜索引擎发现并认为值得提供给用户的每个网页和内容。

  3. 排名:一旦内容被索引,它可以根据相关查询进行展示。搜索引擎通过相关性对这些内容进行排名,首先展示最相关的结果。排名涉及各种算法,考虑关键词、网站权威性和用户体验等因素。

网站管理员可以使用像XML 网站地图Google 搜索控制台这样的工具来促进索引。XML 网站地图列出网站上的所有页面,并附上额外的详细信息,比如每个页面最后修改的时间。这些网站地图可以提交给搜索引擎,提醒它们内容的存在,并帮助爬虫理解网站结构。

搜索引擎根据“爬取预算”进行操作,即它们为爬取网站分配的资源。这个预算受到服务器速度和网站重要性等因素的影响。高价值、频繁更新内容的网站可能会比小型、不太重要的网站更频繁地被爬取。

索引过程还涉及使用倒排索引,这是一个包含指向包含这些元素的文档的指针的文本元素数据库。这个系统使得搜索引擎能够快速检索数据,而无需在单独的页面中查找关键词和主题。

搜索引擎的索引是一个复杂但至关重要的过程,涉及爬取网页以发现内容、存储内容、在索引中组织内容,然后对其进行排序,以向用户提供最相关的搜索结果。理解和优化这个过程是搜索引擎优化(SEO)的基础。

从音频和视频创建可搜索的文本

增强音频和视频内容可发现性的最有效方法之一是通过转录。转录是将语音转换为文本,使得无法搜索的语音变成可搜索的文本。转录本为搜索引擎提供了额外的数据用于索引,使其能够爬取音频或视频内容的完整文本。这可能会增加你的内容在自然搜索结果中的可见度。在你的视频内容中加入转录本,更有可能使其在搜索结果中排名更高,包括像 YouTube 这样的 платформ。

转录本还可以针对特定关键词进行优化,提升目标受众发现你内容的可能性。这一过程不仅使你的内容对更广泛的观众(包括聋人或听力受损者)更具可访问性,而且还使搜索引擎能够索引音频和视频文件的内容。

自动化和人工转录服务都可以将音频和视频内容转换为文本。这些服务可以处理各种类型的内容,从播客和访谈到讲座和商业通讯。一旦转录完成,搜索引擎便可以对这些文本进行索引,从而使您的音频和视频内容通过基于文本的搜索被发现。

利用转录进行 SEO 和内容营销

转录不仅能让您的内容更具可访问性和可搜索性;它还可以显著提升您的 SEO 和内容营销效果。在转录中加入关键词可以提升您内容在搜索引擎上的可见性。转录内容还可以被重新加工成其他形式的内容,如博客文章、案例研究和信息图表,从而进一步增强您的内容营销策略。

转录在内容营销中也扮演着至关重要的角色,通过提升客户互动和覆盖面。发布您的音频和视频内容的转录本,让观众能够将您的内容翻译成他们的语言,从而覆盖更广泛的受众。

此外,转录本还可以帮助满足偏好阅读文本的用户以及有听力障碍的用户,使您的内容更加包容和可访问。这种包容性提高了用户体验,并扩大了您的受众覆盖范围,可能带来更多的网页流量和更高的搜索排名。

为了提高可发现性,内容的索引化是数字内容策略中的关键方面。通过有效地对您的内容进行索引,并利用音频和视频内容的转录,您可以显著提高内容的可见性,接触到更广泛的受众,并增强您的 SEO 和内容营销效果。随着数字环境的不断发展,这些策略将继续是那些希望最大化在线存在并取得可衡量商业成果的企业的核心要素。

在探索了利用转录进行 SEO 和内容营销的重要性之后,我们的下一个目标是创建可搜索的文本,旨在通过使用播客内容作为基础示例,充分挖掘 Whisper 的潜力。这一创新的结合简化了将口语转化为已编制索引的文本的过程,并为在数字平台上提高内容的可发现性和互动性开辟了新途径。

利用 FeedParser 和 Whisper 创建可搜索的文本

FeedParser 和 Whisper 的结合在从音频和视频中创建可搜索的文本方面具有高度相关性,尤其是对于通过 RSS 订阅分发的内容,如播客。FeedParser 是一个 Python 库,可以轻松下载和解析联合订阅的源,包括RSSAtomRDF源。它在自动化音频内容从各种渠道的获取中起着重要作用,随后可以进行转录处理。

当 FeedParser 和 Whisper 结合使用时,能够实现一个简化的流程,将 RSS 订阅源中的音频内容自动获取、下载并转录为文本。该文本随后可以被搜索引擎索引,从而提升内容的可发现性。例如,一集本来无法被搜索引擎访问的播客节目,可以通过 FeedParser 下载,再由 Whisper 转录成文本,使得该集播客的内容可以通过音频中提到的关键词和短语进行搜索。这个过程不仅让内容对更广泛的受众更加可及,同时也便于与数字图书馆和内容管理系统更好地集成,后者的可搜索性至关重要。

由 Whisper 生成的转录文本,结合 FeedParser 提取的音频内容,对于 SEO 和内容营销工作有极大的帮助。具体如下:

  • 关键词优化:转录的文本提供了丰富的相关关键词来源。这些关键词可以战略性地用于优化网页、博客文章和其他内容的搜索引擎排名。通过在元标签、描述以及内容本身中加入这些关键词,可以提高相关内容的 SEO 排名,使其更容易被正在搜索相关话题的用户发现。

  • 内容再利用:转录的文本可以作为创建额外内容格式的基础。例如,播客中的关键见解可以转化为博客文章、信息图表,甚至一系列社交媒体帖子。这延长了原始内容的生命周期,并满足了不同受众的偏好,从而增加了整体的覆盖范围和互动性。

  • 增强用户体验:在音频和视频内容旁提供转录文本,通过迎合不同的消费偏好来改善用户体验。有些用户可能更喜欢阅读而非听内容,转录文本让这一点成为可能。此外,转录文本使得内容对听障或有听力障碍的用户更具可及性,从而扩大潜在的受众群体。

  • 链接建设:转录文本可以创造更多的内部和外部链接机会,这是 SEO 中的一个关键因素。通过在转录中链接相关的文章、资源和其他播客,内容创作者可以建立一个更加互联的网络存在,这也是搜索引擎所青睐的。

  • 分析与洞察:转录文本使得更详细的内容分析成为可能,这有助于制定 SEO 和内容营销策略。通过分析转录内容,创作者可以洞察与受众产生共鸣的主题、话题和语言,并据此调整内容策略。

使用 FeedParser 从 RSS 订阅源提取音频并通过 Whisper 进行处理的基础示例,可以扩展到许多行业的商业案例中。例如,这种方法可以在媒体和娱乐行业中用于转录和索引大量的视听内容,使其可以被搜索,并开辟新的盈利渠道。在客户服务领域,转录并分析客户电话可以提高服务质量和客户满意度。

此外,在市场调研和竞争分析中,转录播客和行业讲座可以提供关于市场趋势和竞争对手策略的及时洞察。在法律和合规领域,能够转录并搜索数小时的法律程序和监管会议记录,可以简化工作流程并确保遵守法规。

通过建立一个系统化的音频内容提取和转录过程,企业可以构建一个强大的框架,适应其他各种数据源,例如视频流、网络研讨会和实时通信。这将提升现有内容的可发现性,并帮助组织准备好利用新兴数据流的潜力。

FeedParser 和 Whisper 的整合是 AI 和机器学习如何应用于解决现实商业挑战的一个典型例子。通过利用这些技术,企业可以构建一个可扩展和灵活的基础设施,适应不断变化的数字化环境,在信息驱动的经济中提供竞争优势。

现在,让我们通过一个实用的 Python 笔记本,增强我们的技术专长,演示 FeedParser 的实际应用!

将 FeedParser 和 Whisper 集成进行文本转录

该笔记本LOAIW_ch06 _2_Transcripting_translating_RSS_with_Whisper.ipynb (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter06/LOAIW_ch06_2_Transcripting_translating_RSS_with_Whisper.ipynb)旨在弥合播客节目中锁定的大量知识与文本所提供的可访问性和分析潜力之间的差距。播客作为一种媒介,在过去几年里迅速普及,成为全球听众信息、娱乐和教育的丰富来源。然而,尽管播客的影响力不断扩大,但将内容转换为文本形式——这对于可访问性、可搜索性和进一步分析至关重要——仍然是一个挑战。这正是转录技术发挥作用的地方。

从 RSS 源中获取播客剧集——一种用于发布定期更新内容的标准联合格式——展示了如何自动化转录。这不仅让播客内容更具可访问性,还为内容创作者、研究人员和教育工作者提供了利用口语内容的全新途径。

通过结合 Python 编程,本笔记本将引导你完成安装必要的库、解析 RSS 源以列出可用的播客剧集、下载音频文件,并使用 Whisper 进行转录。这个过程展示了如何将不同技术整合,形成从音频到文本的无缝工作流:

  1. 设置 环境

    环境设置包括安装在笔记本中将使用的必要 Python 库和系统工具:

    
    !pip install -q cohere openai tiktoken
    !apt-get install ffmpeg
    !pip install -q "git+https://github.com/openai/whisper.git"
    cohere, openai, tiktoken, ffmpeg, and whisper. Here’s what the following commands are doing:*   `feedparser`: This library is specifically designed for parsing RSS and Atom feeds. It simplifies working with feed data, such as extracting podcast information. Its role in the notebook is to parse the RSS feed provided by the user, enabling the extraction of details about the podcast episodes available for download and transcription.*   `requests`: A fundamental library for making HTTP requests in Python. It’s used in the notebook to download audio files from the URLs specified in the podcast’s RSS feed. The simplicity and flexibility of requests make it a go-to choice for web scraping tasks, API interactions, and downloading files over HTTP.
    
  2. 导入库

    一旦环境设置完成,下一步是导入笔记本中使用的 Python 库:

    
    import feedparser
    import requests
    import os
    import time
    from urllib.parse import urlparse
    import subprocess
    import re
    

    我们已经在前一部分了解了大部分这些库。让我们来看一下首次出现的库:

    • os:这是一个标准 Python 库,用于与操作系统进行交互。它用于文件路径操作和环境变量访问,确保笔记本能够保存文件、浏览目录等。

    • time:一个标准的 Python 库,这里用于处理与时间相关的任务。它可以包括在请求之间添加延迟,以避免过度负载服务器,或对操作进行计时以进行性能分析。

    • urlparse:Python 标准库的一部分,用于解析 URL。urlparse 帮助拆解 URL 组件,这在从播客的 URL 中提取信息或确保 URL 格式正确后再进行请求时非常有用。

    • subprocess:这个模块允许你生成新进程、连接它们的输入/输出/错误管道,并获取它们的返回码。笔记本调用外部命令,如 ffmpeg,来处理音频文件。

    • re:这是 requests 库的简称。

    这些库共同构成了笔记本的核心,使其能够处理网页内容、处理音频文件,并高效地与文件系统和外部进程交互。这个准备工作对于顺利执行从解析 RSS 源到转录音频内容的后续任务至关重要。

  3. list_episodes() 帮助用户浏览播客系列中的可用内容,而 download_episode() 提供了访问特定剧集原始音频的方式。download_episode_start_end() 函数提供了更精细的下载内容的方法。让我们简要探讨一下笔记本中定义的三个函数:

    • list_episodes():此函数旨在解析给定的 RSS 源 URL,并列出所有可用的播客集。它系统地提取并整理每集的关键信息,如标题、URL(通常指向音频文件)和发布日期。以下是该函数的 Python 代码定义:

      
      def list_episodes(feed_url):
          d = feedparser.parse(feed_url)
          episodes = []
          for entry in d.entries:
              title = entry.title
              published = time.strftime('%Y%m%d', time.gmtime(time.mktime(entry.published_parsed)))
              url = None
              for link in entry.links:
                  if link.type == "audio/mpeg":
                      url = link.href
                      break
              if url:
                  episodes.append((title, url, published))
          return episodes
      

    此函数作为用户查看播客系列内容的工具,使用户能够选择特定的集进行下载和转录。

    • download_episode():此函数用于下载特定的播客集。它需要输入播客集的 URL(通常从 list_episodes() 获取),并将音频文件保存到用户系统中的指定位置。以下是该函数的 Python 代码定义:

      from urllib.parse import urlparse
      def download_episode(url, filename=None):
          # If a custom filename is provided, append the appropriate extension from the URL
          if filename:
              parsed_url = urlparse(url)
              # Extract only the base path without any query parameters
              base_path = os.path.basename(parsed_url.path)
              ext = os.path.splitext(base_path)[1]
              filename += ext
          else:
              filename = os.path.basename(parsed_url.path)
          response = requests.get(url, stream=True)
          response.raise_for_status()
          with open(filename, 'wb') as f:
              for chunk in response.iter_content(chunk_size=8192):
                  f.write(chunk)
          return filename
      

    此函数对于获取转录所需的原始音频数据至关重要。它确保用户能够直接访问感兴趣的内容并为进一步处理做好准备,例如使用 Whisper 进行转录。

    • download_episode_start_end():此函数是 download_episode() 的一个变种,具有额外的功能。它允许通过从给定的 URL 下载播客集并裁剪出从 start_at 秒到 end_at 秒的时间段来提取特定的时间片段。以下是该函数的 Python 代码定义:

      def download_episode_start_end(url, filename=None, start_at=0, end_at=None):
          parsed_url = urlparse(url)
          if filename:
              # Ensure the filename has the correct extension
              ext = os.path.splitext(parsed_url.path)[1]
              filename += ext
          else:
              filename = os.path.basename(parsed_url.path)
          # Download the file
          response = requests.get(url, stream=True)
          response.raise_for_status()
          temp_filename = "temp_" + filename
          with open(temp_filename, 'wb') as f:
              for chunk in response.iter_content(chunk_size=8192):
                  f.write(chunk)
          # Use ffmpeg to trim the audio file
          trimmed_filename = "trimmed_" + filename
          command = ['ffmpeg', '-y', '-i', temp_filename, '-ss', str(start_at)]
          if end_at is not None and end_at != 0:
              command.extend(['-to', str(end_at)])
          command.extend(['-c', 'copy', trimmed_filename])
          subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
          # Remove the original downloaded file
          os.remove(temp_filename)
          return trimmed_filename
      

    以下是输入参数的详细说明:

    • url:播客集的 URL。

    • filename:保存播客的期望文件名。如果未提供,它将使用 URL 的最后一部分。

    • start_at:音频应从哪一秒开始裁剪的起始时间。

    • end_at:音频应该裁剪到的结束时间(以秒为单位)。如果未提供或设置为 0,音频将裁剪到结束位置。

    在笔记本和实际演示中,download_episode_start_end() 函数允许我们处理音频文件的较小样本;在某些情况下,赞助商相关的内容对我们的学习和实验并不重要。这对于转录某一集的特定片段而非整个内容特别有用,能节省时间和计算资源。例如,如果播客每个片段的前 30 秒总是包含赞助广告,该函数可以直接下载其余部分的内容。

  4. 选择 RSS 源播客

    然后,笔记本指定了播客的 RSS 源 URL 和要列出的集数。将此 URL 替换为您感兴趣的任何播客源:

    
    # Gigantes Podcast Spanish
    podcast = '<Place RSS URL Here>'
    d = feedparser.parse(podcast)
    print(f"Podcast name:", d.feed.title)
    print(f"Number of episodes:", len(d.entries))
    # List episodes
    episodes = list_episodes(podcast)
    # Print the first ten episodes
    print("Episodes:")
    for idx, (title, url, published) in enumerate(episodes, 1):
        print(f"{idx}. {published}-{title}")
        if idx == 10:
            break
    
  5. 选择并下载 一集

    接下来,笔记本提示用户从源中选择一集并进行下载。用户设置该集的编号,相关的音频文件将被获取:

    
    episode_num = 5 #@param {type:"integer"}
    drive_folder = "" #@param {type:"string"}
    start_at_seconds = 1300 #@param {type:"integer"}
    end_at_seconds = 0 #@param {type:"integer"}
    title, url, published = episodes[episode_num - 1]
    custom_filename = published + '-' + (re.sub('[^A-Za-z0-9 ]+', '', title[:75]).replace(' ', '_'))
    # Download the selected episode
    audio_file = download_episode_start_end(url, drive_folder + custom_filename, start_at_seconds, end_at_seconds) print(f"Downloaded '{title}' as {audio_file}.")
    
  6. 显示音频小部件

    为了提供友好的用户界面,笔记本中显示了一个音频小部件,可以直接播放下载的播客集:

    
    import ipywidgets as widgets
    widgets.Audio.from_file(audio_file, autoplay=False, loop=False)
    
  7. 使用 Whisper 转录

    最后,笔记本展示了如何使用 Whisper 来转录下载的播客集:

    
    import whisper
    import torch
    # NLTK helps to split the transcription sentence by sentence
    import nltk
    nltk.download('punkt')
    from nltk import sent_tokenize
    model = whisper.load_model("small")
    audio = whisper.load_audio(audio_file)
    audio = whisper.pad_or_trim(audio)
    # make log-Mel spectrogram and move to the same device as the model
    mel = whisper.log_mel_spectrogram(audio).to(model.device)
    # detect the spoken language
    _, probs = model.detect_language(mel)
    audio_lang = max(probs, key=probs.get)
    print(f"Detected language: {audio_lang}")
    # decode the audio
    options = whisper.DecodingOptions(fp16=torch.cuda.is_available(), language=audio_lang, task='transcribe')
    result = whisper.decode(model, mel, options)
    # print the recognized text
    print("----\nTranscription from audio:")
    for sent in sent_tokenize(result.text):
      print(sent)
    # decode the audio
    options = whisper.DecodingOptions(fp16=torch.cuda.is_available(), language=audio_lang, task='translate')
    result = whisper.decode(model, mel, options)
    # print the recognized text
    print("----\nTranslation from audio:")
    for sent in sent_tokenize(result.text):
      print(sent)
    

我鼓励你运行 Google Colab 笔记本,提升其功能,并找到一个与行业相关的实际应用案例,借助这一基础知识,快速利用 Whisper 获得成功!

我们的下一步是深入探讨客户服务和教育平台,在这些领域,Whisper 的能力在转录准确性以及创造更加互动、响应和丰富的用户体验方面表现出色。

使用 Whisper 提升互动和学习

现在,我们将更深入地探讨如何将 Whisper 定制并整合到客户服务工具和语言学习平台中。在下一章节中,我们将探索一个动手操作的笔记本,展示如何利用 Whisper 尽可能地实现实时转录。同时,让我们简要提醒您在进行实时转录时使用 Whisper 的一些注意事项。

使用 Whisper 实现实时 ASR 的挑战

尽管 Whisper 提供了先进的语音识别能力,但其缺乏原生的实时转录支持,给开发者和组织带来了显著的挑战。然而,通过第三方优化、自定义实现以及利用第三方提供的 API,仍然可以将 Whisper 调整为适用于实时 ASR 应用程序。尽管这些解决方案也存在一定的挑战和成本,但它们为组织在实时场景中利用 Whisper 的强大功能提供了一条可行的路径。

部署 Whisper 用于实时自动语音识别(ASR)应用程序面临若干重大挑战,包括以下几点:

  • 缺乏原生实时支持:Whisper 本质上是一个批量语音转文本模型,并未设计用于流式或实时转录。这一局限性对于需要即时转录的应用程序,如实时客户服务互动或直播语言翻译服务来说,是一个重大挑战。

  • 基础设施和运营成本:运行 Whisper,特别是较大且更精确的模型,需大量基于 GPU 的计算资源,这可能会非常昂贵。组织需要准备投资必要的硬件或云服务,以支持 Whisper 的计算需求,而这些需求在大规模应用时可能会迅速增加。

  • 内部 AI 专业知识:为了有效部署 Whisper,公司必须拥有一支内部的机器学习工程团队,能够在生产环境中操作、优化和支持 Whisper。这还包括开发 Whisper 本身不提供的附加 AI 功能,如说话人分离和个人身份信息PII)遮蔽。

尽管存在这些挑战,组织仍然可以采取一些解决方案和变通方法,以便利用 Whisper 实现实时 ASR:

  • 分块与批处理:Whisper 可以与分块算法一起使用,用于转录任意长度的音频样本,以处理较长的音频。然而,这并不是一种原生的实时解决方案。

  • 第三方 API 提供商:几家公司已对 Whisper 进行了规模优化,解决了核心性能参数,并添加了高价值功能,如实时转录和语者分离。

  • 定制实现:开发人员可以创建定制的解决方案,录制短音频片段并通过 Whisper 将其发送到服务器进行转录,从而模拟接近实时的体验。

在探讨了使用 Whisper 实施实时 ASR 的挑战之后,让我们回到主题,深入探讨这项技术如何彻底改变客户服务,改善互动,并提升整体客户体验。

在客户服务中实施 Whisper

强调实时转录领域的不断发展是至关重要的。Whisper 在客户服务中的集成不仅仅是技术创新,它还为组织创造了重要的机会,以提升服务质量,使每一次客户互动更加有影响力、个性化和高效。

在接下来的章节中,我们将探讨如何利用 Whisper 接近实时的转录能力定制客户回复,以及如何将这项技术与现有的客户服务工具无缝集成,以提升整体效率和效果。

使用接近实时转录定制回复

定制回复使其尽可能接近实时转录的能力可以显著提高客户服务质量。Whisper 在将口语转录为文本方面的高精度,使客户服务代表能够更加有效和高效地理解并解决客户问题。将转录能力从接近实时转变为实时的努力仍在不断发展,并迅速变化。这一进程具有潜在的重大影响:通过实时转录,客户互动过程中没有任何细节被遗漏,从而提供更加个性化和准确的回复。例如,Whisper 在处理各种语言任务方面的熟练程度,如其 API 文档中所强调的,使得能够转录来自不同语言和方言的客户查询,确保了客户服务的包容性和可访问性。

此外,将 Whisper 与客户服务平台集成可以自动化转录过程,缩短响应时间并提高整体效率。通过利用 Whisper 先进的语音识别能力,企业可以创建一个更加动态和响应迅速的客户服务环境,以满足全球客户的需求。

将 Whisper 与现有的客户服务工具集成

将 Whisper 与现有的客户服务工具集成可以简化操作并提升客户体验。在企业层面上,存在着展示这种集成潜力的需求,这将使得在聊天机器人和客户支持软件中能够识别和转录语音信息。目标是使这些集成能够促进语音和基于文本的互动之间的无缝过渡,从而帮助客户服务人员更高效地管理和回应查询。

这些集成最终将实现客户语音信息的自动转录并生成基于文本的响应,从而减少人工工作量并提高响应速度。

使用 Whisper 促进语言学习

Whisper 在语言学习平台中的集成可以彻底改变学习者接收反馈的方式。通过转录口语练习,Whisper 能够对发音、流利度和语言使用提供即时而准确的反馈。这种即时反馈机制对语言学习者至关重要,使他们能够迅速识别和纠正错误,从而加速学习过程。

Whisper 还可以被用来开发更具互动性和吸引力的语言学习体验。通过转录和分析口语,语言学习平台可以创建动态练习,适应学习者的熟练程度和学习风格。这种个性化的语言学习方法可以显著增强学习者的参与感和动力。此外,Whisper 处理多语言内容和大量音频文件的能力,使其成为创造多样化和包容性语言学习材料的理想工具,以满足全球受众的需求。

将 Whisper 集成到客户服务和语言学习平台中提供了许多提升用户互动和教育体验的机会。企业可以通过实时转录定制响应,并将 Whisper 与现有工具集成,从而彻底改变客户服务操作。类似地,通过即时反馈和互动体验来改善语言学习,可以显著提高学习成果。随着我们不断探索和扩展 Whisper 的功能,改变数字互动和学习体验的潜力是无限的。

如我们所见,Whisper 在客户服务和语言学习平台中的集成提供了巨大的潜力,能够提升用户互动和教育体验。然而,要充分实现这些 ASR 解决方案的好处,优化部署环境至关重要。在下一部分,我们将探讨如何通过优化部署环境来显著提高使用 Whisper 构建的 ASR 解决方案的性能、效率和可扩展性,从而确保企业和教育机构能够充分利用这项强大技术的潜力。

优化部署基于 Whisper 构建的 ASR 解决方案的环境

像 Whisper 这样的 ASR 解决方案的部署代表了人机交互的新前沿,展示了一个未来的可能性:技术以前所未有的准确性和效率理解并响应我们的需求。像 OpenAI 的 Whisper 这样的 ASR 系统可以通过提供更加自然和直观的人机沟通方式,革新各个行业。然而,这些系统在现实应用中的真正效能,往往依赖于一个关键方面,而这一点在开发的兴奋中常常被忽视:优化部署环境。

优化部署环境以运行像 Whisper 这样的 ASR 解决方案尤为重要。Whisper 本质上是一个最先进的 ASR 模型,利用深度学习将语音从音频准确转录成文本。尽管其功能令人印象深刻,但 Whisper 在实际操作中的性能和效率取决于其部署环境。这时,类似于优化深度学习模型在不同硬件上性能的工具所使用的优化原则变得至关重要。优化部署环境对 ASR 解决方案(如 Whisper)的整体性能、效率和可用性至关重要,原因如下:

  • 计算效率和资源利用率:部署 ASR 解决方案时,计算效率是首要考虑因素之一。ASR 模型计算密集型,需要大量的处理能力来分析音频数据,并实时或接近实时地生成准确的转录文本。资源利用率低效可能导致瓶颈、增加运营成本,并且由于转录延迟或不准确,降低用户体验。优化部署环境能够确保 ASR 模型充分利用可用硬件,提升性能并减少延迟。

  • 可扩展性和灵活性:优化部署环境的另一个关键方面是可扩展性。ASR 解决方案通常在需求可变的情况下部署,从移动设备上的个人用户到处理成千上万并发请求的企业级应用。优化的环境允许动态扩展,在需求波动时调整资源分配,而不影响性能。这种灵活性对维持服务质量和有效管理成本至关重要。

  • 能源效率与可持续性:在今天这个日益关注环保的世界里,能源效率不仅仅是操作成本的问题,更是环境责任的问题。优化 ASR 解决方案的部署环境有助于通过最小化处理所需的能源消耗来推动可持续发展。这一点对于数据中心和基于云的服务尤为重要,因为计算任务的能源足迹已经成为一个日益严重的问题。通过确保像 Whisper 这样的 ASR 模型能够更加高效地运行,组织可以在提供高质量服务的同时减少碳足迹。

尽管某些优化技术的具体细节并未明确提及,但很明显,它们所体现的原则在实现这些好处方面起到了关键作用。这些技术有助于将深度学习模型适配到各种硬件架构,提高其性能和效率。通过采用如模型压缩、精度降低和硬件特定优化等技术,它们能够让 ASR 解决方案即使在较弱的设备上也能更快、更高效地运行。

这种优化方法不仅仅是关于逐步改进,而是关于释放 ASR 技术(如 Whisper)的全部潜力。通过确保这些模型能够在从高端服务器到边缘设备的广泛硬件上高效运行,我们可以扩大语音识别技术的可访问性和适用性。这种技术的民主化为创新应用铺平了道路,以前由于硬件限制,这些应用是无法想象的。

然而,实现这一愿景不仅仅需要先进的算法;它还要求对部署环境进行精心优化。在现实世界应用中部署如此复杂的模型,必须要有一个优化过的环境,以确保性能、效率和可扩展性。这就是OpenVINO发挥作用的地方,它作为一个免费的关键蓝图,帮助优化和部署自动语音识别(ASR)解决方案。

引入 OpenVINO

OpenVINO由英特尔开发,代表着开放视觉推理和神经网络优化。它是一个工具包,旨在加速应用程序和解决方案在各种英特尔硬件上的部署,优化性能。OpenVINO 通过为开发人员提供优化深度学习模型以进行推理的工具,尤其是在英特尔 CPU、GPU 和神经计算棒上的优化来实现这一点。这种优化包括模型压缩、精度降低和利用特定硬件加速。尽管如此,关键问题是,为什么要使用 OpenVINO 优化我们为 Whisper 部署的环境?原因如下:

  • 最大化计算效率:作为高级自动语音识别(ASR)模型,Whisper 需要大量计算资源来处理音频数据并生成准确的转录。OpenVINO 优化这些模型,使其能够更高效地在现有硬件上运行,显著减少计算负载。这种效率对于实时或接近实时处理应用至关重要,延迟可能会降低用户体验。

  • 增强可扩展性:在从个人移动设备到企业级系统等多样环境中部署 ASR 解决方案,需要可扩展性。OpenVINO 使 Whisper 模型能够动态调整以适应不同的需求,而不损失性能。这种可扩展性确保 ASR 解决方案能够有效处理高峰负载,这对于经历变化的使用模式的服务至关重要。

  • 扩展可访问性:通过 OpenVINO 进行优化,改善性能,并使在更广泛设备上部署高级 ASR 解决方案如 Whisper 变得可行。通过降低运行 Whisper 等模型的硬件要求,OpenVINO 使得使用尖端语音识别技术在更广泛领域内成为可能。这种可访问性可以推动辅助技术等领域的创新,使数字服务更具包容性。

  • 简化部署流程:OpenVINO 通过提供支持多种英特尔硬件的统一工具包来简化部署流程。这种流程优化对于希望在不同平台上部署 Whisper 的开发人员尤为有益,确保了一致的性能并减少了管理多个部署环境的复杂性。

OpenVINO 的开源性质是其吸引力和在部署 Whisper 等 ASR 解决方案中实用性的基石。作为英特尔的产品,OpenVINO 得到了全球公司支持的可靠性和创新。然而,它保持了开源项目的灵活性和协作精神。虽然我们不支持英特尔的商业性质,但要认识到 OpenVINO 为技术专业人士提供了一个强大且可靠的基础,使他们能够部署像 Whisper 这样的尖端 ASR 解决方案。工具包在 Apache License 版本 2.0 下的开源许可证允许高度灵活性和协作,使像我们这样的技术专业人士能够在不受单一供应商约束的情况下进行适应和创新。

工具包的全面文档、可用资源和示例证明了其可靠性和对开发成功的承诺。这些资源旨在指导我们优化和部署 AI 模型,确保即使是新手也能实现快速且成功的部署。作为全球公司英特尔的支持进一步增强了工具包的可信度,保证了持续的开发和维护。英特尔的支持不仅限于文档和示例。

OpenVINO 社区是一个充满活力的生态系统,开发者可以在其中互动、分享见解,并保持对最新进展的了解。

根据我的经验,OpenVINO 是那些希望高效部署 Whisper 或其他 ASR 模型的人的一个有吸引力的选择。它的开源特性,加上强大的文档、示例和英特尔的全球支持,为开发者提供了一个坚实的基础。然而,是否选择使用 OpenVINO 应该通过全面评估所有可用选项来做出决策,确保所选解决方案与项目的独特需求和目标相符。

在探索 OpenVINO 的实际示例实现之前,让我们先更好地理解 OpenVINO 如何利用其模型优化器使得像 Whisper 这样的模型在可用硬件上运行得更加高效。

应用 OpenVINO 模型优化器到 Whisper

OpenVINO 模型优化器旨在将来自流行框架(如 TensorFlow 和 PyTorch)的深度学习模型转换为优化后的中间表示IR)格式。此 IR 格式专为在英特尔硬件平台(如 CPU、GPU 和 VPU)上进行高效推理而量身定制。通过将模型优化器应用于 Whisper 模型,我们可以显著加速其性能,减少内存占用,并能够在不牺牲性能的情况下动态调整以应对不同的需求。

那么,这个优化过程在后台是如何工作的呢?模型优化器执行几个重要步骤:

  1. 转换模型:它首先将 Whisper 模型从原始格式(例如 PyTorch)转换为 OpenVINO 的 IR 格式。这涉及分析模型架构、提取参数,并将操作映射到 OpenVINO 支持的原语。

  2. 融合模型层:优化器识别可以合并为单一操作的相邻层,从而减少整体计算开销。例如,连续的卷积层和激活层可以融合。

  3. 折叠常量:它预计算常量表达式并直接将其嵌入到模型图中。这消除了推理过程中冗余的计算,从而节省了宝贵的处理时间。

  4. 剪枝:优化器删除所有不对模型输出有贡献的节点或层,包括无效分支和未使用的操作,从而使得模型更加精简和高效。

  5. 量化:它可以选择性地将模型的权重和激活从浮动点精度转换为更低精度的数据类型,如 INT8。此量化显著减少了内存带宽和存储需求,同时保持了可接受的准确性。

一旦 Whisper 模型经过这些优化步骤,它就可以通过 OpenVINO 的推理引擎进行部署。优化后的模型能够充分利用英特尔的硬件架构,利用指令集扩展和并行处理能力。

将 OpenVINO 模型优化器应用于 Whisper 模型的影响非常显著。它使得在资源受限的边缘设备上实现实时语音识别成为可能,为汽车、医疗保健和智能家居自动化等领域的智能语音界面开辟了新的可能性。

此外,优化后的模型可以通过后训练量化和剪枝进行微调,使开发者能够在准确性和效率之间为特定的应用场景找到完美的平衡。

作为一个实际例子,我们从运行 Google Colab 笔记本 LOAIW_ch06_3_Creating_YouTube_subtitles_with_Whisper_and_OpenVINO.ipynbgithub.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter06/LOAIW_ch06_3_Creating_YouTube_subtitles_with_Whisper_and_OpenVINO.ipynb)开始,探索 OpenVINO 并理解其基础功能。

使用 Whisper 和 OpenVINO 生成视频字幕

在这一部分,我们将带您通过一个交互式演示,测试以下转录流程:我们提供一个 YouTube 链接,并选择转录或翻译音频,并为该视频返回自动生成的字幕。当然,YouTube 已经实现了自动字幕、转录和翻译功能。我们并不是试图复制这些现有功能,而是通过这个实践演示来展示如何在视频中创建和嵌入字幕的技术细节。

首先,我们将导入 Python 库并安装诸如 OpenVINO、transformers 和 Whisper 等依赖项。这些库为处理 AI 模型和语音数据提供了基础。

接下来,我们加载一个预训练的 Whisper 模型。让我们从基础模型开始。然后,我们将使用 OpenVINO 的模型转换工具来优化这些模型,并将结果保存到磁盘,方便以后重用。这个过程会跟踪模型、冻结参数,并转换为 OpenVINO 高效的 IR 格式。

最后,我们将使用优化后的模型构建我们的转录管道,提取视频中的音频,通过 Whisper 的编码器和解码器模型生成文本,并将结果保存为SubRipSRT)字幕文件。我们还可以在一步中将其翻译成英文!

在后台,笔记本会下载视频、分离音频、利用 Whisper 和 OpenVINO 进行快速语音识别,准备 SRT 文件,并可以在原视频上显示字幕。

理解先决条件

我们首先通过以下命令从 GitHub 仓库导入一个名为 utils.py 的辅助 Python 工具模块:


!wget -nv "https://github.com/PacktPublishing/Learn-OpenAI-Whisper/raw/main/Chapter06/utils.py" -O utils.py

该模块包含我们稍后用于预处理和后处理的函数。接下来,我们安装关键的软件依赖项,以便能够处理 AI 模型和语音数据:


%pip install -q cohere openai tiktoken
%pip install -q "openvino>=2023.1.0"
%pip install -q "python-ffmpeg<=1.0.16" moviepy transformers --extra-index-url https://download.pytorch.org/whl/cpu
%pip install -q "git+https://github.com/garywu007/pytube.git"
%pip install -q gradio
%pip install -q "openai-whisper==20231117" --extra-index-url https://download.pytorch.org/whl/cpu

以下是相关方面的更多细节:

  • openvino 模块和 ov 核心对象。

  • Transformers: 一个 Pytorch 库,包含如 Whisper 这样的架构,用于自然语言处理和语音任务。它提供可重用的模型实现。我们依赖它加载预训练的 Whisper 基础模型进行语音识别。

  • python-ffmpeg 用于处理视频输入/输出并从视频中提取音频流。这些音频数据成为我们 Whisper 流水线的输入。它还包含 moviepy,使得在 Python 中编辑和分析视频/音频变得更加简单。

  • Whisper: OpenAI 的语音识别模型包包含模型实现、分词、解码和音频转录的实用函数。这些是我们所需要的关键功能!

  • Pytube: 用于从 YouTube 链接下载视频。它填充了启动每次语音识别运行的初始视频文件。

  • Gradio: 这个程序为我们的互动演示创建了用户界面。它允许用户提供 YouTube URL,并通过网页浏览器选择翻译/转录选项。

通过预先处理导入和依赖项,我们为核心工作流铺平了道路。辅助工具也是一个关键要素;它们封装了可重用的逻辑,使我们的主代码可以专注于 Whisper 集成。

实例化 Whisper 模型

让我们深入到笔记本的核心部分,在那里我们实例化 Whisper 模型。正如我们已经确定的,Whisper 是一个基于变压器的编码器-解码器模型,擅长将音频频谱特征转换为一系列文本标记。这个过程从原始音频输入开始,通过特征提取器转化为 log-Mel 频谱图。然后,变压器编码器接管,编码频谱图并生成一系列编码器隐藏状态。最后,解码器根据之前的标记和编码器的隐藏状态进行自回归预测文本标记。

为了在我们的笔记本中实现这个模型,我们首先选择适合我们需求的模型大小。我们为本教程选择了 Whisper 基础 模型,尽管我们列出的步骤同样适用于 Whisper 系列中的其他模型。通过使用一个名为 model_idwidgets 对象,我们呈现了一个下拉菜单,允许选择不同的模型大小,确保对各种用例的灵活性和定制:


from whisper import _MODELS
import ipywidgets as widgets
model_id = widgets.Dropdown(
 options=list(_MODELS),
 value='base',
 description='Model:',
 disabled=False,
)
model_id

一旦选择了模型大小,我们就加载它并设置为评估模式。这是准备模型进行推理的关键步骤,确保它的表现与训练时一致:


import whisper
model = whisper.load_model(model_id.value, "cpu")
model.eval()
pass

随着我们的进展,我们将把 Whisper 的编码器和解码器转换为 OpenVINO IR,确保我们的模型能够进行高性能推理。正如我们在之前介绍的 OpenVINO IR 框架中提到的那样,IR 专为在 Intel 硬件平台(如 CPU、GPU 和 VPU)上进行高效推理而设计。通过应用 Model Optimizer 到 Whisper 模型,我们可以显著加速其性能、减少内存占用,并根据不同需求动态调整而不影响性能。这个转换过程不仅是技术上的必要性,也是在一个强大的预训练模型和可部署解决方案之间搭建桥梁的转型步骤。

在接下来的步骤中,我们将继续优化我们的管道,并准备进行转录过程。我们将选择推理设备,运行视频转录管道,并在为我们选择的视频生成字幕时见证我们的努力成果。

将模型转换为 OpenVINO IR 格式

笔记本中的下一部分是关于将 Whisper 模型转换为 OpenVINO IR 格式,以便与 OpenVINO 一起实现最佳性能。这个过程涉及将 Whisper 模型的编码器和解码器部分进行转换。转换过程从编码器开始:


mel = torch.zeros((1, 80 if 'v3' not in model_id.value else 128, 3000))
audio_features = model.encoder(mel)
if not WHISPER_ENCODER_OV.exists():
    encoder_model = ov.convert_model(model.encoder, example_input=mel)
    ov.save_model(encoder_model, WHISPER_ENCODER_OV)

使用零张量创建一个示例输入。然后使用ov.convert_model函数将编码器模型转换为 OpenVINO 的 IR 格式。转换后的模型保存到磁盘以备将来使用。

接下来,解码器进行转换。由于解码器具有自回归性质,根据先前预测的令牌和编码器隐藏状态预测下一个令牌,因此这个过程稍微复杂些。为了处理这个问题,覆盖解码器注意力模块和残差块的前向方法以显式存储缓存值:


tokens = torch.ones((5, 3), dtype=torch.int64)
logits, kv_cache = model.decoder(tokens, audio_features, kv_cache=None)
tokens = torch.ones((5, 1), dtype=torch.int64)
if not WHISPER_DECODER_OV.exists():
    decoder_model = ov.convert_model(model.decoder, example_input=(tokens, audio_features, kv_cache))
    ov.save_model(decoder_model, WHISPER_DECODER_OV)

然后使用ov.convert_model函数将解码器转换为 OpenVINO 的 IR 格式,示例输入包括令牌、音频特征和键/值缓存。转换后的解码器模型也保存到磁盘以备将来使用。

将 Whisper 模型转换为 OpenVINO IR 格式后,我们现在准备好准备推理管道。这是一个关键步骤,我们在这一步将转换后的模型集成到一个协调的管道中,该管道将处理音频并生成所需的字幕。

在运行转录管道之前,我们必须选择适当的推理设备。OpenVINO 让我们可以选择如 CPU、GPU 或专用加速器如 VPU 等元素。对于我们的目的,我们将使用AUTO选项,这允许 OpenVINO 自动选择最合适的设备:


core = ov.Core()
device = widgets.Dropdown(
 options=core.available_devices + [AUTO»],
 value='AUTO',
 description='Device:',
 disabled=False,
)
device

通过选择推理设备,我们确保我们的管道针对手头的硬件进行了优化,这对于在推理过程中实现最佳性能至关重要。

使用所选设备,我们为 OpenVINO 推理修补 Whisper 模型。这包括用 OpenVINO 对应部件替换原始的 PyTorch 模型组件:


from utils import patch_whisper_for_ov_inference, OpenVINOAudioEncoder, OpenVINOTextDecoder
patch_whisper_for_ov_inference(model)
model.encoder = OpenVINOAudioEncoder(core, WHISPER_ENCODER_OV, device=device.value)
model.decoder = OpenVINOTextDecoder(core, WHISPER_DECODER_OV, device=device.value)

这个补丁过程至关重要,因为它将 Whisper 模型适配到 OpenVINO 上,从而利用 OpenVINO 运行时的性能优势。

理解 OpenVINO IR 格式

推理模型通常是在多个平台上开发和训练的,可能会非常庞大且依赖于特定架构。为了在任何设备上高效推理并充分利用 OpenVINO 工具,模型可以转换为 OpenVINO IR 格式。

OpenVINO IR 是 OpenVINO 独有的,通过使用 API 进行模型转换生成的。这个过程将广泛使用的深度学习操作转换为 OpenVINO 内部等效的形式,并结合了原始训练模型的必要权重和偏置。转换过程会生成两个关键文件,这些文件具有以下文件扩展名:

  • .xml - 概述了模型的结构。

  • .bin - 存储模型的权重和二进制信息。

XML 文件通过 <layer> 标签概述了模型的结构,表示操作节点,并通过 <edge> 标签表示数据流之间的连接。每个操作节点都详细列出了指定操作特征的属性。例如,卷积操作的属性包括 dilation(膨胀),stride(步幅),pads_begin(开始填充)和 pads_end(结束填充)。

大的常数值,例如卷积权重,并不会直接存储在 XML 文件中。相反,这些值会引用二进制文件中的一个部分,并以二进制形式存储。

运行视频转录管道

现在,我们已经准备好进行视频转录。我们首先从 YouTube 选择一个视频,下载它并提取音频。图 6.1 展示了使用 Whisper 模型的视频转录管道:

图 6.1 – 运行视频转录管道

图 6.1 – 运行视频转录管道

一旦提供了视频 URL,代码将自动下载视频并保存到本地文件系统。下载的视频文件将作为转录管道的输入。根据视频长度和网络速度,这个过程可能需要一些时间:


from pytube import YouTube
from pathlib import Path
print(f"Downloading video {link.value} started")
output_file = Path("downloaded_video.mp4")
yt = YouTube(link.value)
yt.streams.get_highest_resolution().download(filename=output_file)
print(f"Video saved to {output_file}")

一旦我们获得了音频,就可以选择模型的任务(转录或翻译内容):


task = widgets.Select(
 options=["transcribe", "translate"],
 value="translate",
 description="Select task:",
 disabled=False
)
task

选择任务后,我们调用 model.transcribe 方法来执行转录:


transcription = model.transcribe(audio, task=task.value)

转录结果将以 SRT 文件格式呈现,这是一个广泛使用的字幕格式,兼容许多视频播放器。这个文件可以在播放视频时将转录内容嵌入视频中,或者使用如 ffmpeg 等工具将其直接集成到视频文件中:


from utils import prepare_srt
srt_lines = prepare_srt(transcription, filter_duration=duration)
# save transcription
with output_file.with_suffix(".srt").open("w") as f:
 f.writelines(srt_lines)
print("".join(srt_lines))

最后,我们可以查看带有生成字幕的视频,以验证转录管道的准确性和同步性:


import gradio as gr
def video_with_srt(t_video, t_srt):
    return t_video, t_srt
demo = gr.Interface(
    fn=video_with_srt,  # Pass the function reference
    inputs=[
        gr.Textbox(label=»Video File Path»),
        gr.Textbox(label=»SRT File Path»)
    ],
    outputs="video",
    examples=[[‹downloaded_video.mp4›, ‹downloaded_video.srt›]],
    allow_flagging=»never»
)
try:
    demo.launch(debug=True)
except Exception as e:
    print(e)
    demo.launch(share=True, debug=True)

通过这些步骤,我们成功地驾驭了使用 OpenAI 的 Whisper 和 OpenVINO 搭建高效视频转录管道的复杂过程。此过程展示了 AI 在理解和处理人类语言方面的强大能力,并展示了此类技术在创建可访问内容中的实际应用。

摘要

我们的旅程已接近尾声。本章精心设计,旨在指导你通过使用 Whisper 处理多种任务的细致过程,强调在多个语言和方言中的转录精准度,与数字平台的集成以提升内容可访问性,以及创新地利用 Whisper 改善客户服务体验和教育内容传递。

旅程从深入探讨精确转录开始,我们在此过程中了解了 Whisper 在处理多语言转录方面的能力。本节突出了该技术对不同语言的适应性,展示了 Whisper 如何针对特定语言需求进行微调,从而扩大了其在全球平台上的适用范围。

我们还学会了如何利用 PyTube 作为一种新兴的战略方法,将 YouTube 内容与 Whisper 集成,重点介绍了下载和转录视频的过程。这一整合有助于访问大量信息库,并展示了 Whisper 在处理和转录来自不同来源的音频时的强大能力。

为了提高可发现性而对内容进行索引,我们将重点转向了转录音频和视频内容在 SEO 方面的好处。通过将口语转化为可搜索的文本,本节展示了 Whisper 如何显著影响内容的可见性和可访问性,使其成为内容创作者和营销人员提升数字足迹的关键工具。

利用 FeedParser 和 Whisper,我们进一步拓展了创建可搜索文本的探索,特别是针对播客内容。这个创新的组合为弥合音频内容与基于文本的搜索之间的鸿沟提供了解决方案,提供了关于如何将播客转录以改善 SEO 和观众互动的见解。

本章的一个关键方面是探索了使用 Whisper 进行近实时转录,承认了在实现即时转录需求方面的挑战和未来潜力。尽管实时转录代表了一个不断发展的前沿,但本章为理解当前的能力和局限性奠定了基础,为未来在这一领域的进展铺平了道路。

随着本章的结束,你现在已经具备了对 Whisper 当前应用的全面理解,并窥见了语音技术未来的潜在方向。通过所提供的笔记本完成的基础工作,展示了所讨论概念的实际应用,强化了学习体验。

展望未来,第七章预示着这次探索的激动人心的延续。它旨在深入研究 Whisper 量化以及使用 Whisper 进行近实时转录的可能性。下一章将为你提供知识和工具,进一步利用语音技术的进展,推动 Whisper 的潜力,开启语音识别和处理领域的突破性应用。

第七章:探索高级语音功能

欢迎来到第七章,在这里我们将开始一段激动人心的旅程,探索 OpenAI Whisper 的高级语音功能。本章将深入探讨提升 Whisper 性能的技术,例如 量化,并揭示其在实时语音识别中的潜力。

我们首先检查量化的力量,这是一种在保持准确性的同时减少模型大小和计算要求的技术。您将学习如何通过使用 CTranslate2Open Visual Inference and Neural Network OptimizationOpenVINO)等框架将量化应用于 Whisper,从而在资源受限的设备上实现高效部署。

在上一章中,我们简要讨论了使用 Whisper 实现实时 ASR(自动语音识别)面临的挑战,而在本章中,我们将深入探讨当前的局限性以及正在进行的研究工作,以使实时转录成为现实。我们将探索使用 Whisper 和 Gradio 构建流式 ASR 演示的实验性方法,并提供实际示例,展示 Whisper 在实时语音识别中的潜力。

在本章中,我们将涵盖以下主要内容:

  • 利用量化的力量

  • 面对实时语音识别的挑战与机遇

到本章结束时,您将深入了解优化 Whisper 性能的高级技术,理解实时语音识别的潜力与挑战。您将掌握实用的知识和动手经验,将这些技术应用到您的项目中,突破 Whisper 的应用边界。

那么,让我们解锁 Whisper 高级语音功能的全部潜力,使您能够构建创新应用,改变我们在数字世界中与语言互动的方式。

技术要求

为了利用 OpenAI Whisper 的功能进行高级应用,本章使用 Python 和 Google Colab,旨在简化使用和提高可访问性。Python 环境设置包括用于转录任务的 Whisper 库。

关键要求

  • Google Colab 笔记本:这些笔记本已经设置好,以最小所需的内存和计算能力运行我们的 Python 代码。如果 T4 GPU 运行时类型可用,请选择它以获得更好的性能。

  • Python 环境:每个笔记本都包含加载所需 Python 库的指令,包括 Whisper 和 Gradio。

  • Hugging Face 账户:某些笔记本需要 Hugging Face 账户和登录 API 密钥。Colab 笔记本中包含有关此主题的信息。

  • 麦克风和扬声器:一些笔记本实现了一个 Gradio 应用,支持语音录制和音频播放。连接到计算机的麦克风和扬声器可以帮助你体验交互式语音功能。另一种选择是通过手机打开 Gradio 在运行时提供的 URL 链接;在那里,你可以使用手机的麦克风录制语音。

  • GitHub 仓库访问:所有 Python 代码,包括示例,都可以在本章的 GitHub 仓库中找到(github.com/PacktPublishing/Learn-OpenAI-Whisper/tree/main/Chapter07)。这些 Colab 笔记本已准备好运行,提供了一个实践性强、动手操作的学习方法。

通过满足这些技术要求,你将能够在不同的环境中探索 Whisper,同时享受 Google Colab 提供的流畅体验和 GitHub 上的全面资源。

随着我们深入了解 Whisper 的高级功能,我们必须探索一些技术,以优化其性能和效率。量化就是其中一个备受关注的技术。在这一部分中,我们将探索量化的强大功能,以及如何利用它来提升 Whisper 的部署能力。

利用量化的强大功能

机器学习中的量化,特别是在 ASR 中,指的是减少模型参数的精度。通常,通过将连续的浮点值范围映射到一个离散的值集合,通常是整数,来实现量化。量化的主要目标是减少模型的计算复杂性和内存占用,这对于将 ASR 系统部署到资源有限的设备(如手机或嵌入式系统)上至关重要。量化具有以下几个重要作用:

  • 减小模型尺寸:使用低精度表示模型的权重可以显著减小模型的整体尺寸。这对于设备端部署尤为重要,因为设备的存储空间有限。

  • 提高推理速度:在许多硬件平台上,低精度算术运算比高精度运算更快,特别是那些没有专用浮点单元的硬件。这可以加快推理时间,对于实时应用(如自动语音识别 ASR)至关重要。

  • 提高能效:量化后的模型需要更少的计算资源,从而降低功耗。这对于电池供电的设备至关重要。

  • 扩展硬件兼容性:许多边缘设备对整数计算进行了优化。量化使得模型能够利用这些硬件优化。

在 ASR 中,一些标准的机器学习量化技术包括 向量量化VQ)、int8 量化低比特量化。我们简要描述每一种技术:

VQ 是一种经典的技术,广泛应用于包括语音编码和识别在内的各个领域。它涉及将向量从一个充足的向量空间映射到有限数量的区域,这些区域可以用更少的比特有效表示。VQ 已经成功应用于语音识别系统,通过有效压缩特征空间来提高性能。

INT8 量化 是一种最近的方法,通过使用 8 位整数代替 32 位浮点数来表示模型的权重和激活。这种方法可以在不显著降低性能的情况下,将模型大小缩小 4 倍,因为它在类型之间进行精确的四舍五入,而不是简单地截断数据。

随着进一步的进展,出现了低比特量化技术,探索了甚至为 1 位的激进量化。尽管这可以显著减少存储和运行时,但可能会增加词错误率WER)在 ASR 任务中的表现。然而,通过精心设计,例如 DistilHuBERT(huggingface.co/ntu-spml/distilhubert),可以实现模型压缩,同时保持最小的准确度损失。

请注意,量化会引入量化误差,如果管理不当,可能会降低模型的性能。为减轻这些影响,已经开发了如量化感知训练QAT)和训练后量化PTQ)等技术。QAT 在训练过程中模拟量化过程,使模型能够适应较低的精度。另一方面,PTQ 在训练后应用量化,使用校准技术调整量化参数,以实现最小的性能损失。

图 7.1 显示了 ASR 模型的量化过程的高层次视图:

图 7.1 – ASR 模型的量化过程

图 7.1 – ASR 模型的量化过程

图中大致概述的步骤是通用的,旨在提供基础概览。让我们更详细地回顾每个步骤:

  1. 准备:初始步骤是使用高精度(32 位浮点)表示法训练 ASR 模型。这确保了模型捕捉到准确语音识别所需的复杂模式。

  2. int8),甚至更低。你的选择应考虑模型大小、计算效率和准确性。

    比特深度的选择直接影响模型大小、计算速度和准确度之间的权衡。较低的比特深度显著减少模型的内存占用并提高计算效率,但它们可能引入量化误差,从而可能降低模型性能。挑战在于选择一个最佳的比特深度,既能最小化这些误差,又能实现所需的效率提升。

  3. 校准:使用一个代表性的数据集通过模型进行推理以进行 PTQ。此步骤有助于收集激活值的分布统计信息,这对于确定量化参数至关重要。

  4. 权重和激活量化:使用收集到的统计信息,将模型的权重和激活量化到选定的位深度。这涉及使用比例因子和零点将高精度值映射到较低精度的空间。

  5. QAT(可选):在某些情况下,模型会进行 QAT,即在训练过程中模拟量化效果。这有助于模型适应降低的精度,从而可能减轻准确度损失。

  6. 测试与微调:量化后,评估模型的性能,以确保准确度保持在可接受范围内。如有必要,进行微调或调整量化参数。

  7. 部署:量化后的模型被部署到目标硬件上,受益于减少的内存使用和更快的推理时间。这使得它适用于边缘设备或计算资源有限的环境。

有多个量化版本的 Whisper 可用,并且更多版本正在开发中。根据我的经验,我发现 Faster-Whisper 和 Distil-Whisper 提供了更优越且可靠的性能。以下是它们的简要描述:

  • Faster-Whisper在 CTranslate2 中实现了 Whisper 模型,这是一个用于高效推理 Transformer 模型的库。它通过各种方法提高效率,如权重量化、层融合和批量重排序。量化在 Faster-Whisper 中发挥了重要作用,通过减少模型的内存占用和加速推理,特别是在 GPU 上。我们将在使用 WhisperX 和 NVIDIA 的 NeMo 进行语音分离章节中体验 Faster-Whisper,因为 WhisperX 使用 Faster-Whisper 进行语音转文本STT)转录。

  • small.enmedium.enlarge-v2模型,它们在保持相当 WER 的同时更快且更小。量化可以进一步提高 Distil-Whisper 的效率,通过减少模型参数的精度,从而实现更快的处理速度和更低的内存需求。

在我们探索量化的强大功能时,让我们通过使用 CTranslate2 框架来深入了解一个实际示例。CTranslate2 提供了一种高效的方式来量化和优化 Whisper 模型,以便在资源受限的设备上部署。

使用 CTranslate2 量化 Whisper 并通过 Faster-Whisper 进行推理

请查找并打开LOAIW_ch07_1_Quantizing_Whisper_with_CTranslate2.ipynb Colab 笔记本(github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter07/LOAIW_ch07_1_Quantizing_Whisper_with_CTranslate2.ipynb)。该笔记本演示了如何使用 CTranslate2 和 Faster-Whisper 框架来加载量化模型并进行推理(转录或翻译)。你应先在 CPU 上运行笔记本,然后在 GPU 上运行。由于我们使用的是小型 Whisper 模型、短音频文件和量化,CPU 性能应该相对较快。图 7.2提供了量化过程的概览,从准备音频数据、转换和量化模型,到评估其在语言检测和转录任务中的表现。量化在优化模型以适应资源受限的环境中至关重要,它使得语音识别能力高效且准确:

图 7.2 – 使用 CTranslate2 框架量化 Whisper 过程的高层视图

图 7.2 – 使用 CTranslate2 框架量化 Whisper 过程的高层视图

以下步骤概述了量化过程。有关完整的端到端实现,请参考LOAIW_ch07_1_Quantizing_Whisper_with_CTranslate2.ipynb笔记本。本节将展示高层步骤和选定的代码片段来说明该过程。请记住,笔记本中包含了额外的细节和解释,帮助你全面理解量化工作流。以下是该过程的详细分解:

  1. ctranslate2transformersfaster-whisper

    !pip install ctranslate2
    !pip install transformers[torch]>=4.23
    !pip install faster-whisper
    

    这些库对于量化以及充分利用 Whisper 模型的能力至关重要。

  2. 下载示例音频文件:从我们的 GitHub 仓库下载两个文件,用于测试 Whisper 模型的转录能力:

    !wget -nv https://github.com/PacktPublishing/Learn-OpenAI-Whisper/raw/main/Chapter01/Learn_OAI_Whisper_Sample_Audio01.mp3
    librosa:
    
    

    导入 ctranslate2

    从 IPython.display 导入 Audio

    导入 librosa

    导入 transformers

    加载并重采样音频文件。

    sampling_frequency = 16000

    audio, _ = librosa.load("Learn_OAI_Whisper_Sample_Audio01.mp3", sr=sampling_frequency, mono=True)

    Audio(audio, rate=sampling_frequency)

    
    This step is crucial for ensuring that the audio data is in the correct format for processing by the Whisper model.
    
  3. openai/whisper-tiny) 被转换为 CTranslate2 格式,这是一种更高效的推理格式:

    ct2-transformers-converter command converts models to the CTranslate2 format, optimized for fast inference. The core CTranslate2 implementation is framework-agnostic. The framework-specific logic is moved to a conversion step that loads supported models into a unified representation. The weights are then optionally quantized and saved into an optimized binary format for efficient storage and processing.When converting models using the CTranslate2 tool, the output directory typically contains several key files for the CTranslate2 engine to load and run the model. The command streamlines the process of preparing models for deployment in environments where computational efficiency is crucial and a preparatory step for quantization. While the exact output files can vary depending on the specific model being converted and the options used during conversion, standard files include the following:*   `config.json`: This JSON file contains configuration information about the model, such as its architecture, the size of its layers, and other hyperparameters. This information is crucial for the CTranslate2 engine to interpret the model’s binary weights and perform inference correctly.*   `model.bin`: This is the binary file containing the quantized weights of the model. Quantization reduces the precision of the model’s weights, which can significantly decrease the model size and improve inference speed, often with minimal impact on accuracy.*   `vocabulary.json` or similar vocabulary files (for example, `source.spm` and `target.spm` for models using `SentencePiece` tokenization): These files contain the mapping between tokens (words or subwords) and their corresponding indices in the model’s vocabulary. This mapping is essential for converting input text into a format that the model can process (tokenization) and converting the model’s output back into human-readable text (detokenization).These files represent the converted and optimized model and are ready for use with CTranslate2\. The conversion process might also include copying additional files necessary for the model’s operation, such as tokenization configuration (`tokenizer_config.json`), special tokens mapping (`special_tokens_map.json`), and others, depending on the model’s requirements and the conversion options you use.
    
  4. INT8):

    !ct2-transformers-converter --force --model openai/whisper-tiny --output_dir whisper-tiny-ct2-int8 \
    INT8)
    
  5. 16 位整数(INT16

  6. 16 位浮动点(FP16

  7. 16 位大脑浮动点(BF16

这一步显著减少了模型的大小和计算需求,使其更适合在资源有限的设备上部署。

  1. 检测语言:量化模型检测所提供音频样本的语言:

    # Detect the language.
    results = model.detect_language(features)
    language, probability = results[0][0]
    print("Detected language %s with probability %f" % (language, probability))
    

    这一步对于确保模型准确理解音频数据的上下文非常重要。

  2. processor.tokenizer.convert_tokens_to_ids()方法:

    prompt = processor.tokenizer.convert_tokens_to_ids(
        [
            "<|startoftranscript|>",
            language,
            "<|transcribe|>",
            "<|notimestamps|>",  # Remove this token to generate timestamps.
        ]
    )
    # Load the model on device
    model = ctranslate2.models.Whisper("whisper-tiny-ct2-int8", device=this_device)
    # Run generation for the 30-second window.
    results = model.generate(features, [prompt])
    transcription = processor.decode(results[0].sequences_ids[0])
    print(transcription))
    

    这展示了模型即使在量化后也能准确转录语音的能力。

  3. 评估性能:音频转录后,代码评估量化后模型的性能,如测量转录所用的时间:

    # Print the end time and the delta in seconds and fractions of a second.
    end = time.time()
    print('start: ', start)
    print('end: ', end)
    print('delta: ', end - start)
    print('delta: ', datetime.timedelta(seconds=end - start))
    

    这一评估对于了解量化对模型效率和准确性的影响至关重要。

结果显示了实证证据,表明量化后的 Whisper 模型能够以更小的内存和处理足迹进行良好的转录。基于我们对量化的理解,让我们现在集中研究另一个强大的框架——OpenVINO。我们将探讨 OpenVINO 如何用于量化 Distil-Whisper 模型,提供一个更加全面和严格的量化过程。

使用 OpenVINO 量化 Distil-Whisper

这个实践练习依赖于LOAIW_ch07_2_Quantizing_Distil_Whisper_with_OpenVINO.ipynb Colab 笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter07/LOAIW_ch07_2_Quantizing_Distil_Whisper_with_OpenVINO.ipynb)。由于 OpenVINO 的原因,我建议你在 Colab 中使用 CPU 和大内存运行此笔记本。即使存在 NVIDIA GPU,OpenVINO 也不会使用它,仅使用 Intel GPU。不过,OpenVINO 提供的库经过优化,可以在普通 CPU 上运行,因此在计算处理资源有限时,这也是一个显著的优势。然而,进行量化时你至少需要 50GB 的内存。该笔记本提供了利用 Distil-Whisper(基于 WhisperX),一个经过蒸馏的 Whisper 模型变体,与 OpenVINO 结合用于自动语音识别(ASR)的全面指南。Distil-Whisper 大大减少了参数数量(从large-v2中的 1,550 个参数减少到distill-large-v2中的 756 个参数,约减少 50%),并在保持与原始 Whisper 模型在 WER(字错误率)方面相近性能的同时,提高了推理速度。

图 7.3概述了将 Distil-Whisper 模型转换为 OpenVINO 中间表示IR)格式,应用 INT8 PTQ 以提高性能,并运行模型进行语音识别任务:

图 7.3 – 使用 OpenVINO 框架量化 Distil-Whisper 的高层架构图

图 7.3 – 使用 OpenVINO 框架量化 Distil-Whisper 的高层架构图

以下子章节将描述使用 OpenVINO 框架量化 Distil-Whisper 模型的关键步骤。我们将安装必要的库,加载模型,将其转换为 OpenVINO 格式,并应用量化。我们还将探索如何使用 Optimum 库加载量化后的模型,并将其与 Hugging Face 管道集成。最后,我们将使用量化后的模型进行推理,并将其性能和准确性与原始模型进行比较。

安装库

首先,过程指导安装必要的 Python 库:

%pip install -q "transformers>=4.35" onnx "git+https://github.com/huggingface/optimum-intel.git" "peft==0.6.2" --extra-index-url https://download.pytorch.org/whl/cpu
%pip install -q "openvino>=2023.2.0" datasets  "gradio>=4.0" "librosa" "soundfile"
%pip install -q "nncf>=2.6.0" "jiwer"

让我们更详细地查看每个库,重点介绍那些我们之前没有描述过的库:

  • Transformers:这个库用于处理自然语言处理任务,如文本分类、信息抽取和问答。它提供了访问预训练模型的功能,如 BERT、GPT-2,以及在本例中用于 ASR 的 Distil-Whisper 模型。

  • Open Neural Network Exchange (ONNX):ONNX 是一个开放格式,用于表示机器学习模型。它使模型能够在不同的框架和工具之间转移,促进了互操作性。

  • Optimum Intel:这是 Hugging Face Optimum 库的一部分,专为 Intel 硬件量身定制。它将模型转换为 OpenVINO IR 格式,这种格式经过针对 Intel 硬件的优化,并执行如量化等任务,以提高模型性能。

  • OpenVINO:OpenVINO 工具包旨在促进在 Intel 硬件上快速高效地进行深度学习模型推理。它包括优化工具和库,用于加速各种计算机视觉和深度学习任务。

  • Datasets:这是 Hugging Face 生态系统的一部分,用于简单高效地加载和处理数据集。它对于需要处理大量数据的机器学习任务非常有用。

  • Soundfile:这个库提供了从音频文件读取和写入多种格式的功能。它处理音频数据的输入输出操作。

  • 神经网络压缩框架(NNCF):这是一个通过量化、剪枝和知识蒸馏优化深度学习模型的工具包。它提高了神经网络的性能,特别是在推理速度和内存使用方面。

  • JiWER:这是一个用于评估自动语音识别模型的库。它计算诸如 WER(词错误率)等指标,这是评估语音识别系统性能的标准方法。

每个库在运行和优化 Distil-Whisper 模型时都扮演着特定的角色,从模型转换和优化到性能评估和用户界面创建。

加载模型

在使用 transformers 库初始化 PyTorch Whisper 模型时,AutoModelForSpeechSeq2Seq.from_pretrained 方法是常用的方法:

from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq
processor = AutoProcessor.from_pretrained(model_id.value)
pt_model = AutoModelForSpeechSeq2Seq.from_pretrained(model_id.value)
pt_model.eval();

本教程将使用 distil-whisper/distil-medium.en 模型作为主要示例。值得注意的是,该模型在第一次运行时需要下载,可能需要一些时间。

如果你想探索其他模型,Distil-Whisper Hugging Face 集合提供了如 distil-whisper/distil-large-v2distil-whisper/distil-small.en 等选项。基于原始 Whisper 架构的其他模型也有提供,你可以在提供的资源中找到更多信息。

强调预处理和后处理在此模型使用中的重要性至关重要。AutoProcessor类用于初始化WhisperProcessor,它在为模型准备音频输入数据时发挥了至关重要的作用。它负责将音频转换为 Mel-谱图,并使用分词器将预测的token_ids输出解码回字符串。

通过利用AutoModelForSpeechSeq2Seq.from_pretrained方法,并了解预处理和后处理步骤,你将能够有效地与 PyTorch Whisper 模型进行工作。

使用 Optimum 库加载 OpenVINO 模型

Hugging Face Optimum API 是一个强大的工具,可以简化将 Hugging Face Transformers 库中的模型转换和量化为 OpenVINO™ IR 格式的过程。如果你想了解更多深入的信息,Hugging Face Optimum 文档是一个很好的资源。

Optimum Intel 是加载来自 Hugging Face Hub 的优化模型并创建用于 OpenVINO Runtime 推理的管道时的好伙伴。Optimum 推理模型的一个优点是它们与 Hugging Face 的transformers模型 API 兼容。你可以毫不费力地将AutoModelForXxx类替换为相应的OVModelForXxx类:

# Using HF transformers models
from transformers import AutoModelForSpeechSeq2Seq
from transformers import AutoTokenizer, pipeline
model_id = "distil-whisper/distil-large-v2"
model = AutoModelForSpeechSeq2Seq.from_pretrained(model_id)
# Using Optimum Inference models
from optimum.intel.openvino import OVModelForSpeechSeq2Seq
from transformers import AutoTokenizer, pipeline
model_id = "distil-whisper/distil-large-v2"
model = OVModelForSpeechSeq2Seq.from_pretrained(model_id, export=True)

你需要调用from_pretrained方法来初始化模型类。在下载和转换transformers模型时,包含export=True参数。这将确保平稳的转换过程。一旦你获得转换后的模型,就可以使用save_pretrained方法保存它:

from pathlib import Path
from optimum.intel.openvino import OVModelForSpeechSeq2Seq
model_path = Path(model_id.value.replace('/', '_'))
ov_config = {"CACHE_DIR": ""}
if not model_path.exists():
    ov_model = OVModelForSpeechSeq2Seq.from_pretrained(
        model_id.value, ov_config=ov_config, export=True, compile=False, load_in_8bit=False
    )
    ov_model.half()
    ov_model.save_pretrained(model_path)
else:
    ov_model = OVModelForSpeechSeq2Seq.from_pretrained(
        model_path, ov_config=ov_config, compile=False
    )

值得一提的是,随模型分发的分词器和处理器也与 OpenVINO 模型兼容。这种兼容性允许你重复使用之前初始化的处理器,节省时间和精力。

使用 Hugging Face Optimum 库,我们还可以将 Distil-Whisper 模型转换为 OpenVINO 的优化 IR 格式。这一步骤对于利用 OpenVINO 的推理引擎来高效执行模型至关重要:

-from transformers import AutoModelForSpeechSeq2Seq
+from optimum.intel.openvino import OVModelForSpeechSeq2Seq
from transformers import AutoTokenizer, pipeline
model_id = "distil-whisper/distil-large-v2"
-model = AutoModelForSpeechSeq2Seq.from_pretrained(model_id)
+model = OVModelForSpeechSeq2Seq.from_pretrained(model_id, export=True)

通过利用 Hugging Face Optimum API 和 Optimum Intel,你可以高效地转换和量化模型,加载优化后的模型,并创建用于 OpenVINO Runtime 推理的管道。API 兼容性以及能够重复使用初始化处理器的能力,使得整个过程更加简化。

使用 OpenVINO 模型与 Hugging Face 管道

通过将 OpenVINO 模型与 Hugging Face 管道接口结合,并利用 Distil-Whisper 的分块算法和批处理能力,你将能够以前所未有的速度和轻松度处理长时间的音频转录任务。

与原始的 PyTorch 模型一样,OpenVINO 模型与 Hugging Face 的 ASR 管道接口完美集成。这种兼容性使得你可以轻松地使用管道转录长时间的音频文件:

from transformers import pipeline
ov_model.generation_config = pt_model.generation_config
pipe = pipeline(
    "automatic-speech-recognition",
    model=ov_model,
    tokenizer=processor.tokenizer,
    feature_extractor=processor.feature_extractor,
    max_new_tokens=128,
    chunk_length_s=15,
    batch_size=16,
)

Distil-Whisper 通过采用分块算法将其推向更高级别,显著加快了长形音频的转录过程。这种分块长形算法比 OpenAI 在其 Whisper 论文中提出的顺序算法快了惊人的九倍(cdn.openai.com/papers/whisper.pdf)。

要利用分块的优势,您只需将chunk_length_s参数传递给管道即可。在使用 Distil-Whisper 时,将块长度设置为15秒是达到最佳性能的甜蜜点。但这还不是全部!如果您想利用批处理的能力,在调用管道时包括batch_size参数。这将使您能够同时处理多个音频块,进一步提升转录工作流的效率。

量化模型

量化是一种强大的技术,可以显著减少模型大小并提高推断速度。NNCF 使得实现 PTQ 变得比以往任何时候都更加简单。通过无缝集成量化层到模型图中,并利用训练数据集的子集来初始化这些额外层的参数,NNCF 确保对您原始训练代码的修改是最小的。

踏上优化之旅的第一步是创建专门为量化量身定制的校准数据集:

%%skip not $to_quantize.value
from itertools import islice
from optimum.intel.openvino.quantization import InferRequestWrapper
def collect_calibration_dataset(ov_model: OVModelForSpeechSeq2Seq, calibration_dataset_size: int):
    # Overwrite model request properties, saving the original ones for restoring later
    original_encoder_request = ov_model.encoder.request
    original_decoder_with_past_request = ov_model.decoder_with_past.request
    encoder_calibration_data = []
    decoder_calibration_data = []
    ov_model.encoder.request = InferRequestWrapper(original_encoder_request, encoder_calibration_data)
    ov_model.decoder_with_past.request = InferRequestWrapper(original_decoder_with_past_request,
                                                             decoder_calibration_data)
    calibration_dataset = load_dataset("librispeech_asr", "clean", split="validation", streaming=True)
    for sample in tqdm(islice(calibration_dataset, calibration_dataset_size), desc="Collecting calibration data",
                       total=calibration_dataset_size):
        input_features = extract_input_features(sample)
        ov_model.generate(input_features)
    ov_model.encoder.request = original_encoder_request
    ov_model.decoder_with_past.request = original_decoder_with_past_request
    return encoder_calibration_data, decoder_calibration_data

由于 Whisper 编码器和解码器是分别量化的,为每个模型准备一个校准数据集至关重要。这就是InferRequestWrapper类发挥作用的地方。导入此类,您可以拦截并收集模型输入到列表中。然后,您将在少量音频样本上运行模型推断。请记住,增加校准数据集的大小通常会导致更好的量化质量,因此值得尝试找到适当的平衡。

一旦准备好校准数据集,就是时候释放nncf.quantize的力量了。这个函数是获得量化编码器和解码器模型的关键。在 Distil-Whisper 的情况下,您将在encoderdecoder_with_past模型上运行nncf.quantize。值得注意的是,第一步解码器因其对整体推断时间的贡献微不足道而未被量化:

%%skip not $to_quantize.value
import gc
import shutil
import nncf
CALIBRATION_DATASET_SIZE = 50
quantized_model_path = Path(f"{model_path}_quantized")
def quantize(ov_model: OVModelForSpeechSeq2Seq, calibration_dataset_size: int):
    if not quantized_model_path.exists():
        encoder_calibration_data, decoder_calibration_data = collect_calibration_dataset(
            ov_model, calibration_dataset_size
        )
        print("Quantizing encoder")
        quantized_encoder = nncf.quantize(
            ov_model.encoder.model,
            nncf.Dataset(encoder_calibration_data),
            subset_size=len(encoder_calibration_data),
            model_type=nncf.ModelType.TRANSFORMER,
            # Smooth Quant algorithm reduces activation quantization error; optimal alpha value was obtained through grid search
            advanced_parameters=nncf.AdvancedQuantizationParameters(smooth_quant_alpha=0.50)
        )
        ov.save_model(quantized_encoder, quantized_model_path / "openvino_encoder_model.xml")
        del quantized_encoder
        del encoder_calibration_data
        gc.collect()
        print("Quantizing decoder with past")
        quantized_decoder_with_past = nncf.quantize(
            ov_model.decoder_with_past.model,
            nncf.Dataset(decoder_calibration_data),
            subset_size=len(decoder_calibration_data),
            model_type=nncf.ModelType.TRANSFORMER,
            # Smooth Quant algorithm reduces activation quantization error; optimal alpha value was obtained through grid search
            advanced_parameters=nncf.AdvancedQuantizationParameters(smooth_quant_alpha=0.95)
        )
        ov.save_model(quantized_decoder_with_past, quantized_model_path / "openvino_decoder_with_past_model.xml")
        del quantized_decoder_with_past
        del decoder_calibration_data
        gc.collect()
        # Copy the config file and the first-step-decoder manually
        shutil.copy(model_path / "config.json", quantized_model_path / "config.json")
        shutil.copy(model_path / "openvino_decoder_model.xml", quantized_model_path / "openvino_decoder_model.xml")
        shutil.copy(model_path / "openvino_decoder_model.bin", quantized_model_path / "openvino_decoder_model.bin")
    quantized_ov_model = OVModelForSpeechSeq2Seq.from_pretrained(quantized_model_path, ov_config=ov_config, compile=False)
    quantized_ov_model.to(device.value)
    quantized_ov_model.compile()
    return quantized_ov_model
ov_quantized_model = quantize(ov_model, CALIBRATION_DATASET_SIZE)

代码片段显示,最后一步是在量化后使用openvino.save_model函数序列化 INT8 模型。此步骤确保您的量化模型已准备好部署,并可以快速加载进行推断。

重要的是要记住,量化是一种计算密集型操作,可能既耗时又消耗内存。运行量化代码可能需要耐心,但模型尺寸减小和推断速度提高的好处使其绝对值得努力。

通过遵循这些步骤并利用 NNCF 的强大功能,您可以通过 PTQ 优化模型,从而实现更快、更高效的推理。

运行推理

这里,我们展示了如何使用量化模型进行推理,包括加载模型、准备输入样本以及执行模型进行语音转录。以下是详细步骤:

  1. 来自 Hugging Face 的librispeech_asr_dummy,出自datasets库:

    %%skip not $to_quantize.value
    dataset = load_dataset(
        "hf-internal-testing/librispeech_asr_dummy", "clean", split="validation"
    )
    sample = dataset[0]
    
  2. numpy数组格式转换为模型可以处理的张量:

    input_features = extract_input_features(sample)
    predicted_ids = ov_model.generate(input_features)
    
  3. 在原始模型上运行推理:使用原始 OpenVINO 模型生成输入特征的预测。通过模型的处理器将预测的令牌 ID 解码为文本转录:

    transcription_original = processor.batch_decode(predicted_ids, skip_special_tokens=True)
    
  4. 在量化模型上运行推理:类似地,使用量化后的 OpenVINO 模型生成相同输入特征的预测。通过模型的处理器将预测的令牌 ID 解码为文本转录:

    predicted_ids = ov_quantized_model.generate(input_features)
    transcription_quantized = processor.batch_decode(predicted_ids, skip_special_tokens=True)
    
  5. 使用Audio类播放用于转录的音频文件:

    display(ipd.Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"]))
    
  6. 打印转录文本:打印来自原始模型和量化模型的转录文本以进行结果比较:

    print(f"Original : {transcription_original[0]}")
    print(f"Quantized: {transcription_quantized[0]}")
    

在笔记本中运行此代码后,检查转录文本,并验证原始模型和量化模型的转录文本是否一致,确保量化没有显著影响模型的准确性。

此外,笔记本还包括如何通过 Hugging Face 的 ASR 管道接口使用模型,突出了用于长音频转录的分块算法的效率。

性能和准确性比较

接下来,我们将比较原始模型和量化后的 Distil-Whisper 模型在准确性(使用 WER)和性能(推理时间)方面的差异。这说明了量化在提高模型推理速度而不会显著降低准确性方面的好处。比较原始模型和量化模型的性能和准确性包括以下内容:

  • 衡量准确性:我们使用1 - WER指标来衡量模型的准确性。这涉及将模型生成的转录文本与地面真实文本进行比较,以计算错误率。较低的 WER 表示更高的准确性:

    word_accuracy = (1 - wer(ground_truths, predictions, reference_transform=wer_standardize,                         hypothesis_transform=wer_standardize)) * 100
    
  • 衡量性能:推理时间分别为编码器、解码器-带有过去状态模型的前向推理以及整个模型推理进行测量。此步骤包括对模型的推理过程进行计时,以评估模型生成预测的速度。性能测量对于理解量化在提高效率方面的作用至关重要:

    mean_whole_infer_time = sum(whole_infer_times)
    mean_encoder_infer_time = sum(encoder_infer_times)
    mean_decoder_with_time_infer_time = sum(decoder_with_past_infer_times)
    
  • 比较原始模型和量化模型:笔记本直接比较了原始 Distil-Whisper 模型及其量化版本在准确性(使用 1 - WER)和性能(推理时间)方面的表现。这种比较有助于说明量化对模型效率和效果的影响:

    print(f"Encoder performance speedup: {times_original[1] / times_quantized[1]:.3f}")
    print(f"Decoder with past performance speedup: {times_original[2] / times_quantized[2]:.3f}")
    print(f"Whole pipeline performance speedup: {times_original[0] / times_quantized[0]:.3f}")
    print(f"Whisper transcription word accuracy. Original model: {accuracy_original:.2f}%. Quantized model: {accuracy_quantized:.2f}%.")
    print(f"Accuracy drop: {accuracy_original - accuracy_quantized:.2f}%.")
    

基于运行笔记本后打印出来的对比结果,你可以得出量化的好处,比如模型推理时间的显著改善,而精度几乎没有显著下降。这些步骤为评估量化对 ASR 模型性能和精度的影响提供了一个全面的框架,尤其是在使用 OpenVINO 优化 Distil-Whisper 等模型时。目标是证明,量化可以显著提高模型效率,使其能够在资源受限的环境中部署,而不会大幅牺牲精度。

运行交互式演示

作为附加内容,交互式 Gradio 演示允许我们在他们的音频数据或录音上测试模型的能力。此部分展示了量化后的 Distil-Whisper 模型在用户友好方式下的实际应用。

我鼓励你运行并实验 Colab 笔记本。它是理解量化过程的基础工具,更重要的是,它是你实验或生产工作的重要蓝图。运行完笔记本后,我们开始了一个迷人的旅程,探索了在自动语音识别(ASR)中集成尖端技术。笔记本详细介绍了如何利用 Distil-Whisper 模型,它是 OpenAI 的 Whisper 模型的精简版,在显著减少参数的同时优化了性能,并通过英特尔的 OpenVINO 工具包进行部署,以提高推理速度和效率。

从这个笔记本中获得的一个关键学习是,不同库和框架之间的无缝协同工作,帮助实现了 ASR 任务的高效工作流。使用 Hugging Face Transformers 库访问预训练模型,并利用 Optimum Intel 库将模型转换为 OpenVINO 的 IR 格式,展示了模型部署的一种强大方法。这个过程简化了用户体验,为利用英特尔架构提供的硬件加速能力铺平了道路。

笔记本进一步探讨了使用 NNCF 进行模型量化的实际操作。这一步对于在不显著影响精度的情况下优化模型性能至关重要。准备校准数据集、运行量化并比较原始模型和量化模型的性能与精度的详细演示,提供了关于模型优化细节的宝贵见解。

笔记本中还强调了另一个重要方面,即使用 Gradio 创建交互式演示。这展示了 Distil-Whisper 模型在现实场景中的实际应用,允许用户在他们的音频数据上测试模型的能力。包括这样的演示突显了在开发和部署 AI 模型时,易用性和用户参与的重要性。

你应该寻求将此笔记本中的学习内容直接应用于你的实验或生产 ASR 任务。这些内容可以扩展到 AI 模型部署和优化的更广泛领域,突显了 AI 技术的不断发展和其实际应用。

虽然量化技术已被证明是优化 Whisper 性能和实现高效部署的强大手段,但另一个令人兴奋的前沿领域是探索使用 Whisper 进行实时语音识别的挑战与机遇。实时转录开启了许多可能性,从增强可访问性到促进即时沟通。然而,它也带来了独特的技术难题,必须加以克服。在接下来的部分,我们将深入探讨实时转录面临的当前限制和正在进行的研究工作,旨在使 Whisper 的实时转录成为现实。通过理解这些挑战和前景中的潜在解决方案,我们可以更好地认识到 Whisper 在重塑我们如何在实时场景中与口语互动方面的巨大潜力。

面对实时语音识别的挑战与机遇

追求使用 Whisper 进行实时转录打开了许多应用,这些应用能够惠及教育、医疗和客户服务等各个领域。实时转录可以增强听力障碍人士的可访问性,促进多语言环境中的即时沟通,并提供口头交流的即时文档记录。随着 Whisper 功能的不断发展,它作为通用翻译工具和可访问性工具的潜力变得越来越明显。

然而,目前仍有更多的限制和挑战阻碍着实时转录的实现。让我们深入探讨这些方面,重点关注实现实时转录的技术复杂性和前景:

  • 处理时间和延迟:实现实时转录的主要挑战之一是 Whisper 操作的固有延迟和处理时间。正如 GitHub 和 Hugging Face 等平台上的讨论所揭示,Whisper 并非天生为实时语音转文字(STT)转换设计。虽然它在处理任意长度的音频文件时表现稳健,但系统架构在提供即时转录结果时遇到了障碍。这种延迟源于支撑 Whisper 的复杂神经网络模型,这些模型需要大量计算资源来准确分析和转录语音。

  • 提高准确性和上下文理解能力:另一个限制在于 Whisper 转录的准确性和上下文知识。尽管 Whisper 在转录多种语言和口音方面表现出了非凡的能力,但实时应用仍然面临独特的挑战。系统必须准确识别语音,并理解对话中的上下文、习语和口语表达。这要求具备当前模型仍在努力完善的语言学和文化细微差别。

尽管存在这些限制,Whisper 在实时转录方面的潜力巨大。该技术当前的能力和不断发展的进展为我们展示了一个未来,届时这些挑战将变得可以克服:

  • 提升模型效率:近期的研究集中于提高 Whisper 的效率并减少延迟,使实时转录成为一个切实可行的目标。例如,在 arXiv 上的一项研究《将 Whisper 转变为实时转录系统》(arxiv.org/abs/2307.14743)探讨了将 Whisper 转变为实时转录系统的方法。这些方法包括优化模型的架构以及利用更强大的计算资源。随着这些进展的持续,我们可以预见到处理时间将大幅减少,Whisper 将更接近实现无缝的实时转录。

  • 与边缘计算的整合:Whisper 与边缘计算的整合为克服延迟问题提供了一个有前景的途径。通过在数据生成源附近处理数据,边缘计算可以显著减少音频转录所需的时间。这一方法加速了转录过程,缓解了带宽限制,使实时转录变得更加可行和高效。

尽管通过 Whisper 实现完美的实时转录之路充满了技术挑战,但它所带来的机遇无疑是令人振奋的。延迟、处理时间和上下文准确性方面的限制虽大,但可以管理。通过持续的研究、技术进步和创新应用,Whisper 正站在重新定义实时转录的风口浪尖。展望未来,Whisper 在我们日常生活中的整合不仅有望提升沟通和可访问性,还将推动人工智能领域的可能性边界。前方的道路充满挑战和激动人心的机会,突显了在这一动态领域持续探索和发展的重要性。

为了更好地理解 Whisper 在实时语音识别中的挑战和潜力,让我们深入一个实际的示例。在接下来的部分,我们将使用 Hugging Face 对 Whisper 的实现和用户友好的 Gradio 库构建一个互动式实时 ASR 演示。

使用 Hugging Face Whisper 构建实时 ASR 演示

在本节中,我们将利用 Gradio(一个用户界面库)的强大功能,快速构建一个 Whisper 模型的互动演示。这个演示将允许你或其他人通过设备上的麦克风测试模型的表现。让我们找到并运行 LOAIW_ch07_3_Building_real_time_ASR_with_HF_Whisper.ipynb 笔记本 (github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter07/LOAIW_ch07_3_Building_real_time_ASR_with_HF_Whisper.ipynb)。该笔记本分为三个主要部分:

  • transformers 库,用于为我们的演示准备 ASR 模型。

  • 创建完整上下文的 ASR 演示:我们将构建一个演示,其中用户在 ASR 模型处理并生成转录之前讲述完整音频。

  • 创建流式 ASR 演示:我们将扩展之前的演示,支持实时流式处理,让 ASR 模型在用户讲话时实时转录音频,提供更加互动的体验。

到本笔记本的最后,你将能够充分理解如何使用 Gradio 和 Hugging Face Transformers 库为语音识别模型创建引人入胜的演示。

准备开发环境

在开始构建语音识别演示之前,首先需要设置开发环境并安装必要的依赖项。在这一部分,我们将进行以下操作:

  1. 安装所需的库,如 Gradio,以确保开发过程顺利进行。

  2. 配置环境,以便与 Hugging Face Transformers 库无缝协作,允许我们利用预训练模型和强大的 NLP 工具。

通过正确设置环境,我们为整个笔记本提供了一个高效且无烦恼的编程体验基础。

为了将我们对实时 ASR 与 Whisper 的探索付诸实践,我们首先需要设置开发环境。让我们一起走过安装必要库和配置设置的过程,以确保能够与 Hugging Face Transformers 库无缝协作。

%%capture
!pip -q install gradio

设置你的 Hugging Face 令牌对于确保在使用此笔记本时的流畅体验至关重要。该笔记本将从 Hugging Face 仓库加载 transformer 类和模型,这需要有效的令牌认证。

如果你还没有创建 Hugging Face 令牌,或者需要重新了解这一过程,请参考 github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter03/LOAIW_ch03_working_with_audio_data_via_Hugging_Face.ipynb。该资源提供了创建和配置 Hugging Face 令牌的逐步说明。

通过正确设置您的令牌,您将能够轻松访问 Hugging Face 生态系统中可用的所有功能和模型,从而使您能够构建强大的语音识别演示:

from huggingface_hub import notebook_login
notebook_login()
from huggingface_hub import whoami
whoami()

在设置好我们的开发环境后,让我们首先加载 transformers 的 ASR 模型,它将作为我们交互式应用程序的基础。

步骤 1 – 加载 transformers ASR 模型

我们首先需要一个 ASR 模型来开始构建我们的语音识别演示。您可以选择训练自己的模型或使用预训练模型。加载来自 Hugging Face transformers库的"whisper"模型非常简单。以下是实现此功能的代码片段:

from transformers import pipeline
p = pipeline("automatic-speech-recognition", model="openai/whisper-base.en")

仅通过这两行代码,我们使用"openai/whisper-base.en"模型初始化了一个自动语音识别(ASR)管道。该管道抽象了直接使用模型时的复杂性,提供了一个高层次的接口来执行 ASR 任务。

通过利用像"whisper"这样的预训练模型,我们可以迅速开始构建演示,而无需进行大量的模型训练。这使我们能够专注于将模型集成到我们的应用程序中,并创造一个引人入胜的用户体验。

步骤 2 – 使用 transformers 构建全上下文的 ASR 演示

创建语音识别演示的第一步是构建一个全上下文的 ASR 演示。在这个演示中,用户将在 ASR 模型处理之前,先说完整个音频,模型生成转录文本。得益于 Gradio 直观的界面,构建这个演示变得非常简单:

import gradio as gr
from transformers import pipeline
import numpy as np
transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-base.en")
def transcribe(audio):
    sr, y = audio
    y = y.astype(np.float32)
    y /= np.max(np.abs(y))
    return transcriber({"sampling_rate": sr, "raw": y})["text"]
demo = gr.Interface(
    transcribe,
    gr.Audio(sources=["microphone"]),
    "text",
)
demo.launch(debug=True)

在前面的代码片段中,我们首先创建了一个封装我们先前初始化的pipeline对象的函数。这个函数是我们演示的核心,负责处理音频输入并生成转录文本。

然后,我们利用 Gradio 内置的Audio组件来捕获用户的音频输入。该组件将被配置为接受来自用户麦克风的输入,并返回录制音频的文件路径。我们将使用一个简单的Textbox组件来显示转录文本。

transcribe函数是我们演示的核心,它接收一个名为audio的参数。这个参数代表用户录制的音频数据,以numpy数组的形式存储。然而,pipeline对象期望音频数据为float32格式。为了确保兼容性,我们首先将音频数据转换为float32格式,然后通过其最大绝对值进行归一化。最后,我们将处理后的音频数据传递给pipeline对象,以获得转录文本。

步骤 3 – 增强演示,添加实时流式传输功能

要创建一个流式 ASR 演示,我们需要在 Python Gradio 脚本中进行以下更改:

  1. Audio组件中设置streaming=True,以启用从用户麦克风连续捕获音频。

  2. Interface组件中设置live=True,以确保界面在接收到新音频数据时能够动态更新。

  3. 在接口中添加state变量,以存储记录的音频和前一个转录。

这些修改已经在脚本中应用:

import gradio as gr
from transformers import pipeline
import numpy as np
transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-base.en")
def transcribe(state, new_chunk):
    if state is None:
        stream = np.array([], dtype=np.float32)
        previous_text = ""
    else:
        stream, previous_text = state
    sr, y = new_chunk
    duration = len(y) / sr
    y = y.astype(np.float32)
    y /= np.max(np.abs(y))
    overlap = int(sr * 0.5)  # Half a second overlap
    if len(stream) > 0:
        stream = np.concatenate([stream[-overlap:], y])
    else:
        stream = y
    # Transcribe the current chunk
    new_text = transcriber({"sampling_rate": sr, "raw": stream})["text"]
    # Update the previous text based on the overlap
    if len(previous_text) > 0:
        overlap_text = previous_text[-int(len(previous_text) * 0.1):]  # Last 10% of previous text
        combined_text = previous_text[:-len(overlap_text)] + new_text
    else:
        combined_text = new_text
    return (stream, combined_text), combined_text
demo = gr.Interface(
    transcribe,
    ["state", gr.Audio(sources=["microphone"], streaming=True)],
    ["state", "text"],
    live=True,
)
demo.launch(debug=True)

在流式演示中,我们使用state变量来跟踪音频历史和前一个转录。每当收到一个新的小音频块时,都会调用transcribe函数,需要将新的音频块与之前记录的音频一起处理。

为了提高转录的准确性和连贯性,我们引入了基于新音频块持续时间的动态窗口大小,并在连续的窗口之间设置轻微的重叠。以下是transcribe函数的工作原理:

  1. 如果stateNone,初始化一个空的numpy数组(stream)来存储音频,和一个空字符串(previous_text)来存储前一个转录。

  2. new_chunk中提取采样率(sr)和音频数据(y)。

  3. 计算新的音频块的持续时间并规范化音频数据。

  4. 在连续的窗口之间引入半秒的重叠,以确保转录的连续性。

  5. 将新的音频块与现有流连接,考虑到重叠部分。

  6. 使用transcriber对象转录整个流。

  7. 更新previous_text,通过去除前一个转录的重叠部分,并将其与新的转录合并。

  8. 返回更新后的streamcombined_text值作为状态,以及combined_text值作为转录输出。

通过使用动态窗口大小并在连续窗口之间引入重叠,我们可以提高流式转录的准确性和连贯性。小重叠有助于保持转录的连续性,并减少重叠或缺失单词的发生。

当然,这是一个简单的演示。它的设计目的是展示 Whisper 的实时功能并没有看起来那么遥不可及。我鼓励你增强和实验这个演示,并玩得开心!

摘要

在本章中,我们开始了对 OpenAI 的 Whisper 高级语音能力的激动人心的探索。我们深入研究了提升 Whisper 性能的强大技术,如量化,并揭示了其在实时语音识别中的潜力。

我们从研究量化的力量开始,量化可以减少模型的大小和计算需求,同时保持准确性。我们学会了如何使用 CTranslate2 和 OpenVINO 等框架将量化应用于 Whisper,实现了在资源受限设备上的高效部署。通过使用 CTranslate2 和 Distil-Whisper 与 OpenVINO 量化 Whisper 的实践经验,我们深入了解了如何优化模型以适应不同的部署场景。

此外,我们利用 Whisper 解决了实时语音识别的挑战和机遇。我们深入了解了当前的限制,如处理时间和延迟,并探索了使实时转录成为现实的持续研究努力。利用 Whisper 和 Gradio 构建流式 ASR 演示的实验方法,展示了实时语音识别未来可能性的一瞥。

在整个章节中,我们获得了优化 Whisper 性能的高级技术的扎实理解,并且认识到了实时语音识别的潜力和挑战。通过实际操作的编码示例和实用见解,我们掌握了应用这些技术到我们的项目中的知识和技能,推动了 Whisper 的可能性边界。

随着本章的结束,我们展望第八章使用 WhisperX 和 NVIDIA 的 NeMo 进行语音辨析。虽然 Whisper 已被证明是一个强大的转录工具,但还有另一个关键的语音分析方面可以显著增强其效用:说话者辨析。通过增强 Whisper 的能力来识别和归因不同说话者的语音片段,我们为分析多说话者对话打开了新的可能性领域。请加入我在下一章,让我们探讨如何将 Whisper 与前沿的辨析技术结合,解锁这些功能。

第八章:使用 WhisperX 和 NVIDIA 的 NeMo 进行语音分段

欢迎来到第八章,在这里我们将探索语音分段的世界。尽管 Whisper 已被证明是一个强大的语音转录工具,但语音分析中还有另一个至关重要的方面——说话人分段,这可以显著增强其效用。通过增强 Whisper 的能力,识别并将语音片段归属于不同的说话人,我们为分析多说话人对话开辟了新的可能性。本章将探讨如何将 Whisper 与最先进的分段技术结合,以解锁这些能力。

我们将从探索说话人分段系统的演变开始,了解早期方法的局限性,以及变压器模型带来的变革性影响。通过实际的操作示例,我们将预处理音频数据,使用 Whisper 转录语音,并微调转录与原始音频之间的对齐。

在本章中,我们将涵盖以下主要主题:

  • 增强 Whisper 的说话人分段能力

  • 执行实际的语音分段

本章结束时,您将了解如何将 Whisper 与先进的技术(如语音活动检测、说话人嵌入提取和聚类)集成,从而增强其功能,并实现最先进的分段性能。您还将学习如何利用 NVIDIA 强大的多尺度分段解码器MSDD)模型,该模型考虑了说话人嵌入的多个时间分辨率,以提供卓越的准确性。通过掌握本章中介绍的技术,您将能够应对复杂的多说话人音频场景,推动 OpenAI Whisper 的可能性极限。

准备好深入探索说话人分段的激动人心的世界,并从多说话人对话中获得新的见解吧!让我们一起开始这段变革之旅!

技术要求

为了利用 OpenAI 的 Whisper 实现高级应用,本章使用 Python 和 Google Colab,便于使用和访问。Python 环境设置包括用于转录任务的 Whisper 库。

关键要求

  • Google Colab 笔记本:笔记本设置为使用最低要求的内存和容量运行我们的 Python 代码。如果可用,请选择T4 GPU运行类型以获得更好的性能。

  • Google Colab 笔记本:笔记本设置为使用最低要求的内存和容量运行我们的 Python 代码。如果可用,请将运行时类型更改为GPU以获得更好的性能。

  • Python 环境:每个笔记本包含指令,用于加载所需的 Python 库,包括 Whisper 和 Gradio。

  • Hugging Face 帐户:某些笔记本需要 Hugging Face 帐户和登录 API 密钥。Colab 笔记本中包含有关此主题的信息。

  • 麦克风和扬声器:一些笔记本实现了一个带有语音录制和音频播放功能的 Gradio 应用程序。连接到计算机的麦克风和扬声器可以帮助您体验互动语音功能。另一种选择是在运行时打开 Gradio 提供的 URL 链接,在您的手机上使用手机麦克风录制您的声音。

  • GitHub 仓库访问:所有 Python 代码,包括示例,都可以在本章的 GitHub 仓库中找到(github.com/PacktPublishing/Learn-OpenAI-Whisper/tree/main/Chapter08)。这些 Colab 笔记本已准备好运行,提供了一种实用且动手的学习方法。

通过满足这些技术要求,您将为在不同情境中探索 Whisper 做好准备,同时享受 Google Colab 带来的流畅体验以及 GitHub 上提供的全面资源。

使用说话人分离增强 Whisper

说话人分离是将音频流按说话人的身份划分为不同的段落,是多说话人语音处理中的一个强大功能。它解决了*谁在什么时候说话?*的问题。在给定的音频片段中,增强 ASR 系统的功能性和可用性至关重要。说话人分离的起源可以追溯到 1990 年代,当时为基于聚类的分离范式奠定了基础。这些早期的研究主要集中在广播新闻和通信应用,旨在提高 ASR 性能。早期研究中使用的特征大多是手工设计的,其中Mel 频率倒谱系数MFCCs)是常见的选择。

随着时间的推移,说话人分离领域取得了显著的进展,特别是在深度学习技术的出现之后。现代分离系统通常利用神经网络和大规模 GPU 计算来提高准确性和效率。分离技术的发展包括早期方法中使用高斯混合模型GMMs)和隐马尔可夫模型HMMs),以及近年来采用神经嵌入(如x-向量和d-向量,我们将在本章稍后的说话人嵌入介绍部分中详细介绍)和聚类方法。

对该领域最重要的贡献之一是端到端神经分离方法的发展,这些方法通过将分离流程中的不同步骤合并,简化了分离过程。这些方法旨在处理多说话人标注和分离中的挑战,例如处理嘈杂的声学环境、不同的音色和口音差异。

开源项目也为说话人分离能力的演变做出了贡献,工具如 ALIZE、pyannote.audio、pyAudioAnalysis、SHoUT 和 LIUM SpkDiarization 为研究人员和开发人员提供了资源,以便在他们的应用程序中实现和实验说话人分离。大多数早期工具现在已经不再活跃或被遗弃,只有 pyannote.audio(Pyannote)仍在使用。

早期的说话人分离系统虽然在解决音频录音中谁在何时说话的问题上具有开创性,但也面临着若干局限性,这些局限性影响了它们的准确性和效率。在下一节中,我们将更详细地探讨早期说话人分离解决方案的根本性障碍。

理解说话人分离的局限性和约束

早期说话人分离技术中的许多不足和不准确性源于当时的技术约束、人类语音的复杂性以及应用于音频处理的机器学习技术尚处于初步阶段。理解这些局限性为我们提供了对说话人分离能力演变的宝贵见解,并帮助我们认识到随着时间推移所取得的重大进展:

  • 计算限制:早期的说话人分离系统受限于当时可用的计算能力。处理大规模音频数据集需要大量的计算资源,这些资源在当时并不像今天这样普遍和强大。这一限制影响了可以在合理时间内运行的算法的复杂度,从而限制了早期说话人分离系统的准确性。

  • 特征提取和建模的局限性:早期的说话人分离系统中使用的特征提取技术,如 MFCCs,相较于现代系统中使用的复杂嵌入技术,要简单得多。这些早期的特征可能无法有效捕捉不同说话人声音的细微差别,从而导致说话人区分不够准确。

  • 依赖 GMM 和 HMM 进行说话人建模:尽管这些模型为说话人分离提供了基础,但它们在处理不同说话人和环境下人类语音的变化性和复杂性时存在局限性。

  • 处理说话者变化点:早期分离系统面临的一个重大挑战是准确检测说话者变化点。这些系统尤其在处理短语音段和接近说话者变化点的语音段时遇到了困难。随着语音段时长的减少以及与变化点的接近,系统的表现会有所下降。例如,在单一远程麦克风SDM)和多重远程麦克风MDM)的条件下,所有评估的系统中超过 33%和 40%的错误发生在变化点前后 0.5 秒内。SDM 指的是在离说话者一定距离处放置一个麦克风,用来捕捉所有参与者的音频。而 MDM 则是在录音环境中不同位置放置多个麦克风,提供额外的空间信息,从而可以提升分离性能。这些设置下的错误百分比突显了早期分离系统在准确检测说话者变化时,尤其是在变化点附近,所面临的挑战。

  • 可扩展性和灵活性:早期的分离系统通常是针对特定应用设计的,如广播新闻或会议录音,可能无法快速适应其他类型的音频内容。这种缺乏灵活性限制了分离技术的广泛应用。此外,这些系统在处理大规模或实时分离任务时的可扩展性也是一个重大挑战。

  • 错误分析和改进方向:对早期分离系统的深入错误分析表明,改善说话者变化点附近的处理可以显著提升整体性能。为解决这些限制,探索了替代最小持续时间约束以及利用最显著和第二大对数似然得分之间的差异进行无监督聚类等改进措施。

尽管早期的说话者分离方法取得了开创性进展,但它们仍面临各种限制,这些限制本可以提高它们的准确性和效率。这些限制来源于技术约束、人类语音的复杂性以及机器学习技术的初期阶段。然而,引入基于变压器的模型彻底改变了这一领域,解决了许多挑战,为更准确高效的解决方案铺平了道路。

将变压器引入语音分离

变换器在推动最先进的语音分离技术方面起到了关键作用。它们擅长处理语音的序列性和上下文性,这对于在音频流中区分说话人至关重要。变换器中的自注意力机制使得模型能够权衡输入数据中每个部分的重要性,这对于识别说话人切换点并将语音段归属到正确的说话人至关重要。

如前所述,传统的语音分离方法通常依赖于高斯混合模型(GMMs)和隐马尔可夫模型(HMMs)来建模说话人的特征。这些方法需要改进,以应对人类语音的变化性和复杂性。相比之下,基于变换器的语音分离系统可以同时处理整个数据序列,从而更有效地捕捉语音段之间的上下文和关系。

变换器还启用了嵌入表示,如x-向量和d-向量,它们提供了更细致的说话人特征表示。这有助于提高语音分离的性能,特别是在具有挑战性的声学环境或有重叠语音的场景中。

超越早期语音分离方法的局限性,我们必须引入一种颠覆性的框架,将变换器(transformers)引入语音分离——NVIDIA 的神经模块NeMo)。NeMo 是一个开源工具包,用于构建、训练和微调 GPU 加速的语音和自然语言处理(NLP)模型。它提供了一组预构建的模块和模型,可以快速组合以创建复杂的 AI 应用程序,如自动语音识别(ASR)、自然语言理解和文本到语音合成。NeMo 通过其基于变换器的管道为语音分离提供了更直接的方法,开启了说话人识别和分离的新可能性。

引入 NVIDIA 的 NeMo 框架

与传统方法相比,基于变换器的语音分离系统提供了更优的性能,并更适应自然语音的复杂性。NVIDIA 的 NeMo 工具包支持训练和微调说话人语音分离模型。NeMo 利用基于变换器的模型处理各种语音任务,包括语音分离。该工具包提供了一个管道,其中包括语音活动检测VAD)、说话人嵌入提取聚类模块,这些模块是语音分离系统的关键组成部分。NeMo 的语音分离方法涉及训练能够捕捉未见过说话人特征的模型,并将音频段分配到正确的说话人索引。

从更全面的角度来看,NVIDIA 的 NeMo 提供的功能远超基于变换器的说话人分离。NeMo 是一个端到端的、云原生的框架,用于在各种平台上构建、定制和部署生成性 AI 模型,包括大型语言模型(LLMs)。它为整个生成性 AI 模型开发生命周期提供了全面的解决方案,从数据处理、模型训练到推理。NeMo 特别以其在对话 AI 方面的能力而著称,涵盖了自动语音识别(ASR)、自然语言处理(NLP)和文本转语音合成。

NeMo 以其处理大规模模型的能力脱颖而出,支持训练具有数万亿参数的模型。诸如张量并行、流水线并行和序列并行等先进的并行化技术为此提供了支持,使得模型可以在成千上万的 GPU 上高效扩展。该框架建立在 PyTorch 和 PyTorch Lightning 之上,为研究人员和开发人员提供了一个熟悉的环境,在对话 AI 领域进行创新。

NeMo 的一个关键特点是其模块化架构,在这种架构中,模型由具有强类型输入和输出的神经模块组成。这种设计促进了重用性,并简化了新对话 AI 模型的创建,允许研究人员利用现有代码和预训练模型。

NeMo 作为开源软件可供使用,鼓励社区的贡献,并促进了广泛的采用和定制。它还与 NVIDIA 的 AI 平台集成,包括 NVIDIA Triton 推理服务器,以便在生产环境中部署模型。NVIDIA NeMo 提供了一个强大而灵活的框架,用于开发最先进的对话 AI 模型,提供的工具和资源可以简化将生成性 AI 应用从概念到部署的全过程。

现在我们已经分别探讨了 Whisper 和 NeMo 的能力,接下来我们来考虑将这两种强大工具集成的潜力。将 Whisper 的转录能力与 NeMo 的先进说话人分离功能结合,可以从音频数据中解锁更多的洞见。

集成 Whisper 与 NeMo

尽管 Whisper 主要以其转录能力而闻名,但它也可以适应说话人分离任务。然而,Whisper 并不原生支持说话人分离。为了实现 Whisper 的说话人分离,需要借助如 Pyannote 这样的说话人分离工具包,结合 Whisper 的转录结果来识别说话人。

将 NVIDIA 的 NeMo 与 OpenAI 的 Whisper 结合进行说话人分离,涉及到一个创新的流程,利用两个系统的优势来增强分离效果。这种集成在推理和结果解读方面尤其值得注意。

该管道首先由 Whisper 处理音频以生成高精度的转录。Whisper 的主要角色是转录音频,提供详细的口语内容文本输出。然而,Whisper 本身不支持说话人分离(diarization)——识别音频中谁在什么时候说话

为了引入分离,管道集成了 NVIDIA 的 NeMo,特别是它的说话人分离模块。NeMo 的分离系统旨在处理音频录音,通过说话人标签进行分段。它通过多个步骤实现这一目标,包括语音活动检测(VAD)、说话人嵌入提取和聚类。说话人嵌入捕捉独特的声音特征,然后通过聚类区分音频中的不同说话人。

Whisper 和 NeMo 在分离中的集成使你能够将 Whisper 的转录与 NeMo 识别的说话人标签对齐。这意味着输出不仅包括说了什么(来自 Whisper 的转录),还识别了每一部分由哪位说话人说(来自 NeMo 的分离)。结果是对音频内容有更全面的理解,既提供文本转录,又提供说话人的归属。

这种集成在理解对话动态至关重要的场景中非常有用,例如会议、访谈和法律程序。通过为转录添加一层特定于说话人的上下文,它增强了转录的实用性,使得更容易跟随对话并准确归属发言。

Whisper 和 NeMo 的说话人分离集成将 Whisper 的先进转录能力与 NeMo 强大的分离框架结合在一起。这种协同作用通过提供详细的转录和准确的说话人标签,增强了音频内容的可解释性,从而为口语互动提供更丰富的分析。

在深入探讨 Whisper 和 NeMo 的集成之前,了解现代语音处理系统中的一个基本概念——说话人嵌入至关重要。这些说话人特征的向量表示对于实现准确的说话人分离至关重要。

说话人嵌入简介

说话人嵌入(Speaker embeddings)是从语音信号中提取的向量表示,能够以紧凑的形式 encapsulate 说话人声音的特征。这些嵌入被设计为具有辨别性,意味着它们能够有效地区分说话人,同时对语音内容、通道和环境噪音的变化具有鲁棒性。目标是从可变长度的语音话语中获取固定长度的向量,捕捉说话人声音的独特特征。

说话人嵌入是现代语音处理系统的基础组件,支持从说话人验证到分离等多种应用。它们能够将说话人声音的丰富信息压缩成固定长度的向量,这使得它们在需要识别、区分或追踪不同说话人的音频记录系统中具有不可替代的价值。

从更技术的角度来看,有几种类型的说话人嵌入,每种都有其提取方法和特征:

  • i-vectors:这些嵌入在低维空间中捕捉说话人和通道的变异性。它们源自 GMM 框架,并表示给定说话人的发音与一组语音类别之间的平均发音的差异。

  • d-vectors:这些向量通过训练一个说话人区分的深度神经网络DNN)并从最后的隐藏层提取帧级向量得到。这些向量随后在整个话语中进行平均,产生d-vector,代表说话人的身份。

  • x-vectors:这种类型的嵌入涉及帧级和段级特征(话语)处理。X-vectors 通过一个 DNN 提取,该 DNN 处理一系列声学特征并对它们进行聚合,使用统计池化层生成固定长度的向量。

  • s-vectors:也称为序列向量或摘要向量,s-vectors 来源于递归神经网络架构,如 RNN 或 LSTM。它们旨在捕捉顺序信息,可以在相当程度上编码口语词汇和单词顺序。

提取说话人嵌入通常涉及训练一个神经网络模型,通过优化编码器并使用鼓励区分学习的损失函数来实现。训练完成后,提取段级网络中隐藏层的前激活值作为说话人嵌入。该网络在一个包含大量说话人的数据集上进行训练,以确保嵌入能够很好地泛化到未见过的说话人。

在说话人分离的背景下,说话人嵌入根据说话人的身份将语音段进行聚类。嵌入提供了一种测量段之间相似性的方法,并将这些段与可能来自同一说话人的段群体进行分组。这是分离过程中的关键步骤,因为它允许你在音频流中准确地将语音归属到正确的说话人。

正如我们所见,增强了 Pyannote 的 Whisper 和 NVIDIA 的 NeMo 都提供了强大的分离能力。然而,理解这些方法之间的关键区别至关重要,这样才能在选择分离解决方案时做出明智的决定。

区分 NVIDIA 的 NeMo 能力

分话功能的集成对 ASR 系统的影响受到变换器模型(transformer models)出现的显著推动,特别是在 OpenAI 的 Whisper 和 NVIDIA 的 NeMo 框架的背景下。这些进展提升了 ASR 系统的准确性,并引入了处理分话任务的新方法。我们将深入探讨使用 Pyannote 的 Whisper 分话与使用 NVIDIA NeMo 的分话之间的相似性与差异,重点关注语音活动检测、说话人变化检测和重叠语音检测。了解这两种分话方法之间的差异,对于在选择适合自己特定使用案例的解决方案时做出明智决策至关重要。通过研究每个系统如何处理分话过程中的关键环节,如语音活动检测、说话人变化检测和重叠语音检测,您可以更好地评估哪种方法与您的准确性、效率和集成需求最为契合:

分话功能Whisper 与 PyannoteNVIDIA NeMo
检测 语音活动Whisper 本身并不执行语音活动检测(VAD)作为其分话任务的一部分。然而,当与 Pyannote 结合使用时,来自 Pyannote 工具包的外部 VAD 模型可以在应用分话之前将音频分割为语音和非语音区间。这种方法需要将 Whisper 的语音识别(ASR)能力与 Pyannote 的 VAD 模型相结合,基于深度学习技术和微调,实现精确的语音/非语音分割。NeMo 的分话流程包括一个专门的 VAD 模块,该模块是可训练和优化的,作为分话系统的一部分。此 VAD 模型旨在检测语音的存在或缺失,并生成语音活动的时间戳。将 VAD 集成到 NeMo 的分话流程中,可以实现更加简化的过程,直接将 VAD 结果传递到后续的分话步骤中。
检测 说话人变化Whisper 与 Pyannote 集成以执行分话任务时,依赖于 Pyannote 的说话人变化检测能力。Pyannote 使用神经网络模型来识别音频中发生说话人变化的点。这个过程对于将音频分割成归属于各个说话人的同质段落至关重要。Pyannote 中的说话人变化检测是一个独立模块,与其分话流程一起工作。NeMo 的说话人变化检测方法隐式地在其分话流程中处理,包括用于提取和聚类说话人嵌入的模块。虽然 NeMo 没有明确提到独立的说话人变化检测模块,但通过分析说话人嵌入及其在音频中的时间分布,识别说话人变化已集成到整体分话工作流中。
检测 重叠语音重叠语音检测是 Pyannote 补充 Whisper 功能的另一个领域。Pyannote 的工具包包括设计用于检测和处理重叠语音的模型,这是说话人分离中一个具有挑战性的方面。这个功能对于准确地分离多个说话人同时发言的对话至关重要。与说话人变化检测类似,NeMo 对重叠语音的处理被集成到其分离管道中,而不是通过单独的模块来解决。该系统处理重叠语音的能力来源于其复杂的说话人嵌入和聚类技术,即使在挑战性的重叠情境下,也能识别和分离说话人。
将说话人嵌入集成到 分离管道Whisper 与 Pyannote 的结合依赖于外部模块来完成这些任务,提供了灵活性和模块化。而 NeMo 的分离管道直接集成了这些功能,提供了一个简化而连贯的工作流程。这些进展凸显了变换器模型对语音处理的变革性影响,为更精确高效的分离系统铺平了道路。NVIDIA 的 NeMo 工具包提供了一种更集成的说话人分离方法。它提供了一个完整的分离管道,包含 VAD、说话人嵌入提取和聚类。NeMo 的说话人嵌入是通过专门训练的模型提取的,这些嵌入随后在同一框架中用于执行分离所需的聚类。
聚类和分配 说话人嵌入在提取了说话人嵌入后,Pyannote 使用各种聚类算法,如层次聚类,来对嵌入进行分组并将其分配给相应的说话人。这个聚类过程对于确定哪些音频段属于哪个说话人至关重要。NeMo 也使用聚类算法对说话人嵌入进行分组。然而,NeMo 采用了一种多尺度、自调节的光谱聚类方法,据称比 Pyannote 的版本更具抗干扰性。这种方法包括使用不同窗口长度对音频文件进行分段,并计算多个尺度的嵌入,随后将这些嵌入进行聚类,以标记每个段落的说话人。

表 8.1 – 不同的分离方法如何处理关键的分离特征

虽然 Whisper 结合 Pyannote 和 NVIDIA 的 NeMo 都使用说话人嵌入作为其分离流程的核心部分,但它们的处理方法有显著的不同。Whisper 需要一个外部工具包(pyannote.audio)来执行说话人分离,而 NeMo 则提供了一个集成的解决方案,包括说话人嵌入提取和聚类模块。NeMo 的多尺度聚类方法是一个独特的特点,使其与与 Whisper 结合使用的 Pyannote 实现有所不同。这些差异反映了语音分离研究领域中多样化的方法和创新。

混合 Whisper 和 PyAnnote – WhisperX

WhisperX (replicate.com/dinozoiddev/whisperx) 提供了快速的自动语音识别(比 OpenAI 的Whisper large-v2快 70 倍),并且具备词级时间戳和说话人分离功能,这些是 Whisper 本身不原生支持的特性。WhisperX 在 Whisper 的基础优势上进行扩展,解决了其一些局限性,特别是在时间戳精度和说话人分离方面。尽管 Whisper 提供的是发言级别的时间戳,WhisperX 通过提供词级时间戳来推动这一进步,这对于需要精确文本和音频同步的应用(如字幕和详细的音频分析)至关重要。这一功能通过结合多种技术实现,包括 VAD(语音活动检测)、将音频预分段为可管理的块,以及使用外部音素模型进行强制对齐,从而提供准确的词级时间戳。

WhisperX 的实现支持 Whisper 支持的所有语言的转录,目前英语音频的对齐功能已经可用。它已升级为融合最新的 Whisper 模型和由 Pyannote 支持的分离技术,以进一步提升其性能。在撰写本文时,WhisperX 集成了whisper-large-v3,并且通过 Pyannote 增强了说话人分离(更新至 speaker-diarization-3.1)和分段技术(更新至 segmentation-3.0)。WhisperX 在词汇分割的精度和召回率方面展现出了显著改进,同时在词错误率(WER)上有所减少,并且在采用批量转录和 VAD 预处理时,转录速度有了显著提升。

总结来说,WhisperX 是 OpenAI 的 Whisper 的重要进化,提供了通过词级时间戳和说话人分离增强的功能。这些进展使 WhisperX 成为一个强大的工具,适用于需要详细且准确的语音转录和分析的应用。

有了这个坚实的理论基础,是时候将我们的知识付诸实践了。接下来的实践部分将探索一个实际的实现,结合 WhisperX、NeMo 和其他支持的 Python 库,对现实世界的音频数据进行语音分离。

执行实践中的语音分离

从语音分离的理论背景过渡到实际实现,让我们深入了解结合 WhisperX、NeMo 以及其他支持 Python 库的实践应用,所有这些都可以在我们信赖的 Google Colaboratory 中完成。我鼓励你访问本书的 GitHub 仓库,找到LOAIW_ch08_diarizing_speech_with_WhisperX_and_NVIDIA_NeMo.ipynb笔记本(github.com/PacktPublishing/Learn-OpenAI-Whisper/blob/main/Chapter08/LOAIW_ch08_diarizing_speech_with_WhisperX_and_NVIDIA_NeMo.ipynb),并自己运行 Python 代码;可以随意修改参数并观察结果。该笔记本详细介绍了如何将 Whisper 的转录功能与 NeMo 的语音分离框架集成,提供了一个强大的解决方案来分析音频记录中的语音。

该笔记本被结构化为多个关键部分,每个部分专注于语音分离过程中的特定方面。

设置环境

笔记本的第一部分介绍了几个 Python 库和工具的安装,这些工具对于语音分离过程至关重要:

!pip install git+https://github.com/m-bain/whisperX.git@78dcfaab51005aa703ee21375f81ed31bc248560
!pip install --no-build-isolation nemo_toolkit[asr]==1.22.0
!pip install --no-deps git+https://github.com/facebookresearch/demucs#egg=demucs
!pip install dora-search "lameenc>=1.2" openunmix
!pip install deepmultilingualpunctuation
!pip install wget pydub

让我们回顾一下每个工具,以理解它们在语音分离中的作用:

  • whisperX:OpenAI Whisper 模型的扩展,旨在增强功能。特别地,WhisperX 安装了 faster-whisper(github.com/SYSTRAN/faster-whisper),这是一个使用 CTranslate2(github.com/OpenNMT/CTranslate2/)重新实现的 OpenAI Whisper 模型。该实现比 OpenAI 的 Whisper 快最多四倍,且在保持相同精度的同时,内存占用更少。通过在 CPU 和 GPU 上使用 8 位量化,可以进一步提高效率。

  • nemo_toolkit[asr]:NVIDIA 的 NeMo 工具包,用于自动语音识别(ASR),为说话人分离提供基础。

  • demucs:一个用于音乐源分离的库,能够通过将语音与背景音乐隔离来进行音频文件的预处理。

  • dora-searchlameencopenunmix:用于音频处理的工具和库,提升音频数据的质量和兼容性,以便于语音分离任务。

  • deepmultilingualpunctuation:一个用于为转录文本添加标点符号的库,改善了生成文本的可读性和结构。

  • wget 和 pydub:用于下载和操作音频文件的工具,简化了在 Python 环境中处理音频数据的过程。

这些库共同构成了处理音频文件、转录语音以及执行说话人分离的基础。每个工具都发挥着特定的作用,从准备音频数据到生成准确的转录内容,再到识别音频中的不同说话人。

简化语音分离工作流的辅助函数

该笔记本定义了几个辅助函数,以简化使用 Whisper 和 NeMo 进行话者分离的过程。这些函数在管理音频数据、将转录与说话者身份对齐以及优化工作流程方面起着关键作用。以下是每个函数的简要描述:

  • create_config(): 初始化并返回配置对象,设置话者分离过程所需的基本参数:

    def create_config(output_dir):
        DOMAIN_TYPE = "telephonic"  # Can be meeting, telephonic, or general based on domain type of the audio file
        CONFIG_FILE_NAME = f"diar_infer_{DOMAIN_TYPE}.yaml"
        CONFIG_URL = f"https://raw.githubusercontent.com/NVIDIA/NeMo/main/examples/speaker_tasks/diarization/conf/inference/{CONFIG_FILE_NAME}"
        MODEL_CONFIG = os.path.join(output_dir, CONFIG_FILE_NAME)
        if not os.path.exists(MODEL_CONFIG):
            MODEL_CONFIG = wget.download(CONFIG_URL, output_dir)
        config = OmegaConf.load(MODEL_CONFIG)
        data_dir = os.path.join(output_dir, "data")
        os.makedirs(data_dir, exist_ok=True)
        meta = {
            "audio_filepath": os.path.join(output_dir, "mono_file.wav"),
            "offset": 0,
            "duration": None,
            "label": "infer",
            "text": "-",
            "rttm_filepath": None,
            "uem_filepath": None,
        }
        with open(os.path.join(data_dir, "input_manifest.json"), "w") as fp:
            json.dump(meta, fp)
            fp.write("\n")
        pretrained_vad = "vad_multilingual_marblenet"
        pretrained_speaker_model = "titanet_large"
        config.num_workers = 0  # Workaround for multiprocessing hanging with ipython issue
        config.diarizer.manifest_filepath = os.path.join(data_dir, "input_manifest.json")
        config.diarizer.out_dir = (
            output_dir  # Directory to store intermediate files and prediction outputs
        )
        config.diarizer.speaker_embeddings.model_path = pretrained_speaker_model
        config.diarizer.oracle_vad = (
            False  # compute VAD provided with model_path to vad config
        )
        config.diarizer.clustering.parameters.oracle_num_speakers = False
        # Here, we use our in-house pretrained NeMo VAD model
        config.diarizer.vad.model_path = pretrained_vad
        config.diarizer.vad.parameters.onset = 0.8
        config.diarizer.vad.parameters.offset = 0.6
        config.diarizer.vad.parameters.pad_offset = -0.05
        config.diarizer.msdd_model.model_path = (
            "diar_msdd_telephonic"  # Telephonic speaker diarization model
        )
        return config
    
  • get_word_ts_anchor(): 确定单词的时间戳锚点,确保说话单词与其音频时间戳之间的准确对齐:

    def get_word_ts_anchor(s, e, option="start"):
        if option == "end":
            return e
        elif option == "mid":
            return (s + e) / 2
        return s
    
  • get_words_speaker_mapping(): 根据话者分离结果,将转录中的每个单词映射到相应的说话者,确保每个单词归属于正确的说话者:

    def get_words_speaker_mapping(wrd_ts, spk_ts, word_anchor_option="start"):
        s, e, sp = spk_ts[0]
        wrd_pos, turn_idx = 0, 0
        wrd_spk_mapping = []
        for wrd_dict in wrd_ts:
            ws, we, wrd = (
                int(wrd_dict["start"] * 1000),
                int(wrd_dict["end"] * 1000),
                wrd_dict["word"],
            )
            wrd_pos = get_word_ts_anchor(ws, we, word_anchor_option)
            while wrd_pos > float(e):
                turn_idx += 1
                turn_idx = min(turn_idx, len(spk_ts) - 1)
                s, e, sp = spk_ts[turn_idx]
                if turn_idx == len(spk_ts) - 1:
                    e = get_word_ts_anchor(ws, we, option="end")
            wrd_spk_mapping.append(
                {"word": wrd, "start_time": ws, "end_time": we, "speaker": sp}
            )
        return wrd_spk_mapping
    
  • get_first_word_idx_of_sentence(): 找到句子中第一个单词的索引,对于在说话者归属和对齐的上下文中处理句子至关重要:

    def get_first_word_idx_of_sentence(word_idx, word_list, speaker_list, max_words):
        is_word_sentence_end = (
            lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
        )
        left_idx = word_idx
        while (
            left_idx > 0
            and word_idx - left_idx < max_words
            and speaker_list[left_idx - 1] == speaker_list[left_idx]
            and not is_word_sentence_end(left_idx - 1)
        ):
            left_idx -= 1
        return left_idx if left_idx == 0 or is_word_sentence_end(left_idx - 1) else -1
    
  • get_last_word_idx_of_sentence(): 找到句子中最后一个单词的索引,有助于在转录文本中划定句子边界:

    def get_last_word_idx_of_sentence(word_idx, word_list, max_words):
        is_word_sentence_end = (
            lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
        )
        right_idx = word_idx
        while (
            right_idx < len(word_list)
            and right_idx - word_idx < max_words
            and not is_word_sentence_end(right_idx)
        ):
            right_idx += 1
        return (
            right_idx
            if right_idx == len(word_list) - 1 or is_word_sentence_end(right_idx)
            else -1
        )
    
  • get_realigned_ws_mapping_with_punctuation(): 考虑标点符号调整单词到说话者的映射,提高在复杂对话场景中的说话者归属准确性:

    def get_realigned_ws_mapping_with_punctuation(
        word_speaker_mapping, max_words_in_sentence=50
    ):
        is_word_sentence_end = (
            lambda x: x >= 0
            and word_speaker_mapping[x]["word"][-1] in sentence_ending_punctuations
        )
        wsp_len = len(word_speaker_mapping)
        words_list, speaker_list = [], []
        for k, line_dict in enumerate(word_speaker_mapping):
            word, speaker = line_dict["word"], line_dict["speaker"]
            words_list.append(word)
            speaker_list.append(speaker)
        k = 0
        while k < len(word_speaker_mapping):
            line_dict = word_speaker_mapping[k]
            if (
                k < wsp_len - 1
                and speaker_list[k] != speaker_list[k + 1]
                and not is_word_sentence_end(k)
            ):
                left_idx = get_first_word_idx_of_sentence(
                    k, words_list, speaker_list, max_words_in_sentence
                )
                right_idx = (
                    get_last_word_idx_of_sentence(
                        k, words_list, max_words_in_sentence - k + left_idx - 1
                    )
                    if left_idx > -1
                    else -1
                )
                if min(left_idx, right_idx) == -1:
                    k += 1
                    continue
                spk_labels = speaker_list[left_idx : right_idx + 1]
                mod_speaker = max(set(spk_labels), key=spk_labels.count)
                if spk_labels.count(mod_speaker) < len(spk_labels) // 2:
                    k += 1
                    continue
                speaker_list[left_idx : right_idx + 1] = [mod_speaker] * (
                    right_idx - left_idx + 1
                )
                k = right_idx
            k += 1
        k, realigned_list = 0, []
        while k < len(word_speaker_mapping):
            line_dict = word_speaker_mapping[k].copy()
            line_dict["speaker"] = speaker_list[k]
            realigned_list.append(line_dict)
            k += 1
        return realigned_list
    
  • get_sentences_speaker_mapping(): 生成整个句子与说话者的映射,提供说话者在音频中贡献的高层次视图:

    def get_sentences_speaker_mapping(word_speaker_mapping, spk_ts):
        sentence_checker = nltk.tokenize.PunktSentenceTokenizer().text_contains_sentbreak
        s, e, spk = spk_ts[0]
        prev_spk = spk
        snts = []
        snt = {"speaker": f"Speaker {spk}", "start_time": s, "end_time": e, "text": ""}
        for wrd_dict in word_speaker_mapping:
            wrd, spk = wrd_dict["word"], wrd_dict["speaker"]
            s, e = wrd_dict["start_time"], wrd_dict["end_time"]
            if spk != prev_spk or sentence_checker(snt["text"] + " " + wrd):
                snts.append(snt)
                snt = {
                    "speaker": f"Speaker {spk}",
                    "start_time": s,
                    "end_time": e,
                    "text": "",
                }
            else:
                snt["end_time"] = e
            snt["text"] += wrd + " "
            prev_spk = spk
        snts.append(snt)
        return snts
    
  • get_speaker_aware_transcript(): 生成考虑到说话者身份的转录,将文本内容和说话者信息整合为一致的格式:

    def get_speaker_aware_transcript(sentences_speaker_mapping, f):
        previous_speaker = sentences_speaker_mapping[0]["speaker"]
        f.write(f"{previous_speaker}: ")
        for sentence_dict in sentences_speaker_mapping:
            speaker = sentence_dict["speaker"]
            sentence = sentence_dict["text"]
            # If this speaker doesn't match the previous one, start a new paragraph
            if speaker != previous_speaker:
                f.write(f"\n\n{speaker}: ")
                previous_speaker = speaker
            # No matter what, write the current sentence
            f.write(sentence + " ")
    
  • format_timestamp(): 将时间戳转换为人类可读的格式,便于为转录注释准确的时间信息:

    def format_timestamp(
        milliseconds: float, always_include_hours: bool = False, decimal_marker: str = "."
    ):
        assert milliseconds >= 0, "non-negative timestamp expected"
        hours = milliseconds // 3_600_000
        milliseconds -= hours * 3_600_000
        minutes = milliseconds // 60_000
        milliseconds -= minutes * 60_000
        seconds = milliseconds // 1_000
        milliseconds -= seconds * 1_000
        hours_marker = f"{hours:02d}:" if always_include_hours or hours > 0 else ""
        return (
            f"{hours_marker}{minutes:02d}:{seconds:02d}{decimal_marker}{milliseconds:03d}"
        )
    
  • write_srt(): 以SubRip TextSRT)格式输出话者分离结果,适用于字幕或详细分析,包括说话者标签和时间戳:

    def write_srt(transcript, file):
        """
        Write a transcript to a file in SRT format.
        """
        for i, segment in enumerate(transcript, start=1):
            # write srt lines
            print(
                f"{i}\n"
                f"{format_timestamp(segment['start_time'], always_include_hours=True, decimal_marker=',')} --> "
                f"{format_timestamp(segment['end_time'], always_include_hours=True, decimal_marker=',')}\n"
                f"{segment['speaker']}: {segment['text'].strip().replace('-->', '->')}\n",
                file=file,
                flush=True,
            )
    
  • find_numeral_symbol_tokens(): 在转录文本中识别表示数字符号的标记,帮助处理文本中的数字数据:

    def find_numeral_symbol_tokens(tokenizer):
        numeral_symbol_tokens = [
            -1,
        ]
        for token, token_id in tokenizer.get_vocab().items():
            has_numeral_symbol = any(c in "0123456789%$£" for c in token)
            if has_numeral_symbol:
                numeral_symbol_tokens.append(token_id)
        return numeral_symbol_tokens
    
  • _get_next_start_timestamp(): 计算下一个单词的开始时间戳,确保转录中时间戳序列的连续性:

    def _get_next_start_timestamp(word_timestamps, current_word_index, final_timestamp):
        # if current word is the last word
        if current_word_index == len(word_timestamps) - 1:
            return word_timestamps[current_word_index]["start"]
        next_word_index = current_word_index + 1
        while current_word_index < len(word_timestamps) - 1:
            if word_timestamps[next_word_index].get("start") is None:
                # if next word doesn't have a start timestamp
                # merge it with the current word and delete it
                word_timestamps[current_word_index]["word"] += (
                    " " + word_timestamps[next_word_index]["word"]
                )
                word_timestamps[next_word_index]["word"] = None
                next_word_index += 1
                if next_word_index == len(word_timestamps):
                    return final_timestamp
            else:
                return word_timestamps[next_word_index]["start"]
    
  • filter_missing_timestamps(): 过滤并修正转录数据中缺失或不完整的时间戳,保持时间信息的完整性:

    def filter_missing_timestamps(
        word_timestamps, initial_timestamp=0, final_timestamp=None
    ):
        # handle the first and last word
        if word_timestamps[0].get("start") is None:
            word_timestamps[0]["start"] = (
                initial_timestamp if initial_timestamp is not None else 0
            )
            word_timestamps[0]["end"] = _get_next_start_timestamp(
                word_timestamps, 0, final_timestamp
            )
        result = [
            word_timestamps[0],
        ]
        for i, ws in enumerate(word_timestamps[1:], start=1):
            # if ws doesn't have a start and end
            # use the previous end as start and next start as end
            if ws.get("start") is None and ws.get("word") is not None:
                ws["start"] = word_timestamps[i - 1]["end"]
                ws["end"] = _get_next_start_timestamp(word_timestamps, i, final_timestamp)
            if ws["word"] is not None:
                result.append(ws)
        return result
    
  • cleanup(): 清理在话者分离过程中创建的临时文件或目录,确保工作环境整洁:

    def cleanup(path: str):
        """path could either be relative or absolute."""
        # check if file or directory exists
        if os.path.isfile(path) or os.path.islink(path):
            # remove file
            os.remove(path)
        elif os.path.isdir(path):
            # remove directory and all its content
            shutil.rmtree(path)
        else:
            raise ValueError("Path {} is not a file or dir.".format(path))
    
  • process_language_arg(): 处理语言参数,确保与模型兼容,促进不同语言间的准确转录:

    def process_language_arg(language: str, model_name: str):
        """
        Process the language argument to make sure it's valid and convert language names to language codes.
        """
        if language is not None:
            language = language.lower()
        if language not in LANGUAGES:
            if language in TO_LANGUAGE_CODE:
                language = TO_LANGUAGE_CODE[language]
            else:
                raise ValueError(f"Unsupported language: {language}")
        if model_name.endswith(".en") and language != "en":
            if language is not None:
                logging.warning(
                    f"{model_name} is an English-only model but received '{language}'; using English instead."
                )
            language = "en"
        return language
    
  • transcribe(): 利用 Whisper 将音频转录为文本,为话者分离过程提供基础文本数据:

    def transcribe(
        audio_file: str,
        language: str,
        model_name: str,
        compute_dtype: str,
        suppress_numerals: bool,
        device: str,
    ):
        from faster_whisper import WhisperModel
        from helpers import find_numeral_symbol_tokens, wav2vec2_langs
        # Faster Whisper non-batched
        # Run on GPU with FP16
        whisper_model = WhisperModel(model_name, device=device, compute_type=compute_dtype)
        # or run on GPU with INT8
        # model = WhisperModel(model_size, device="cuda", compute_type="int8_float16")
        # or run on CPU with INT8
        # model = WhisperModel(model_size, device="cpu", compute_type="int8")
        if suppress_numerals:
            numeral_symbol_tokens = find_numeral_symbol_tokens(whisper_model.hf_tokenizer)
        else:
            numeral_symbol_tokens = None
        if language is not None and language in wav2vec2_langs:
            word_timestamps = False
        else:
            word_timestamps = True
        segments, info = whisper_model.transcribe(
            audio_file,
            language=language,
            beam_size=5,
            word_timestamps=word_timestamps,  # TODO: disable this if the language is supported by wav2vec2
            suppress_tokens=numeral_symbol_tokens,
            vad_filter=True,
        )
        whisper_results = []
        for segment in segments:
            whisper_results.append(segment._asdict())
        # clear gpu vram
        del whisper_model
        torch.cuda.empty_cache()
        return whisper_results, language
    
  • transcribe_batched():提供批处理能力以转录音频文件,从而优化转录过程的效率和可扩展性:

    def transcribe_batched(
        audio_file: str,
        language: str,
        batch_size: int,
        model_name: str,
        compute_dtype: str,
        suppress_numerals: bool,
        device: str,
    ):
        import whisperx
        # Faster Whisper batched
        whisper_model = whisperx.load_model(
            model_name,
            device,
            compute_type=compute_dtype,
            asr_options={"suppress_numerals": suppress_numerals},
        )
        audio = whisperx.load_audio(audio_file)
        result = whisper_model.transcribe(audio, language=language, batch_size=batch_size)
        del whisper_model
        torch.cuda.empty_cache()
        return result["segments"], result["language"]
    

这些功能共同构成了笔记本的说话人分离工作流程基础,能够无缝集成 Whisper 的转录能力与 NeMo 的高级说话人分离功能。

使用 Demucs 将音乐与语音分离

在探索笔记本时,让我们关注预处理步骤,这对于在进行说话人分离之前提升语音清晰度至关重要。本节介绍了Demucs,一个用于将音乐源人声与复杂音轨分离的深度学习模型。

将音乐与语音分离非常关键,尤其是在处理包含背景音乐或其他非语音元素的录音时。通过提取人声成分,分离系统可以更有效地分析并将语音归属给正确的说话人,因为其语音信号的频谱和时间特征变得更加明显,不会被音乐干扰:

if enable_stemming:
    # Isolate vocals from the rest of the audio
    return_code = os.system(
        f'python3 -m demucs.separate -n htdemucs --two-stems=vocals "{audio_path}" -o "temp_outputs"'
    )
    if return_code != 0:
        logging.warning("Source splitting failed, using original audio file.")
        vocal_target = audio_path
    else:
        vocal_target = os.path.join(
            "temp_outputs",
            "htdemucs",
            os.path.splitext(os.path.basename(audio_path))[0],
            "vocals.wav",
        )
else:
    vocal_target = audio_path

Demucs 通过利用一个神经网络来区分混合音频中的不同音源来工作。当应用于音频文件时,它可以将人声轨道与伴奏乐器分开,从而使得后续工具(如 Whisper 和 NeMo)能够在没有背景音乐干扰的情况下处理语音。

这个分离步骤对说话人分离的准确性以及任何需要清晰语音输入的后续任务(如转录和语音识别)非常有帮助。通过将 Demucs 作为预处理管道的一部分,笔记本确保输入到分离系统的音频得到了优化,从而实现最佳性能。

使用 WhisperX 进行音频转录

下一步是利用 WhisperX 来转录音频内容。转录过程包括将音频文件通过 Whisper 处理,生成一组文本段落,每个段落都有时间戳,指示该段落被说出的时间:

compute_type = "float16"
# or run on GPU with INT8
# compute_type = "int8_float16"
# or run on CPU with INT8
# compute_type = "int8"
if batch_size != 0:
    whisper_results, language = transcribe_batched(
        vocal_target,
        language,
        batch_size,
        whisper_model_name,
        compute_type,
        suppress_numerals,
        device,
    )
else:
    whisper_results, language = transcribe(
        vocal_target,
        language,
        whisper_model_name,
        compute_type,
        suppress_numerals,
        device,
    )

这一基础步骤提供了进行说话人分离和进一步分析所需的文本内容。我希望你注意到,transcribe()transcribe_batch()这两个函数在笔记本中已经定义过了。

使用 Wav2Vec2 对转录文本与原始音频进行对齐

在转录之后,笔记本介绍了如何使用Wav2Vec2进行强制对齐,这是一个将转录文本与原始音频进行对齐的过程。Wav2Vec2 是一个大型神经网络模型,擅长学习有助于语音识别和对齐任务的语音表示。通过使用 Wav2Vec2,我们演示了如何微调转录段落与音频信号的对齐,确保文本与所说的话语准确同步:

if language in wav2vec2_langs:
    device = "cuda"
    alignment_model, metadata = whisperx.load_align_model(
        language_code=language, device=device
    )
    result_aligned = whisperx.align(
        whisper_results, alignment_model, metadata, vocal_target, device
    )
    word_timestamps = filter_missing_timestamps(
        result_aligned["word_segments"],
        initial_timestamp=whisper_results[0].get("start"),
        final_timestamp=whisper_results[-1].get("end"),
    )
    # clear gpu vram
    del alignment_model
    torch.cuda.empty_cache()
else:
    assert batch_size == 0, (  # TODO: add a better check for word timestamps existence
        f"Unsupported language: {language}, use --batch_size to 0"
        " to generate word timestamps using whisper directly and fix this error."
    )
    word_timestamps = []
    for segment in whisper_results:
        for word in segment["words"]:
            word_timestamps.append({"word": word[2], "start": word[0], "end": word[1]})

这一对齐对于分离至关重要,因为它允许根据说话人的变化进行更精确的音频分割。Whisper 和 Wav2Vec2 的结合输出提供了一个完全对齐的转录,这对于说话人分离、情感分析和语言识别等任务非常有帮助。本节强调,如果某个特定语言没有可用的 Wav2Vec2 模型,则将使用 Whisper 生成的单词时间戳,展示了该方法的灵活性。

通过将 Whisper 的转录能力与 Wav2Vec2 的对齐精度结合,我们为准确的说话人分离奠定了基础,提高了分离过程的整体质量和可靠性。

使用 NeMo 的 MSDD 模型进行说话人分离

在笔记本的核心部分,重点转向了复杂的说话人分离过程,利用了 NVIDIA NeMo MSDD 的先进能力。该部分非常关键,因为它解决了在音频信号中区分不同说话人的问题,这对于将语音片段准确归属到个人说话人至关重要:

# Initialize NeMo MSDD diarization model
msdd_model = NeuralDiarizer(cfg=create_config(temp_path)).to("cuda")
msdd_model.diarize()
del msdd_model
torch.cuda.empty_cache()

NeMo MSDD 模型处于这一过程的最前沿,采用了一种复杂的分离方法,考虑了说话人嵌入的多时间分辨率。这种多尺度策略提高了模型在挑战性音频环境中(如重叠语音或背景噪音)区分说话人的能力。

根据时间戳将说话人映射到句子

在成功地将语音与音乐分离、使用 Whisper 转录音频并通过 NeMo MSDD 模型进行说话人分离后,下一个挑战是将转录中的每个句子准确地映射到相应的说话人。这涉及分析转录中每个单词或片段的时间戳以及在分离过程中分配的说话人标签:

speaker_ts = []
with open(os.path.join(temp_path, "pred_rttms", "mono_file.rttm"), "r") as f:
    lines = f.readlines()
    for line in lines:
        line_list = line.split(" ")
        s = int(float(line_list[5]) * 1000)
        e = s + int(float(line_list[8]) * 1000)
        speaker_ts.append([s, e, int(line_list[11].split("_")[-1])])
wsm = get_words_speaker_mapping(word_timestamps, speaker_ts, "start")

前面的代码确保了转录中的每个句子都正确地归属于某个说话人,考虑了口语片段的开始和结束时间。这一细致的映射对于理解对话动态(例如谁在何时说了什么)至关重要。它使得对多说话人对话、会议、访谈和音频内容的分析更加细致。

通过基于标点符号的重新对齐提升说话人归属

以下代码片段演示了标点符号如何决定每个句子的主要说话人。它使用一个预训练的标点符号模型kredor/punctuate-all,为转录的单词预测标点符号。然后,代码处理这些单词及其预测的标点符号,处理一些特殊情况,例如首字母缩略词(如 USA),以避免错误的标点符号。这种方法确保即使在其他说话人的背景评论或简短插话的情况下,每个句子的说话人归属也能保持一致。这在转录未指示说话人变化的情况下特别有用,例如当一个说话人的发言被另一个人的话语打断或重叠时。通过分析每个句子中每个单词的说话人标签分布,代码能够为整个句子分配一个一致的说话人标签,从而增强对话分段输出的连贯性:

if language in punct_model_langs:
    # restoring punctuation in the transcript to help realign the sentences
    punct_model = PunctuationModel(model="kredor/punctuate-all")
    words_list = list(map(lambda x: x["word"], wsm))
    labled_words = punct_model.predict(words_list)
    ending_puncts = ".?!"
    model_puncts = ".,;:!?"
    # We don't want to punctuate U.S.A. with a period. Right?
    is_acronym = lambda x: re.fullmatch(r"\b(?:[a-zA-Z]\.){2,}", x)
    for word_dict, labeled_tuple in zip(wsm, labled_words):
        word = word_dict["word"]
        if (
            word
            and labeled_tuple[1] in ending_puncts
            and (word[-1] not in model_puncts or is_acronym(word))
        ):
            word += labeled_tuple[1]
            if word.endswith(".."):
                word = word.rstrip(".")
            word_dict["word"] = word
else:
    logging.warning(
        f"Punctuation restoration is not available for {language} language. Using the original punctuation."
    )
wsm = get_realigned_ws_mapping_with_punctuation(wsm)
ssm = get_sentences_speaker_mapping(wsm, speaker_ts)

这种方法还解决了在主要说话人进行独白时,背景评论或简短插话发生的情况。代码有效地将主要的讲话内容归属于主说话人,而忽略其他人的零星评论。这使得语音片段与相应说话人的映射更加准确可靠,确保分段过程反映了对话的实际结构。

完成分段过程

在最后一部分,代码执行必要的清理任务,导出分段结果以供进一步使用,并将说话人 ID 替换为对应的名字。主要步骤包括以下内容:

  1. get_speaker_aware_transcript 函数生成一个包含文本内容和说话人信息的转录本。该转录本随后被保存为与输入音频文件同名的文件,但扩展名为.txt

    with open(f"{os.path.splitext(audio_path)[0]}.txt", "w", encoding="utf-8-sig") as f:
        get_speaker_aware_transcript(ssm, f)
    
  2. write_srt function 用于将分段结果导出为 SRT 格式。此格式通常用于字幕,并包括每个发言的说话人标签和精确的时间戳。SRT 文件将以与输入音频文件相同的名称保存,但扩展名为.srt

    with open(f"{os.path.splitext(audio_path)[0]}.srt", "w", encoding="utf-8-sig") as srt:
        write_srt(ssm, srt)
    
  3. 清理临时文件:清理功能删除在分段过程中创建的任何临时文件或目录。这一步确保了一个干净、井然有序的工作环境,释放了存储空间并保持系统效率:

    cleanup(temp_path)
    
  4. Speaker 0Speaker 1Speaker 2替换为实际说话人的名字:

    # Open the file
    with open(f"{os.path.splitext(audio_path)[0]}.txt", 'r') as f:
        text = f.read()
    # Replace the speaker IDs with names
    text = text.replace('Speaker 0','Ewa Jasiewicz')
    text = text.replace('Speaker 1','Chris Faulkner')
    text = text.replace('Speaker 2','Matt Frei')
    # Write the file to disk
    with open(audio_path[:-4] + '-with-speakers-names.txt', 'w') as f:
        f.write(text)
    

通过完成这些最终步骤,语音分离过程得以完成,结果可以用于进一步分析、后处理或与其他工具和工作流程的集成。导出的包含说话者信息的转录、SRT 文件和映射了说话者名称的转录提供了对音频录音内容和结构的宝贵洞见,为广泛应用提供了可能,如内容分析、说话者识别和字幕生成。

在深入研究该笔记本后,我们发现了一个关于使用前沿 AI 工具进行语音分离的宝贵宝藏。这本笔记本是一本实践指南,详细指导我们如何从复杂的音频文件中分离和转录语音。

第一个教训是如何设置正确的环境。该笔记本强调了安装特定依赖项的必要性,如 Whisper 和 NeMo,它们对于任务的执行至关重要。这一步是基础,为所有后续操作奠定了基础。

随着深入学习,我们了解了辅助函数的实用性。这些函数是默默奉献的英雄,它们简化了工作流程,从处理音频文件到处理时间戳和清理资源。它们体现了编写简洁、可重用代码的原则,大大降低了项目的复杂性。

该笔记本还介绍了使用 Demucs 将音乐从语音中分离的技术。这个步骤展示了预处理在提高分离准确性方面的强大作用。通过隔离人声,我们专注于语音的频谱和时间特征,这对于识别不同的说话者至关重要。

另一个关键收获是集成多个模型以获得更好的结果。该笔记本展示了如何使用 Whisper 进行转录,使用 Wav2Vec2 将转录与原始音频对齐。模型之间的协同作用是一个出色的例子,展示了如何结合不同的 AI 工具来实现更强大的解决方案。

将说话者映射到句子并通过标点符号重新对齐语音片段的过程尤其令人启发。它展示了语音分离的复杂性以及对细节的关注,确保每个说话者在转录中都得到准确表达。

从本质上讲,这本笔记本是一个关于 AI 在语音分离应用中的实用技巧的高级教程。它不仅教会了我们涉及的技术步骤,还传授了关于预处理重要性、结合不同 AI 模型的力量,以及细致后处理以确保最终输出完整性的更广泛教训。

总结

在本章中,我们开始了对 OpenAI Whisper 先进语音能力的激动人心的探索。我们深入研究了增强 Whisper 性能的强大技术,例如量化,并发现了它在说话者分离和实时语音识别中的潜力。

我们为 Whisper 增添了说话人分离功能,使其能够识别并将音频录音中的语音片段归属到不同的说话人。通过将 Whisper 与 NVIDIA NeMo 框架整合,我们学会了如何执行精准的说话人分离,为分析多说话人对话开辟了新天地。我们与 WhisperX 和 NVIDIA NeMo 的实操经验展示了将 Whisper 的转录能力与先进的说话人分离技术结合的强大潜力。

在本章中,我们深入理解了优化 Whisper 性能和通过说话人分离扩展其功能的高级技巧。通过动手编码示例和实用的见解,我们掌握了应用这些技巧的知识和技能,推动了 Whisper 的可能性边界。

当我们结束本章时,我们将展望第九章利用 Whisper 进行个性化语音合成。在那一章中,我们将获得预处理音频数据、微调语音模型以及使用个人语音合成模型生成逼真语音的知识和技能。动手编码示例和实用的见解将使你能够将这些技巧应用到你的项目中,推动个性化语音合成技术的边界。

跟随我继续与 Whisper 同行,准备迎接语音合成技术这一迅速发展的领域中的激动人心的可能性。