前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >音频知识(六)--LPCNet语音合成模型

音频知识(六)--LPCNet语音合成模型

原创
作者头像
languageX
发布2022-10-01 10:19:22
1.4K0
发布2022-10-01 10:19:22
举报
文章被收录于专栏:计算机视觉CV计算机视觉CV

最近学习了语音合成方面的知识,总结下LPCNet的算法结构和工程流程。

深度神经网络比如WaveNet在语音合成中效果好但是由于计算复杂度高很难实时;DSP速度快,但是合成质量不高。LPCNet结合了信号处理和深度神经网络提升语音合成的效果。

语音合成

上世纪70年代,人们就开始研究如何对语音进行建模。source_filter模型认为语音可以通过信源和信道两个模块;信源部分将浊音近似为一系列规则间隔的脉冲,清音通过白噪声近似;信道部分可以用LPC滤波器建模。如下图所示

2016年DeepMind提出了WaveNet,基于深度神经网络进行语音合成。WaveNet每个音频点不是直接预测,而是有一个预测和采样的过程,官网解释这里为什么不直接选取最大值而是有一个采样过程是因为语音本身有一定的随机性,如果全部选取概率最大可能就会出现全0的情况。WaveNet能生成高质量的音频,但是复杂度太高所以无法实时。

WaveRNN的提出优化了性能问题,使用RNN和稀疏矩阵降低复杂度,但是还是需要大约10GFLOPS。

LPCNet算法

LPCNet基于WaveRNN为基础,加入LPC filter模块降低神经网络复杂度。他将采样点的预测分解为线性和非线性两部分,基于DSP来预测线性部分,基于神经网络预测较小的非线性残余部分。

LPCNet的网络结构

LPCNet分为FRN和SRN两部分,FRN是以帧级为单位进行操作,项目中以10ms(160采样点)为一帧,一帧计算一次;SRN是以样点为单位,每个采样点都要执行一次,一帧计算160次。

LPCNet结构解析

feature:

输入:训练阶段,15帧(2400个采样点)

输出: [15,20]特征数据

每帧提取的特征,工程中保存了36维的数据,网络使用了20维特征(18个BFCC,2个pitch参数pitch,gain),计算LPC需要16个系数。

其中BFCC的计算和MFCC类似,仅在频带划分有差异(MFCC可参考之前的文章https://cloud.tencent.com/developer/article/1831454)

compute LPC:

输入:前16个采样点{s_{t-16},S_{t-1}},和本帧16个LPC系数

输出:线性预测当前采样点P_t

使用LPC系数和前16个采样点预测下一个采样点Pt

FRN:

输入:feature特征[N,19,20]

输出:通过卷积和全连接层后,得到[N,19,C]特征

feature通过两层卷积和全连接,训练过程使用15帧(2400个采样点),由于要经过两次conv,所以要pad到19。输出为[N,15,C]的cfeat,作为SRN的条件输入

SRN:

输入:FRN的特征提取结果f,LPC预测系数P_t,上一个样点S_{t-1},上一个预测激励e_{t-1}

输出:预测当前时刻的非线性激励信号

输入合并后经过两层GRU和FC,最后通过softmax,得到本次激励e_t,结合p_t相加得到预测点值,训练160次(期间f不变)得到一帧的合成音频数据。

LPCNet工程

源码https://github.com/xiph/LPCNet

根据readme进行操作

  1. 配置
代码语言:javascript
复制
./autogen.sh
./configure
make
  1. 生成数据
代码语言:javascript
复制
./dump_data -btrain input.pcm features.f32 data.s16

其中input.pcm是将训练wav写入一个pcm文件,注意是int16

features.f32和data.s16是生成数据

其中features.f32是生成的特征值

--训练lpcnet使用-train,一帧20+16个特征

--训练lpcnet使用-btrain,一帧36+20+16个特征,多了36个burg特征

data.s16是网络模型的输入和输出采样值

生成数据源码dump_data.c文件

  1. 训练脚本
代码语言:javascript
复制
python3 training_tf2/train_lpcnet.py features.f32 data.s16 model_name --retrain plcn5cq_512_20.h5
  1. 测试脚本
代码语言:javascript
复制
python ./training_tf2/test_lpcnet.py lpcnet55Puq_640_01.h5 test_features.f32 test.s16

LPCNet源码分析

dump_data.c

主要用于dump生成训练和测试数据

重要代码注释

代码语言:javascript
复制
    // 二阶滤波,数据增广
    biquad(x, mem_hp_x, x, b_hp, a_hp, FRAME_SIZE);
    biquad(x, mem_resp_x, x, b_sig, a_sig, FRAME_SIZE);
    for (i=0;i<FRAME_SIZE;i++) {
      float g;
      float f = (float)i/FRAME_SIZE;
      g = f*speech_gain + (1-f)*old_speech_gain;
      x[i] *= g;
    }
    if (burg) {
      float ceps[2*NB_BANDS];
      // 计算burg特征,36
      burg_cepstral_analysis(ceps, x);
      // 写特征
      fwrite(ceps, sizeof(float), 2*NB_BANDS, ffeat);
    }
    // 预加重
    preemphasis(x, &mem_preemph, x, PREEMPHASIS, FRAME_SIZE);
    for (i=0;i<FRAME_SIZE;i++) x[i] += rand()/(float)RAND_MAX - .5;
    /* PCM is delayed by 1/2 frame to make the features centered on the frames. */
    for (i=0;i<FRAME_SIZE-TRAINING_OFFSET;i++) pcm[i+TRAINING_OFFSET] = float2short(x[i]);
    // 计算帧特征,18(bfcc)+2(pitch])+16(plc)
    compute_frame_features(st, x);

    RNN_COPY(&pcmbuf[st->pcount*FRAME_SIZE], pcm, FRAME_SIZE);
    if (fpcm) {
        compute_noise(&noisebuf[st->pcount*FRAME_SIZE], noise_std);
    }
    
    if (!quantize) {
      // 写特征
      process_single_frame(st, ffeat);
      if (fpcm) write_audio(st, pcm, &noisebuf[st->pcount*FRAME_SIZE], fpcm, 1);
    }
    st->pcount++;
    /* Running on groups of 4 frames. */
    if (st->pcount == 4) {
      if (quantize) {
        unsigned char buf[8];
        process_superframe(st, buf, ffeat, encode, quantize);
        if (fpcm) write_audio(st, pcmbuf, noisebuf, fpcm, 4);
      }
      st->pcount = 0;
    }
代码语言:javascript
复制
void write_audio(LPCNetEncState *st, const short *pcm, const int *noise, FILE *file, int nframes) {
  int i, k;
  for (k=0;k<nframes;k++) {
  short data[2*FRAME_SIZE];
  for (i=0;i<FRAME_SIZE;i++) {
    float p=0;
    float e;
    int j;
    for (j=0;j<LPC_ORDER;j++) p -= st->features[k][NB_BANDS+2+j]*st->sig_mem[j];
    e = lin2ulaw(pcm[k*FRAME_SIZE+i] - p);
    /* Signal in. data.s16,写入输入p_{t-1}+e_{t-1}=S_{t-1}*/
    data[2*i] = float2short(st->sig_mem[0]);
    /* Signal out. data.s16,写入输出S_t的gt*/
    data[2*i+1] = pcm[k*FRAME_SIZE+i];
    /* Simulate error on excitation. */
    e += noise[k*FRAME_SIZE+i];
    e = IMIN(255, IMAX(0, e));
    
    RNN_MOVE(&st->sig_mem[1], &st->sig_mem[0], LPC_ORDER-1);
    st->sig_mem[0] = p + ulaw2lin(e);
    st->exc_mem = e;
  }
  fwrite(data, 4*FRAME_SIZE, 1, file);
  }
}

lpcnet_demo.c

C代码实现feature特征提取和网络前向运算进行语音合成

代码语言:javascript
复制
else if (mode == MODE_FEATURES) {
        // 创建FRN
        LPCNetEncState *net;
        net = lpcnet_encoder_create();
        while (1) {
            float features[NB_TOTAL_FEATURES];
            short pcm[LPCNET_FRAME_SIZE];
            size_t ret;
            ret = fread(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fin);
            if (feof(fin) || ret != LPCNET_FRAME_SIZE) break;
            // 计算单帧的feature
            lpcnet_compute_single_frame_features(net, pcm, features);
            fwrite(features, sizeof(float), NB_TOTAL_FEATURES, fout);
        }
        lpcnet_encoder_destroy(net);
    } else if (mode == MODE_SYNTHESIS) {
        LPCNetState *net;
        // 创建lpcnet网络
        net = lpcnet_create();
        while (1) {
            float in_features[NB_TOTAL_FEATURES];
            float features[NB_FEATURES];
            short pcm[LPCNET_FRAME_SIZE];
            size_t ret;
            // 读feature
            ret = fread(in_features, sizeof(features[0]), NB_TOTAL_FEATURES, fin);
            if (feof(fin) || ret != NB_TOTAL_FEATURES) break;
            RNN_COPY(features, in_features, NB_FEATURES);
            // 网络infer,对feature转为wav
            lpcnet_synthesize(net, features, pcm, LPCNET_FRAME_SIZE);
            fwrite(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fout);
        }

参考资料

LPCnet论文:https://jmvalin.ca/papers/lpcnet_icassp2019.pdf

LPCNet源码:https://github.com/xiph/LPCNet

https://jmvalin.ca/demo/lpcnet/

https://zhuanlan.zhihu.com/p/54952637

https://cloud.tencent.com/developer/article/1831454

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 语音合成
  • LPCNet算法
    • LPCNet的网络结构
      • LPCNet结构解析
      • LPCNet工程
      • LPCNet源码分析
      相关产品与服务
      语音合成
      语音合成(Text To Speech,TTS)满足将文本转化成拟人化语音的需求,打通人机交互闭环。提供多场景、多语言的音色选择,支持 SSML 标记语言,支持自定义音量、语速等参数,让发音更专业、更符合场景需求。语音合成广泛适用于智能客服、有声阅读、新闻播报、人机交互等业务场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档