【PaddleSpeech进阶】语音合成-onnx模型使用

2023-11-04 08:59

本文主要是介绍【PaddleSpeech进阶】语音合成-onnx模型使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

很多同学对PaddleSpeech发布的语音合成onnx模型的使用比较感兴趣,这篇教程将教会你如何使用PaddleSpeech提供的语音合成预训练模型完成推理工作。

0. PaddleSpeech 介绍

🚀 PaddleSpeech 是 all-in-one 的语音算法工具箱,包含多种领先国际水平的语音算法与预训练模型。你可以从中选择各种语音处理工具以及预训练模型,支持语音识别,语音合成,声音分类,声纹识别,标点恢复,语音翻译等多种功能,PaddleSpeech Server模块可帮助用户快速在服务器上部署语音服务。PaddleSpeech团队发表的论文 An Easy-to-Use All-in-One Speech Toolkit 入选 NAACL2022 ,荣获 NAACL2022 Best Demo Award

喜欢的同学可以点个 ⭐️star⭐️ 支持我们,PaddleSpeech传送门:https://github.com/PaddlePaddle/PaddleSpeech

🎁 学习过程中你遇到任何问题,可以加入PaddleSpeech的交流群进行讨论。

 

1. 初步认识onnxruntime推理流程

使用onnxruntime推理PaddleSpeech提供的语音合成onnx模型只需要四个步骤:

  1. 文本前端
  2. 加载模型,创建Session
  3. 模型推理
  4. 音频保存

2. 配置PaddleSpeech开发环境

你可以通过PaddleSpeech的源码进行安装

In [ ]

# 安装PaddleSpeech
!git clone https://gitee.com/paddlepaddle/PaddleSpeech.git
%cd PaddleSpeech
!pip install pytest-runner
!pip install .

In [ ]

# aistudio会报错: paddlespeech 的 repo中存在失效软链接
# 执行下面这行命令!!
!find -L /home/aistudio -type l -delete

In [ ]

# 下载模型模型
%cd /home/aistudio/work
!wget https://paddlespeech.bj.bcebos.com/Parakeet/released_models/fastspeech2/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0.zip
!wget https://paddlespeech.bj.bcebos.com/Parakeet/released_models/mb_melgan/mb_melgan_csmsc_onnx_0.2.0.zip
!unzip fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0.zip
!unzip mb_melgan_csmsc_onnx_0.2.0.zip

In [ ]


# 下载nltk数据包,如果项目中有就不用下载了
%cd /home/aistudio
!wget -P data https://paddlespeech.bj.bcebos.com/Parakeet/tools/nltk_data.tar.gz
!tar zxvf data/nltk_data.tar.gz

3. TTS文本前端

PaddleSpeech提供的文本前端可以帮助我们把中文文本转换成模型推理需要的音素序列

In [3]

phones_dict = "/home/aistudio/work/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0/phone_id_map.txt"

In [ ]

from paddlespeech.t2s.frontend.zh_frontend import Frontendfrontend = Frontend(phone_vocab_path=phones_dict,tone_vocab_path=None)

In [ ]

text = "今天天气真的很不错,我想出去玩!"
input_ids = frontend.get_input_ids(text,merge_sentences=True, # 是否按符号拆分句子get_tone_ids=False)
input_ids = input_ids['phone_ids']
print(input_ids)

4. 加载模型,创建Onnxruntime Session

创建onnxruntime的session,用于推理

In [ ]

import onnxruntime as ort# 模型路径
onnx_am_encoder = "/home/aistudio/work/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0/fastspeech2_csmsc_am_encoder_infer.onnx"
onnx_am_decoder = "/home/aistudio/work/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0/fastspeech2_csmsc_am_decoder.onnx"
onnx_am_postnet = "/home/aistudio/work/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0/fastspeech2_csmsc_am_postnet.onnx"
onnx_voc_melgan = "/home/aistudio/work/mb_melgan_csmsc_onnx_0.2.0/mb_melgan_csmsc.onnx"# 用CPU推理
providers = ['CPUExecutionProvider']# 配置ort session
sess_options = ort.SessionOptions()# 创建session
am_encoder_infer_sess = ort.InferenceSession(onnx_am_encoder, providers=providers, sess_options=sess_options)
am_decoder_sess = ort.InferenceSession(onnx_am_decoder, providers=providers, sess_options=sess_options)
am_postnet_sess = ort.InferenceSession(onnx_am_postnet, providers=providers, sess_options=sess_options)
voc_melgan_sess = ort.InferenceSession(onnx_voc_melgan, providers=providers, sess_options=sess_options)

5. 模型推理

In [7]

# 辅助函数 denorm, 训练过程中mel输出经过了norm,使用过程中需要进行denorm
import numpy as np
am_stat_path = r"/home/aistudio/work/fastspeech2_cnndecoder_csmsc_streaming_onnx_1.0.0/speech_stats.npy"
am_mu, am_std = np.load(am_stat_path)

In [8]

from paddlespeech.server.utils.util import denorm
# 推理阶段封装
# 端到端合成:一次性把句子全部合成完毕
def inference(text):phone_ids = frontend.get_input_ids(text, merge_sentences=True, get_tone_ids=False)['phone_ids']orig_hs = am_encoder_infer_sess.run(None, input_feed={'text': phone_ids[0].numpy()})hs = orig_hs[0]am_decoder_output = am_decoder_sess.run( None, input_feed={'xs': hs})am_postnet_output = am_postnet_sess.run(None,input_feed={'xs': np.transpose(am_decoder_output[0], (0, 2, 1))})am_output_data = am_decoder_output + np.transpose(am_postnet_output[0], (0, 2, 1))normalized_mel = am_output_data[0][0]mel = denorm(normalized_mel, am_mu, am_std)wav = voc_melgan_sess.run(output_names=None, input_feed={'logmel': mel})[0]return wav

6. 音频保存

In [10]

# 保存为wav,播放体验
import soundfile as sf
import time
text = "欢迎使用飞桨语音合成系统,测试一下合成效果。"
t1 = time.time()
wav = inference(text)
print("合成耗时:", time.time() - t1)
sf.write("demo.wav", wav, samplerate=24000)
合成耗时: 6.246196746826172

In [11]

import IPython.display as dp
dp.Audio("demo.wav")
<IPython.lib.display.Audio object>

7. 流式语音合成

流式语音合成需要流式播放才能起到展示效果,思路上是把各个流程进行分片,然后再分块合成,播放器同时流式播放。

流式播放需要声卡支持,建议放到自己的笔记本上进行播放,aistudio 上不便于展示,只展示拼接在一起的结果,不进行流式播放展示

将 streaming_tts.py下载到本机,按上面的步骤下载好模型,安装好PaddleSpeech即可(注意nltk_data,下载速度较慢,建议按上面方式提前下载好)

需要安装 pyaudio

In [12]

# 配置流式参数
import math
from paddlespeech.server.utils.util import get_chunksvoc_block = 36
voc_pad = 14
am_block = 72
am_pad = 12
voc_upsample = 300def depadding(data, chunk_num, chunk_id, block, pad, upsample):""" Streaming inference removes the result of pad inference"""front_pad = min(chunk_id * block, pad)# first chunkif chunk_id == 0:data = data[:block * upsample]# last chunkelif chunk_id == chunk_num - 1:data = data[front_pad * upsample:]# middle chunkelse:data = data[front_pad * upsample:(front_pad + block) * upsample]return datadef inference_stream(text):input_ids = frontend.get_input_ids(text,merge_sentences=False,get_tone_ids=False)phone_ids = input_ids["phone_ids"]print(phone_ids)for i in range(len(phone_ids)):# 先分句# am voc_chunk_id = 0orig_hs = am_encoder_infer_sess.run(None, input_feed={'text': phone_ids[i].numpy()})orig_hs = orig_hs[0]# streaming voc chunk infomel_len = orig_hs.shape[1]voc_chunk_num = math.ceil(mel_len / voc_block)start = 0end = min(voc_block + voc_pad, mel_len)# streaming amhss = get_chunks(orig_hs, am_block, am_pad, "am")am_chunk_num = len(hss)for i, hs in enumerate(hss):am_decoder_output = am_decoder_sess.run(None, input_feed={'xs': hs})am_postnet_output = am_postnet_sess.run(None,input_feed={'xs': np.transpose(am_decoder_output[0], (0, 2, 1))})am_output_data = am_decoder_output + np.transpose(am_postnet_output[0], (0, 2, 1))normalized_mel = am_output_data[0][0]sub_mel = denorm(normalized_mel, am_mu, am_std)sub_mel = depadding(sub_mel, am_chunk_num, i,am_block, am_pad, 1)if i == 0:mel_streaming = sub_melelse:mel_streaming = np.concatenate((mel_streaming, sub_mel), axis=0)# streaming voc# 当流式AM推理的mel帧数大于流式voc推理的chunk size,开始进行流式voc 推理while (mel_streaming.shape[0] >= end andvoc_chunk_id < voc_chunk_num):voc_chunk = mel_streaming[start:end, :]sub_wav = voc_melgan_sess.run(output_names=None, input_feed={'logmel': voc_chunk})sub_wav = depadding(sub_wav[0], voc_chunk_num, voc_chunk_id,voc_block, voc_pad, voc_upsample)yield sub_wavvoc_chunk_id += 1start = max(0, voc_chunk_id * voc_block - voc_pad)end = min((voc_chunk_id + 1) * voc_block + voc_pad,mel_len)

In [13]

text = "欢迎使用飞桨语音合成系统,测试一下合成效果。"
wavs = []
t1 = time.time()
for sub_wav in inference_stream(text):print("响应时间:", time.time() - t1)t1 = time.time()wavs.append(sub_wav.flatten())
wav = np.concatenate(wavs)
print(wav.shape)
sf.write("demo_stream.wav",data=wav, samplerate=24000)
[Tensor(shape=[21], dtype=int64, place=Place(cpu), stop_gradient=True,[71 , 199, 126, 177, 115, 138, 69 , 46 , 151, 89 , 241, 120, 71 , 42 ,39 , 57 , 260, 75 , 182, 163, 179]), Tensor(shape=[16], dtype=int64, place=Place(cpu), stop_gradient=True,[38 , 44 , 177, 116, 73 , 260, 80 , 71 , 42 , 39 , 57 , 260, 99 , 70 ,232, 179])]
响应时间: 1.4043552875518799
响应时间: 1.4002647399902344
响应时间: 1.2040159702301025
响应时间: 0.8999142646789551
响应时间: 0.8972508907318115
响应时间: 1.100409746170044
响应时间: 0.19948339462280273
响应时间: 1.9018454551696777
响应时间: 1.303241491317749
响应时间: 0.9031462669372559
响应时间: 1.1989772319793701
响应时间: 0.7002658843994141
(110100,)

In [14]

dp.Audio("demo_stream.wav")
<IPython.lib.display.Audio object>

8. 总结

通过上面教程的学习,相信你已经熟练掌握了如何使用onnxruntime来推理PaddleSpeech提供的预训练onnx模型,希望本教程能对你有所帮助。

遇到问题,可以加入 PaddleSpeech 技术交流群,和 PaddleSpeech 的开发者们一起交流讨论。

 

这篇关于【PaddleSpeech进阶】语音合成-onnx模型使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/344681

相关文章

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.