NVIDIA开源ASR模型-Parakeet TDT 0.6B V2手把手部署教程

1. 引言

英伟达在5月1日发布了一款开源语音识别模型:Parakeet TDT 0.6B V2,其以 600M 参数登顶 Hugging Face Open ASR 榜单。官方链接:nvidia/parakeet-tdt-0.6b-v2

  • 极致转录效率:60 分钟音频仅需 1 秒内完成转录(A100 推理)
  • OpenASR 榜首表现:超越 Whisper、Conformer、Wav2Vec 等主流闭源模型
  • 极小参数量:仅 0.6B(轻量级,适合边缘设备)
  • 高精度:平均 WER 6.05%(Hugging Face Open ASR 榜单),优于 Whisper-large-v3
  • 高鲁棒性:多语速、多口音、多录音环境下表现稳定(英文)

2. 环境准备

部署环境基于NVIDIA nemo框架,现在开始,
首先,确保电脑环境安装好了Anaconda

conda create --name nemo_py310 python=3.10
conda activate nemo_py310
conda install -c conda-forge cmake
pip install sentencepiece
pip install -U nemo_toolkit["asr"]

为了充分发挥 TDT 模型在某些解码环节的性能(如 CUDA graphs with while loops),NeMo 会提示安装 cuda-python。如果需要,可以运行(此步骤可选,不安装也能运行,但可能会有性能提示),若想要部署cuda环境,详细见:

pip install cuda-python>=12.3 # 请根据您环境的CUDA主版本选择合适的cuda-python版本

3. 编写推理脚本

我们将编写一个 Python 脚本来加载模型、处理音频、执行转录,并计算一些性能指标。
新建Python 代码保存为文件,例如 run_parakeet_transcribe.py。

脚本概览

脚本主要包含以下部分:

  • 配置模型名称和音频路径。
  • 加载 Parakeet-TDT-0.6B-V2 模型。
  • 读取音频文件并获取时长。
  • 执行语音转文字的推理。
  • 提取转录文本,计算每分钟字数 (WPM) 和近似实时因子 (RTFx)。
  • 将转录结果保存到 .txt 文件。
  • (可选)集成 NVTX 标记,便于使用 NVIDIA Nsight Systems 进行性能剖析。

代码详解

run_parakeet_transcribe.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import nemo.collections.asr as nemo_asr
import torch
import time
import wave # 用于获取 .wav 文件时长
import os

# --- 配置参数 ---
# 重要:如果您已手动下载模型,请修改此处为您的 .nemo 文件绝对路径
# MODEL_NAME = "nvidia/parakeet-tdt-0.6b-v2" # 在线下载模式
MODEL_NAME = "/home/garyhuang/ASR/parakeet-tdt-0.6b-v2.nemo" # 离线加载模式,替换为您的实际路径

AUDIO_FILE_PATH = "/home/garyhuang/ASR/2086-149220-0033.wav" # 替换为您的音频文件路径
TARGET_WPM = 400 # 目标每分钟字数

# --- NVTX 辅助类 (可选,用于性能分析) ---
class NvtxTracer:
    def __init__(self, name: str):
        self.name = name
    def __enter__(self):
        if torch.cuda.is_available():
            torch.cuda.nvtx.range_push(self.name)
    def __exit__(self, type, value, traceback):
        if torch.cuda.is_available():
            torch.cuda.nvtx.range_pop()

# --- 音频处理函数 ---
def get_audio_duration_wav(filepath: str) -> float:
    try:
        with wave.open(filepath, 'r') as wf:
            frames = wf.getnframes()
            rate = wf.getframerate()
            duration = frames / float(rate)
            return duration
    except wave.Error as e:
        print(f"错误:无法读取WAV文件 {filepath}: {e}")
        return 0.0
    except FileNotFoundError:
        print(f"错误:音频文件未找到于 {filepath}")
        return 0.0

# --- 主程序 ---
def main():
    print("--- ASR 性能测试脚本 (Parakeet TDT 0.6B V2) ---")

    if not os.path.exists(AUDIO_FILE_PATH):
        print(f"错误:音频文件未找到于 {AUDIO_FILE_PATH}")
        return
    
    # 检查模型文件路径是否有效(尤其对于离线加载)
    # 如果MODEL_NAME是HuggingFace ID,则此检查不适用,由NeMo内部处理下载
    if "/" in MODEL_NAME and not os.path.exists(MODEL_NAME): # 简单判断是否为路径
        print(f"错误:本地模型文件未找到于 {MODEL_NAME}")
        return

    print(f"\n正在加载模型: {MODEL_NAME}...")
    asr_model = None
    load_time_start = time.perf_counter()
    with NvtxTracer("ModelLoading"):
        try:
            # 如果 MODEL_NAME 是 HuggingFace ID (如 "nvidia/parakeet-tdt-0.6b-v2")
            # 且希望强制在线下载,或者首次使用,可以用 from_pretrained:
            # asr_model = nemo_asr.models.ASRModel.from_pretrained(model_name=MODEL_NAME)

            # 如果 MODEL_NAME 是本地 .nemo 文件路径,推荐使用 restore_from:
            if "/" in MODEL_NAME: # 再次判断是否为路径
                 asr_model = nemo_asr.models.ASRModel.restore_from(restore_path=MODEL_NAME)
            else: # 否则认为是HuggingFace ID
                 asr_model = nemo_asr.models.ASRModel.from_pretrained(model_name=MODEL_NAME)

        except Exception as e:
            print(f"加载模型时发生错误: {e}")
            print("请检查模型名称/路径,网络连接(如果在线下载),或文件是否损坏。")
            return
    load_time_end = time.perf_counter()
    model_load_duration = load_time_end - load_time_start
    print(f"模型加载完成,耗时: {model_load_duration:.2f} 秒")

    if torch.cuda.is_available():
        print("CUDA 可用,将模型移至 GPU。")
        asr_model = asr_model.cuda()
    else:
        print("警告:CUDA 不可用。模型将在 CPU 上运行,性能会显著降低。")

    print(f"\n准备转录音频文件: {AUDIO_FILE_PATH}")
    audio_duration_seconds = get_audio_duration_wav(AUDIO_FILE_PATH)
    if audio_duration_seconds == 0: return
    audio_duration_minutes = audio_duration_seconds / 60.0
    print(f"音频时长: {audio_duration_seconds:.2f} 秒 ({audio_duration_minutes:.2f} 分钟)")

    transcribed_text = ""
    word_count = 0
    inference_duration = 0

    try:
        with NvtxTracer("PreProcessing"):
            paths2audio_files = [AUDIO_FILE_PATH]
            print("预处理阶段完成 (主要由模型内部处理)。")

        print("\n开始推理...")
        inference_time_start = time.perf_counter()
        with NvtxTracer("Inference"):
            # 将路径列表作为第一个位置参数传入
            hypotheses = asr_model.transcribe(paths2audio_files, batch_size=1)
        inference_time_end = time.perf_counter()
        inference_duration = inference_time_end - inference_time_start
        print(f"推理完成,耗时: {inference_duration:.2f} 秒")

        with NvtxTracer("PostProcessing"):
            print("\n开始后处理...")
            if hypotheses and len(hypotheses) > 0:
                # Parakeet TDT 模型卡片示例的输出结构
                if hasattr(hypotheses[0], 'text'):
                    transcribed_text = hypotheses[0].text
                # 其他可能的输出格式处理
                elif isinstance(hypotheses[0], str):
                    transcribed_text = hypotheses[0]
                elif isinstance(hypotheses[0], list) and len(hypotheses[0]) > 0 and isinstance(hypotheses[0][0], str) :
                    transcribed_text = hypotheses[0][0]
                else:
                    print(f"警告:未知的转录输出格式: {type(hypotheses[0])}。")
                    transcribed_text = str(hypotheses[0])
                word_count = len(transcribed_text.split())
                print("后处理完成。")
            else:
                transcribed_text = "错误:转录未返回任何结果。"
                word_count = 0
    except Exception as e:
        print(f"\n处理过程中发生未知错误: {e}")
        return

    if transcribed_text and word_count > 0 :
        output_txt_filename = os.path.splitext(AUDIO_FILE_PATH)[0] + ".txt"
        try:
            with open(output_txt_filename, 'w', encoding='utf-8') as f:
                f.write(transcribed_text)
            print(f"\n转录结果已保存到: {output_txt_filename}")
        except IOError as e:
            print(f"\n错误:无法写入转录结果到文件 {output_txt_filename}: {e}")

    print(f"\n--- 结果分析 ---")
    print(f"转录文本: \"{transcribed_text}\"")
    print(f"总字数: {word_count}")
    print("\n--- 测试结束 ---")

if __name__ == "__main__":
    main()

4. 准备工作与运行脚本

下载模型(离线部署)

如果您的服务器网络访问 Hugging Face 不稳定,或者您希望进行离线部署:

  1. 手动下载 .nemo 文件
    • 下载链接:https://huggingface.co/nvidia/parakeet-tdt-0.6b-v2/resolve/main/parakeet-tdt-0.6b-v2.nemo
    • 将下载的文件(例如 parakeet-tdt-0.6b-v2.nemo)放置到您服务器的某个目录下,比如我们示例中的 /home/garyhuang/ASR/
  2. 修改脚本中的 MODEL_NAME
    确保脚本中的 MODEL_NAME 变量指向这个本地文件的绝对路径,并确保加载模型时使用的是 ASRModel.restore_from(restore_path=MODEL_NAME)

如果网络良好,您可以直接将 MODEL_NAME 设置为 "nvidia/parakeet-tdt-0.6b-v2",脚本首次运行时会自动下载。

准备音频文件

  • 准备一个 .wav.flac 格式的音频文件。模型期望输入是 16kHz 的单声道音频。
  • 将音频文件路径更新到脚本中的 AUDIO_FILE_PATH 变量。

执行脚本

  1. 将上述 Python 代码保存为文件,例如 run_parakeet_transcribe.py
  2. 在终端中,进入脚本所在目录,然后运行:
    python run_parakeet_transcribe.py
    
    如果想同时使用 NVIDIA Nsight Systems 进行性能剖析:
    nsys profile -o parakeet_profile --stats=true python run_parakeet_transcribe.py
    
    之后可以用 nsys-ui parakeet_profile.nsys-rep (或 .qdrep) 文件打开分析报告。

5. 解读输出结果

脚本运行成功后,会看到类似以下的命令行输出:

--- ASR 性能测试脚本 (Parakeet TDT 0.6B V2) ---
... (模型加载日志) ...
模型加载完成,耗时: 8.90 秒
CUDA 可用,将模型移至 GPU。

准备转录音频文件: /home/garyhuang/ASR/2086-149220-0033.wav
音频时长: 7.43 秒 (0.12 分钟)
预处理阶段完成 (主要由模型内部处理)。

开始推理...
Transcribing: 100%|██████████| 1/1 [00:01<00:00,  1.45s/it]
推理完成,耗时: 1.46 秒

开始后处理...
后处理完成。

转录结果已保存到: /home/garyhuang/ASR/2086-149220-0033.txt

--- 结果分析 ---
转录文本: "Well, I don't wish to see it any more, observed Phebe, turning away her eyes. It is certainly very like the old portrait."
总字数: 23
每分钟字数 (WPM): 185.61
--- 测试结束 ---
  • 转录文本: 模型识别出的语音内容。
  • TXT 文件: 转录文本会保存到与输入音频文件同名(扩展名为.txt)的文件中。
  • WPM 和 RTFx: 性能指标,详见下文。

也会看到在文件目录下出现以下结构:
在这里插入图片描述
2086-149220-0033的转录结果如下:
在这里插入图片描述

6. 常见问题与排错锦囊

在我们探索过程中,遇到了一些典型问题,这里总结一下:

网络错误导致模型下载失败

  • 症状: MaxRetryError, NewConnectionError: [Errno 101] Network is unreachable
  • 原因: 无法连接到 Hugging Face 下载模型。
  • 解决:
    1. 检查服务器网络。
    2. 如无法解决,采用手动下载 .nemo 文件的方式(见上文),并在脚本中通过 ASRModel.restore_from(restore_path="本地路径") 加载。
    3. 具体操作可参考模型权重下载方法中 light-hf-proxy方法

加载本地模型文件路径问题

  • 症状: Repo id must be in the form 'repo_name' or 'namespace/repo_name': '/path/to/your.nemo'. Use repo_type argument if needed.
  • 原因: 使用 ASRModel.from_pretrained(model_name="本地路径") 时,NeMo 可能将本地路径误认为 Hugging Face 仓库 ID。
  • 解决: 明确使用 ASRModel.restore_from(restore_path="本地路径") 来加载本地 .nemo 文件。

transcribe() 参数错误

  • 症状: TypeError: EncDecRNNTModel.transcribe() got an unexpected keyword argument 'paths2audio_files'
  • 原因: transcribe() 函数期望音频文件列表作为第一个位置参数,而非关键字参数。
  • 解决: 将 asr_model.transcribe(paths2audio_files=my_audio_list, ...) 修改为 asr_model.transcribe(my_audio_list, ...)

性能警告:cuda-python 缺失

  • 症状: No conditional node support for Cuda. ... Reason: No cuda-python module. Please do pip install cuda-python>=12.3
  • 原因: 缺少 cuda-python 包,导致 TDT 解码器中某个 CUDA 优化无法启用。
  • 解决: (可选)安装 pip install cuda-python>=12.3(版本需与您的CUDA主版本匹配)以获取潜在的性能提升。不安装不影响基本功能。

7. 性能指标浅析

  • WPM (Words Per Minute - 每分钟字数):
    • 计算公式: 总字数 / (音频时长_秒 / 60)
    • 反映了在给定音频上的有效转录速率。是衡量ASR系统吞吐量的一个用户友好指标。
  • RTFx (Real-Time Factor - 实时因子):
    • 计算公式: 音频时长_秒 / 推理耗时_秒
    • 表示模型处理音频的速度是其实际播放速度的多少倍。例如,RTFx 为 5.0 意味着处理10秒的音频仅需2秒。RTFx > 1 表示快于实时。

这些指标受硬件、音频质量、模型大小等多种因素影响。

8. 总结与展望

如果想要转录自己的音频文件,只需替换“2086-149220-0033.wav”和脚本中的“2086-149220-0033.wav”即可.
最后,所有的项目文件我打包放在这里了:
通过网盘分享的文件:NVIDIA-parakeet-tdt-0.6b-v2
链接: https://pan.baidu.com/s/1VNOoPqTJzUwo3mD37NhQwA?pwd=jrh7 提取码: jrh7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉均

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值