【详细代码拆解】PaddleSpeech学习笔记(流式)

流式模型的解析比较简单,相同的地方在此篇不再赘述,都是设置断点后从utils.py经过装饰器stats_wrapper和函数_parse_args_以及_note_one_stat函数最终进入到真正的处理。

【详细代码拆解】PaddleSpeech学习笔记(非流式)_paddlespeech cli-CSDN博客

流式模型结构简介

【飞桨PaddleSpeech语音技术课程】— 语音识别-流式服务_流式语音识别-CSDN博客

更详细的说明在此博客。

相比非流式模型,流式模型在处理音频流时无需等待完整句音频输入,从而提高了处理效率。

在流式语音识别系统中,客户端(client)与服务器(server)之间需要维持一个持久的、长时间的数据交互过程。这一过程中,客户端不断地将音频数据实时传输至服务器,而服务器则负责对这些数据进行即时语音识别,并将识别出的文本结果实时回传给客户端。为了实现这种高效且实时的数据交换,客户端与服务器之间必须保持一个稳定的网络连接。

PaddleSpeech,作为一个强大的语音识别框架,采用了WebSocket协议来确保客户端与服务器之间能够长时间稳定地保持连接。WebSocket协议以其支持全双工通信的特性而著称,这意味着在同一网络连接上,客户端和服务器可以同时发送和接收消息,无需像传统HTTP请求那样频繁地建立和断开连接。

从上面的介绍可以看出来,主要处理都是在服务端,客户端主要是发送读取好的音频数据。这点对于后续的学习理解比较重要。也是由于这个特性,必须要开启两个python文件,或者是开两个终端,把服务器挂好,再去使用客户端请求

ps:吐槽一下流式模型的代码真的很难找,非流式因为没有采用websocket设断点一下就进去了,也有可能是因为我太菜了。

代码部署

此处参考官方readme文档,可以使用命令行,或者是python文件。

1. 安装

安装 PaddleSpeech 的详细过程请看 安装文档

推荐使用 paddlepaddle 2.3.1 或以上版本。

你可以从简单,中等,困难 几种方式中选择一种方式安装 PaddleSpeech。

如果使用简单模式安装,需要自行准备 yaml 文件,可参考 conf 目录下的 yaml 文件。

2. 准备配置文件

流式ASR的服务启动脚本和服务测试脚本存放在 PaddleSpeech/demos/streaming_asr_server 目录。 下载好 PaddleSpeech 之后,进入到 PaddleSpeech/demos/streaming_asr_server 目录。 配置文件可参见该目录下 conf/ws_application.yaml 和 conf/ws_conformer_wenetspeech_application.yaml 。

目前服务集成的模型有: DeepSpeech2 和 conformer模型,对应的配置文件如下:

  • DeepSpeech: conf/ws_application.yaml
  • conformer: conf/ws_conformer_wenetspeech_application.yaml

这个 ASR client 的输入应该是一个 WAV 文件(.wav),并且采样率必须与模型的采样率相同。

可以下载此 ASR client的示例音频:

wget -c https://paddlespeech.bj.bcebos.com/PaddleAudio/zh.wav 

3. 服务端使用方法

  • 命令行 (推荐使用) 注意: 默认部署在 cpu 设备上,可以通过修改服务配置文件中 device 参数部署在 gpu 上。
# 在 PaddleSpeech/demos/streaming_asr_server 目录启动服务
paddlespeech_server start --config_file ./conf/ws_conformer_wenetspeech_application.yaml
# 你如果愿意为了增加解码的速度而牺牲一定的模型精度,你可以使用如下的脚本 
 paddlespeech_server start --config_file ./conf/ws_conformer_wenetspeech_application_faster.yaml
  •  python文件代码
# 在 PaddleSpeech/demos/streaming_asr_server 目录
from paddlespeech.server.bin.paddlespeech_server import ServerExecutor

server_executor = ServerExecutor()
server_executor(
    config_file="./conf/ws_conformer_wenetspeech_application", 
    log_file="./log/paddlespeech.log")

4. 客户端使用方法

  • 命令行 (推荐使用)

若 127.0.0.1 不能访问,则需要使用实际服务 IP 地址

paddlespeech_client asr_online --server_ip 127.0.0.1 --port 8090 --input ./zh.wav
  • python文件代码
from paddlespeech.server.bin.paddlespeech_client import ASROnlineClientExecutor

asrclient_executor = ASROnlineClientExecutor()
res = asrclient_executor(
    input="./zh.wav",
    server_ip="127.0.0.1",
    port=8090,
    sample_rate=16000,
    lang="zh_cn",
    audio_format="wav")
print(res)

代码拆解

客户端Client

从该处设置断点进入

下一个断点在这里

则进入核心部分,客户端启动websocket服务,handler.run(input)是启动WebSocket连接、发送音频数据到服务器、接收并处理识别结果的异步函数。

进入断点,主要执行如下代码,分为六段。

  1. 发送WebSocket握手协议
  2. 服务器已接收握手协议,客户端开始发送命令
  3. 客户端通过self.read_wave(wavfile_path)方法读取音频文件,并分块发送音频数据到服务器。对于每个数据块,客户端都发送数据并等待服务器的响应,然后打印响应内容。
  4. 当所有音频数据块都发送完毕后,客户端发送一个包含signalend的JSON消息,通知服务器音频文件处理结束。
  5. 客户端将接收到的字节消息解码为JSON对象。如果配置了标点服务器(self.punc_server),并且识别结果非空,则对识别结果进行标点恢复处理。
  6. 记录最终结果和统计信息

        # 1. send websocket handshake protocal
        start_time = time.time()
        async with websockets.connect(self.url) as ws:
            # 2. server has already received handshake protocal
            # client start to send the command
            audio_info = json.dumps(
                {
                    "name": "test.wav",
                    "signal": "start",
                    "nbest": 1
                },
                sort_keys=True,
                indent=4,
                separators=(',', ': '))
            await ws.send(audio_info)
            msg = await ws.recv()
            logger.info("client receive msg={}".format(msg))

            # 3. send chunk audio data to engine
            for chunk_data in self.read_wave(wavfile_path):
                await ws.send(chunk_data.tobytes())
                msg = await ws.recv()
                msg = json.loads(msg)
                logger.info("client receive msg={}".format(msg))
            #client start to punctuation restore
            if self.punc_server and len(msg['result']) > 0:
                msg["result"] = self.punc_server.run(msg["result"])
                logger.info("client punctuation restored msg={}".format(msg))
            # 4. we must send finished signal to the server
            audio_info = json.dumps(
                {
                    "name": "test.wav",
                    "signal": "end",
                    "nbest": 1
                },
                sort_keys=True,
                indent=4,
                separators=(',', ': '))
            await ws.send(audio_info)
            msg = await ws.recv()

            # 5. decode the bytes to str
            msg = json.loads(msg)

            if self.punc_server:
                msg["result"] = self.punc_server.run(msg["result"])

            # 6. logging the final result and comptute the statstics
            elapsed_time = time.time() - start_time
            audio_info = soundfile.info(wavfile_path)
            logger.info("client final receive msg={}".format(msg))
            logger.info(
                f"audio duration: {audio_info.duration}, elapsed time: 0.0698, RTF={elapsed_time/audio_info.duration}"
            )

            result = msg

服务端Server

与客户端断点类似,进入核心部分。主要在paddlespeech_server.py文件。

首先初始化api,进入模型调用。

注意有两个asr_engine.py文件,不过是在不同路径下。self.executor初始化了服务端执行器。

而该类又继承了ASRExecutor,声明在infer.py。就是之前非流式同一个模型,U2Model。这个还是稍微有些不同的。

这里多嘴一下,我找他的模型类是为了对官方模型做微调训练,因为官方的预训练工具paddlehub不支持对asr进行训练,只能自己找封装接口,流式的比较难找,找了好久发现还是同一个。之所以怀疑流式和非流式官方没给同一个封装是因为流式(online)模型的参数文件大小有490M,非流式460M,我拿流式训练完用官方paddle.save保存也是460M。为了验证,我直接在官方代码处存了一份参数,490M存完也变成460M,很奇怪,但是我用460M的取代490M的参数文件,模型能正常用。如果用懂的佬可以评论区解答一下。

初始化完模型之后,再进行系列websocket的初始化,就开始准备接受客户端数据了。最终循环会在__call__函数的unicorn.run处。使用uvicorn.run(app, host=config.host, port=config.port)启动uvicorn服务器,其中app是ASGI应用实例,hostport分别从config对象中获取服务器的地址和端口号。这样,uvicorn就会根据提供的配置信息启动服务器,并运行app应用。

服务端正常运行~

如何微调PPASR后续会出总结帖,可以蹲蹲更新。

  • 23
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值