使用 Vosk 实现语音识别

在近两年里,如果说想要在本地部署离线语音识别模型,那么 Whisper 和 FunASR 肯定是首选项。所以为什么要使用 Vosk 呢?

优势

Vosk 是一个离线开源语音识别工具包,它的优点在于:

  1. 轻量:Vosk 提供轻量级的模型(小于 50MB 大小),可以用于低功耗平台(例如 Android、树莓派之类)
  2. 多编程语言、多平台支持:Python、Java、Node.js、C#、C++、Rust、Go 等
  3. 多语种支持:支持二十多种语言的识别(包括中文)
  4. 实时性:实时性语音识别场景下,vosk 的延迟非常低

简单来讲,你电脑中有 Python 环境,再下载一个 50 MB 的模型,就可以用 Vosk 实现一个正确率还可以接受的语言识别相关的项目。而像 Whisper 虽然识别效果好,但是对硬件要求很高,同时部署起来麻烦(例如需要配置 CUDA 环境),另外也不是很适用于实时性场景。

使用

这里以 Python 为例,首先安装 Vosk:pip3 install vosk pyaudio

音频文件识别 www.cqzlsb.com

以下代码实现对 test.wav 音频文件中语音内容的识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import wave
import sys
from vosk import KaldiRecognizer, Model, SetLogLevel

SetLogLevel(level=-1)

wf: wave.Wave_read = wave.open(os.path.join(dir_path, "test.wav"), "rb")
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
    print("Audio file must be WAV format mono PCM.")
    sys.exit(1)

model = Model(model_path="/path/to/vosk-model-small-en-us-0.15")

rec = KaldiRecognizer(model, wf.getframerate())
rec.SetWords(True)
rec.SetPartialWords(True)

while True:
    data = wf.readframes(4000)
    if len(data) == 0:
        break
    if rec.AcceptWaveform(data):
        print(rec.Result())
    else:
        print(rec.PartialResult())

print(rec.FinalResult())

解释一下上述 Vosk 相关代码调用:

  1. 首先 SetLogLevel(-1) 用来控制运行过程中日志打印,这里为了清晰的输出选择关闭日志。
  2. 之后初始化语音识别模型,这里通过指定模型路径的方式完成:Model(model_path="/path/to/vosk-model-small-en-us-0.15"),模型的下载地址可以参考官网
  3. 然后创建 KaldiRecognizer 对象,SetWords(True) 的作用是后续调用 Result() 和 FinalResult() 方法时将在输出中包含识别的单词及其时间戳,SetPartialWords(True) 同理。
  4. rec.AcceptWaveform(data) 相关代码的逻辑是:如果 AcceptWaveform() 方法返回 True,表明语音识别过程已经找到了一个或多个稳定的词语(比如,话语的间隙或者片段的终点),并且可以通过 Result() 方法获取完整的识别结果(返回识别的语句,可能包含了多个词语);如果返回 False,表明语音识别过程还在继续,还没找到稳定的词语,可以通过 PartialResult() 方法获取部分识别结果(返回的只是当前识别的部分信息,可能只包含一个或者部分词语)。
  5. 最后 rec.FinalResult() 用来在每次完成一段完整的音频处理(如一句话或一段对话)时调用,用于获取该段音频的最后一部分识别结果。

麦克风输入

以下代码利用 PyAudio 实现从麦克风中获取音频输入,并利用 Vosk 完成语言识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rec = KaldiRecognizer(model, 16000)
p = PyAudio()
stream = p.open(format=paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4096)
stream.start_stream()

try:
    while stream.is_active():
        data: bytes = stream.read(4096)
        if rec.AcceptWaveform(data):
            print(json.loads(rec.Result()))
        else:
            res = json.loads(rec.PartialResult())
            if res["partial"]:
                print(res['partial'])
except KeyboardInterrupt:
    print("KeyboardInterrupt...")
finally:
    stream.stop_stream()
    stream.close()
    p.terminate()

补充

  1. 如果只想获得识别结果文本,可以将 rec.Result() 改为 json.loads(rec.Result())["text"],将 rec.FinalResult() 改为 json.loads(rec.FinalResult())["text"]。但是注意 rec.PartialResult() 不存在 text 键。
  2. KaldiRecognizer 对象存在 Reset() 方法,调用它会重置识别器到初始状态,这意味着识别器会清除之前处理的所有音频数据和中间状态,使用 Reset() 方法可以在不创建新识别器的情况下开始新的一轮语音识别。
  3. KaldiRecognizer 对象存在 SetMaxAlternatives(num) 方法,用来设置识别结果的最大候选项数量,之后 Result() 和 FinalResult() 方法将会在输出中包含最容易识别为正确结果的 num 个候选项。
  4. KaldiRecognizer 对象可以使用 SetGrammar(json.dumps(grammar_list)) 方法,可以用它来设置特定的语法集,这意味着它定义了语音识别应该识别的确切词或短语模式。通俗的来讲,可以把它看作是为识别器编写的一个“听力测试”,测试中只包括预先编写好的词汇和句型。这样识别器就可以忽略无关的语音,只专注于理解这个集合中的内容。

猜你喜欢

转载自blog.csdn.net/weixin_48967543/article/details/142338862
今日推荐