本篇文章6882字,读完约17分钟
雷锋。作者张庆恒最初发表在作者的个人博客上,和雷锋。(公开号码:雷锋。com)被授权发布。
本文通过简单的kaldi源代码分析了dnn训练声学模型时神经网络的输入和输出。由gmm-hmm训练的模型需要在dnn训练之前使用。以训练好的单声道模型为例,对模型进行维特比对齐,主要完成每个语音文件从帧到过渡标识的映射。
让我们看看对齐的结果:
$ copy-int-vector " ark:gunzip-c Ali . 1 . gz | " ark,t:- | head -n 1
扬声器001 _ 00003 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 15 15 15 18 890 889 889 889 889 889 889 892 894 893 893 893 86 88 87 90 89 89 89 89 89 89 89 89 89 89 89 89 89 8 9 194 193 196 195 195 198 197 386 385 385 385 385 385 385 385 385 388 387 387 390 902 901 901 904 903 906 905 905 905 905 905 905 905 905 905 905 905 9 14 913 913 916 918 917 917 917 917 917 917 752 751 751 751 751 751 754 753 753 753 753 753 753 753 753 756 755 755 926 925 928 927 927 927 927 927 927 927 930 929 929 929 929 929 929 929 929 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 18
对于训练语音文件speaker001_00003,后面的每个数字表示一个过渡id,每个数字对应一个特征向量。相应的向量可以通过复制矩阵来查看,相关的内容可以通过参考特征来提取。链接如下:
t/rx2n4dx
看看过渡id:
$ show-transitions phones . txt final . MDL
转换状态1: phone = sil hmm-state = 0 pdf = 0
跃迁-id = 1 p = 0.966816[自循环]
过渡-id = 2 p = 0.01 [0 -> 1]
过渡-id = 3 p = 0.01 [0 -> 2]
跃迁-id = 4 p = 0.013189 [0 -> 3]
过渡状态2: phone = sil hmm-state = 1 pdf = 1
跃迁-id = 5 p = 0.970016[自环]
跃迁-id = 6 p = 0.01 [1 -> 2]
跃迁-id = 7 p = 0.01 [1 -> 3]
过渡-id = 8 p = 0.01 [1 -> 4]
过渡状态3: phone = sil hmm-state = 2 pdf = 2
过渡-id = 9 p = 0.01 [2 -> 1]
跃迁-id = 10 p = 0.968144[自循环]
跃迁-id = 11 p = 0.01 [2 -> 3]
跃迁-id = 12 p = 0.0118632 [2 -> 4]
过渡状态4: phone = sil hmm-state = 3 pdf = 3
跃迁-id = 13 p = 0.01 [3 -> 1]
跃迁-id = 14 p = 0.01 [3 -> 2]
跃迁-id = 15 p = 0.932347[自循环]
跃迁-id = 16 p = 0.0476583 [3 -> 4]
过渡状态5: phone = sil hmm-state = 4 pdf = 4
跃迁-id = 17 p = 0.923332[自循环]
跃迁-id = 18 p = 0.0766682 [4 -> 5]
过渡状态6: phone = a1 hmm-state = 0 pdf = 5
跃迁-id = 19 p = 0.889764[自循环]
过渡-id = 20 p = 0.110236 [0 -> 1]
...
一个唯一的转换状态对应于一个唯一的pdf,它包括多个转换id。
接下来,看看神经网络的输入和输出是什么。以步骤为例。将脚本追溯到steps/nnet/train.sh并找到相关命令:
...
labels _ tr = " ark:Ali-to-pdf $ alidir/final . MDL " ark:gun zip-c $ alidir/Ali。*。gz |\ "方舟:- |阿里-到-后方舟:- |方舟:-| "
...
专长_tr= "方舟:复制-专长scp:$dir/train.scp方舟:- | "
...
#输入-调光,
get _ dim _ from = $ feature _ transform
num_fea=$(专长-变暗" $专长_转移-前进" $ get _变暗_从\ "方舟:-方舟:- |" -)
#输出-暗淡,
num _ TGT = $(hmm-info-print-args = false $ alidir/final . MDL | grep pdf | awk { print $ nf })
...
dnn)
utils/nnet/make _ nnet _ proto . py $ proto _ opts \
${bn_dim:+ -瓶颈-dim=$bn_dim} \
$ num _ FEA $ num _ TGT $ hid _ layers $ hid _ dim > $ nnet _ proto
;;
从神经网络的上述关键训练准备阶段可以看出,神经网络的输入是变换后的特征向量,输出是标号。分别运行以上命令,看看神经网络的输出是什么。标签tr分两步生成:
Ali-to-pdf:将上述对齐文件中的转换id转换为相应的pdf-id;;
Ali-to-post:根据获得的pdf-id,生成[pdf,post]对,即pdf及其对应的后验概率。
$ Ali-to-pdf final . MDL " ark:gun zip-c Ali . 1 . gz | " ark,t:- | head -n 1
扬声器001 _ 00003 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 4 440 440 440 440 440 440 440 441 442 442 442 442 38 39 39 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 92 92 93 93 93 94 94 188 188 188 188 188 188 188 188 188 189 189 189 190 446 446 446 447 447 448 448 448 448 448 448 448 448 448 448 448 448 452 452 452 4 53 454 454 454 454 454 454 454 371 371 371 371 371 371 372 372 372 372 372 372 372 372 372 373 373 373 458 458 459 459 459 459 459 459 459 459 460 460 460 460 460 460 460 460 460 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4
观察前两帧,结合文章的开头,过渡id分别为4和1,对应的pdf为0。结果是阿里又来了:
$ Ali-to-pdf final . MDL " ark:gunzip-c Ali . 1 . gz | " ark,t:-| head-n-1 | Ali-to-post ark,t:-
speaker 001 _ 00003[0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1][0 1]......[3 1][3 1][3 1][3 1][4 1][440 1][440 1][440 1][440 1][440 1][440 1][440 1][440 1][441 1][442 1][442 1][442 1][442 1][38 1][39 1][39 1] [40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][40 1][92 1] ......[ 0 1 ] [ 0 1 ] [ 0 1 ] [ 0 1 ] [ 3 1 ] [ 4 1 ]
得到了Pdf-id和相应的后验概率,二者均为1。
因此,获得训练数据和相应的目标标签。进一步观察神经网络的输入和输出维度,网络结构由utils/nnet/make _ nnet_proto.py编写在nnet _ proto文件中。python脚本的两个重要参数num_fea和num_tgt分别是神经网络的输入和输出维度。其中num_fea是通过从特征到尺寸转换获得的:
$ feat至dim scp:../tri4b_dnn/train.scp ark,t:- | grep speaker001_00003
speaker001_00003 40
这是fbank的特征,尺寸为40。当它真正被用作神经网络的输入时,我们可以从源代码steps/nnet/train.sh中看到拼接参数(默认值为5),它指定了特征向量的变换:在对应的帧前后取5帧,组成一个由11帧组成的大向量(维数为440)。这部分特征变换的拓扑也保存到final.feature_transform:
$ more final.feature_transform
440 40
[ -5 -4 -3 -2 -1 0 1 2 3 4 5 ]
...
稍后,在训练神经网络时,将使用拓扑来变换特征向量,并且神经网络的最终输入维数是440。
通过hmm-info得到num_tgt的维数:
$ hmm-信息终稿. mdl
电话数量218
pdf数量1026
过渡次数-id 2834
过渡状态数1413
$ hmm-info final . MDL | grep pdf | awk { print $ nf }
1026
因此,我们可以看到,神经网络的输出维数是1026,然后看看nnet_proto:
440 1024-2.000000 4.000000 0.037344 0.000000
1024 1024
1024 1024-2.000000 4.000000 0.109375 0.000000
1024 1024
1024 1024-2.000000 4.000000 0.109375 0.000000
1024 1024
1024 1024-2.000000 4.000000 0.109375 0.000000
1024 1024
1024 1026 0.000000 0.000000 0.109322 1.000000 0.100000
1026 1026
在这里,我们可以看到神经网络的输入维数已经从40变化到440,并且输出的pdf数量(对应于hmm状态的数量)。
如果继续追踪代码,您最终可以找到单个神经网络的训练实现,即kaldi/src/nnet bin/nnet-train-frmshuff . cc:
使用小批量随机梯度下降执行神经网络训练的一次迭代(历元)。训练目标通常是pdf-post,由ali-to-post准备。
继续分析代码,我们可以看到几个关键步骤:分析训练参数和配置网络
读取特征向量和目标标签,输入为矩阵型,输出为后验型,即
//获取特征/目标对,
matrix mat = feature _ reader . value();
后验目标=目标_阅读器.值(utt);
训练数据随机置乱作为神经网络的输入和期望输出;
const cumatrix base & nnet _ in = feature _ random zer . value();
const后路& nnet _ TGT = targets _ random zer . value();
常量向量& frm _ weights = weights _ random zer . value();
正向传播,计算估计值nnet_out
//向前传球,
nnet.propagate(nnet_in,& nnet _ out);
计算成本,支持交叉熵、均值方差和多任务。结果是对象差异
//评估我们选择目标函数,
if(objective _ function = = " xent "){
//通过评估中的权重重新调整梯度,
xent.eval(frm_weights、nnet_out、nnet_tgt和obj _ diff);
}否则if (objective_function == "mse") {
//通过评估中的权重重新调整梯度,
mse.eval(frm_weights、nnet_out、nnet_tgt和obj _ diff);
{}
...
根据误差反向传播更新参数
如果(!交叉验证){
//反向传播,并进行更新,
nnet . back ropagate(obj _ diff,null);
{}
完成参数更新并继续迭代。
total_frames += nnet_in.numrows(),
最后,/steps/nnet/train_scheduler.sh调用这部分代码指定最大迭代次数max _迭代器或接受训练好的模型。
接受:损失更好,或者我们有固定的学习率,或者我们有固定的历元数
dnn培训前的总结:
训练gmm-hmm模型,聚类,获得音素(或状态)后验。
语音数据被对齐,并且语音文件和帧特征向量之间根据时间序列的对应关系在这里被获得。
生成配对作为训练目标
对语音文件的特征向量进行变换,前后取5帧,拼接一个11帧的高维特征向量作为神经网络的输入。
神经网络输入变换后的特征向量,通过前向传播和软最大化层,得到每个pdf对应的帧特征的概率预测值。
根据目标的后验概率计算每个概率密度函数与预测值之间的误差
反向传播更新参数。
不断迭代,直到达到最大训练次数,或者模型在交叉验证后损失较小,然后停止训练。
解码时,使用训练好的dnn-hmm模型输入帧的特征向量,得到帧处于各种状态(对应pdf)的概率。
X_t对应于时间t的观察值(输入),q_t=s_i表示时间t的状态为s_i..P(x_t)是观测值的出现概率,对结果影响不大。P(s_i)是s_i的先验概率,它可以从语料库中获得。最后,得到与gmm相同的目标:hmm状态到观测帧特征向量的输出概率。有以下示意图:
雷锋。com相关阅读:
教你如何使用张量流实现基于dnn的文本分类
深度神经网络发展综述:如何加速dnn操作?
开发者特别会议|英伟达深度学习学院现场授课
英伟达dli高级工程师现场指导,理论联系实际,深入学习!
课程链接:mooc.ai/course/90
雷锋文章版权所有。严禁擅自转载。详情请参考转载说明。
标题:详解 DNN 在声学应用中的模型训练
地址:http://www.hcsbodzyz.com/hcxw/9355.html