首页 > 其他分享 >基于kaldi的语音识别:chain模型的finetune通用步骤

基于kaldi的语音识别:chain模型的finetune通用步骤

时间:2022-10-16 17:45:36浏览次数:47  
标签:chain 训练 kaldi finetune tree sh 模型

前记:先说下模型训练的背景。正如一般的机器学习的模型训练那样,首先会用较大的数据集训练生成一个较大的模型,然后在这个模型基础上进行调优,也就是finetune。

  我这边基于kaldi的模型训练也是采用这个的思路。Kaldi下面通常是用GMM+Chain的形式进行声学模型训练,然后还要结合语言模型进行训练和解码(这点同端对端的方案是不一样的)。GMM用来做语音序列同文本的对齐,然后再做chain模型的训练,得到声学模型。这可以看作是预训练(pre-training)。Kaldi提供的chain模型训练脚本可以参考egs/libspeech/s5/local/chain/run_tdnn.sh或者egs/wsj/s5/local/chain/run_tdnn.sh。

以上这些实现起来比较容易,不多赘述。后面开始进行finetune的时候就开始遇到问题了。Kaldi中其实提供了两种调参模式:一种叫tune,也就是调整整个训练过程的方案和参数,得到新的模型,这种形式不会基于已有的模型进行,所以相当于就是重新跑一边chain的训练过程,比较耗时。如果去看kaldi的egs下面的脚本,里面出现比如tdnn_7r这样的字段,其中,7r就是对应这种调参方式的不同版本编号。另一种就是finetune,这个就是本文要介绍的方案。

 

  基础模型是用数千小时的语料训练出来的,针对在应用场景下出现的识别问题,又整理了数百小时的数据进行finetune。

  对于GMM模型和对齐(主要是对齐结果),可以参照librispeech中的run.sh,与预训练模型的训练一样。

  对于Chain模型finetune部分,起初,我参考了egs/rm/s5/local/run/tuning/run_tdnn_wsj_rm_1c.sh,但是发现一个问题(第一个坑),里面的tree文件夹是预先生成的,但是我找不到生成这个tree文件夹的脚本。这里先解释下tree文件夹是干嘛的:chain模型训练实际上是区分性训练,所以有分子和分母,分子采用GMM的声学模型解码所得,分母则是force-aligned的对齐结果。tree文件夹中主要保存的就是对齐结果(.ali)和声学模型的聚类树(tree)。另外,从GMM到chain,聚类的对象从triphone变为biphone,而phone topo从5-state变为1-state,所以这里有一个topo和tree的转换工作要做,然后根据新的topo和tree重新对齐。这个过程就是run_tdnn.sh中steps/nnet3/chain/gen_topo.py, steps/nnet3/chain/build_tree.sh做的事情。回到run_tdnn_wsj_rm_1c.sh,里面的tree文件夹按我的理解(并未实际去验证)应该是做完以上两个操作之后生成的,在这个脚本中并未体现,所以这里对使用者(至少是我)产生了一定困惑。

  此时,如果按照run_tdnn.sh中的步骤,重新生成phone topo和tree,那么在之后的chain训练中,就会出现第二个坑:pdf数量不匹配!pdf就是每个分类的概率密度分布,是tree的聚类数量,体现在神经网络里面,就是最后一层的维度。所以,这里出现问题的原因就是重新生成的tree的聚类数量同原来预训练模型的分类数量不匹配。在build_tree.sh,里面生成tree采用的是当前的训练数据,数百小时的和数千小时的数据的聚类结果出现很大差异也是正常的。再看build_tree.sh做的事情,就是两个:生成new tree,以及用生成的new tree重新做对齐:convert-ali。所以,我们可以不用重新生成tree,而是用预训练模型的tree只做重新对齐就可以了。

  最后,就可以用steps/nnet3/chain/train.py进行chain模型的训练。在finetune时,需要加载预训练模型作为启动,加载方式分两步:首先,对于声学模型final.mdl的格式,里面存在一些其它信息,作为预训练模型加载时需要转成纯nnet原始数据的格式,可以通过”nnet-copy --raw=true src.mdl tgt.raw”实现;之后,在train.py中,通过--trainer.input_model将模型配置进来。

 

  以上就是我在基于kaldi做声学模型的fintune时遇到的问题和解决方案,可能写的比较乱,下面就把完整步骤整理如下:

1、语言模型与原预训练模型一致

  一般在egs/xxx/s5中都有一个run.sh文件,而开头会有一些准备工作,比如生成dict,lang,lm. 这些操作根据不同的训练集可能会得到不同的结果,尤其是phone表!这会影响后续聚类和对齐的问题,所以这些语言模型相关的信息在finetune时,需要与预训练模型保持一致,不要在finetune时进行处理。建议可以生成一个固定的版本,独立维护。

2、特征提取

  特征提取一般用mfcc,在GMM训练时就都会做。

  在chain训练时,也可以用ivector。

  我这边是在GMM时用mfcc,而chain训练时用了ivector。

3、GMM模型训练

  输入:finetune的数据集;比如(data/train_for_finetune)

  输出:GMM声学模型、基于GMM的强制对齐结果;比如(finetune_tri5a & finetune_tri5a_ali)

4、沿用预训练模型的相关结果

   a.预训练模型从final.mdl转成input.raw:nnet-copy --raw=true final.mdl input.raw

  PS: 这里说明下,我并没有对预训练模型的神经网络进行任何改变,如果想要做些改变,可以参考下run_tdnn_wsj_rm_1c.sh里面的处理。

   b.将预训练模型用于chain训练的tree文件夹(文件一般存放在exp/chain/中,比如:exp/chain/tri5a_tree)中的tree和1.mdl拷贝到当前finetune的tree文件夹中。

  PS:只需要这两个就可以了,其它的.ali和.trans都是要重新生成的。

5、生成Chain训练需要的分子分母

  1. 分子:steps/align_fmllr_lats.sh, 参数具体可以参照run_tdnn.sh
  2. 分母:steps/nnet3/chain/build_tree.sh, 可以参照run_tdnn.sh的参数配置,但是增加一个配置项:--stage -1,这样就可以不生成new tree,只执行第二步convert-ali。那么这时候的tree哪里来呢,就是将预训练的tree放到build_tree.sh的生成目录中,也就是上面4.b做的事情。举个例子:

    steps/nnet3/chain/build_tree.sh  --stage -1 --frame-subsampling-factor 3 \

                --context-opts "--context-width=2 --central-position=1" \

                --cmd "$train_cmd" 7000 data/$train_set/train $lang exp/$train_set""_tri5a_ali $treedir

  其中最后一个参数treedir就是本次finetune的chain训练需要的tree所在的目录,我事先生成这个目录,并将预训练中对应文件夹中的tree和1.mdl拷贝到这里,然后在执行build_tree.sh即可。

6、chain训练,等待结果即可。

 

后记:以上絮絮叨叨写了很多,但难免受制于个人能力,可能会有众多不足和谬误,对于存在的问题欢迎指正;如果我有没说清楚的地方,也欢迎交流。

  之所以写篇文章,一方面也是对最近工作的记录总结;另外,发现kaldi中对于finetune的实际操作没有一个比较现成的脚本,所以我在这个过程中踩了很多坑,希望我的经验可以帮助到同行。他山之石可以攻玉。

标签:chain,训练,kaldi,finetune,tree,sh,模型
From: https://www.cnblogs.com/benjaminzhou/p/16796642.html

相关文章

  • 经典框架Kaldi配套的语音识别实战
    周末到了,给大家送上一本重磅书籍,语音识别领域重要框架Kaldi配置的书籍,书为《Kaldi语音识别实践》。本书内容这是一本以Kaldi框架为工具,讲解语音识别中核心技术的书籍,书籍各......
  • 【NLP预训练模型】你finetune BERT的姿势可能不对哦?
    预训练模型BERT是NLP领域如今最大的网红,BERT的预训练过程学习了大量的自然语言中词、句法以及常识等泛领域的知识。因此,在运用BERT到实际的NLP任务中,通常的做法都是基于特定......
  • 使用chainWebpack配置插件
    使用chainWebpack配置TerserWebpackPlugin插件安装插件版本要和webpack的版本匹配npminstallterser-webpack-plugin--save-devchainWebpack(config){config......
  • 【chainer速成】chainer图像分类从模型自定义到测试
    文章首发于微信公众号《有三AI》​​【chainer速成】chainer图像分类从模型自定义到测试​​欢迎来到专栏《2小时玩转开源框架系列》,这是我们第八篇,前面已经说过了caffe,tens......
  • CSharp: Chain of Responsibility Pattern in donet core 3
     ///<summary>///责任链模式ChainofResponsibilityPattern亦称:职责链模式、命令链、CoR、ChainofCommand、ChainofResponsibility///geovindu,......
  • Bitcoin-NG: A Scalable Blockchain Protocol
    Motivation由于比特币平均10分钟出一个块,每个块大小限制在1MB,所以每秒只能记录3~4个交易,导致比特币系统存在着的吞吐量低下和高延迟的问题。本文的主要目的就是通过提......
  • rustup toolchains
    默认的toolchain是stable-x86_64-pc-windows-msvc也可以使用stable-x86_64-pc-windows-gnugnu结尾的需要mingw32默认的需要vsc++buildtoolrustupinstall<toolchai......
  • clion 调试rust报错 GNU debugger cannot be used with MSVC Rust toolchain
    安装以下rustuptoolchaininstallrustupdefaultstable-x86_64-pc-windows-gnu......
  • NewStarCTF Week3 Blockchain
    前言:最近学了点blockchain,正好NewStarCTF这周上了题,赶紧来练练手,出题人很友好,代码都很简单,适合刚了解区块链的新手入门Checkin先安装Metamask,再去Goerli水龙头领币然后n......
  • kaldi训练模型的过程
    整理一下训练新模型的过程:1.进入到kaldi-trunk/egs目录下创建XX(看你心情随便命名)文件夹,然后在文件夹里创建一个audio文件夹,在audio文件夹内在创建两个文件夹train和test......