使用预训练Xvector模型进行测试
# 已知条件
# 数据集处理流程
- 联合SRE16之前的所有SRE系列数据和Mixer 6,放入data/sre
- 准备SWBD数据集,放入data/swbd
- 整理出注册数据data/sre16_eval_enroll,验证数据data/sre16_eval_test,无标签的广东话和菲律宾语集合data/sre16_major
- 将SRE和SWBD数据集联合,放入data/swbd_sre
- 加混响data/swbd_sre_noise,加噪data/swbd_sre_noise,加音乐data/swbd_sre_music,加语音swbd_sre_babble
- 将语音增强数据集合data/swbd_sre_aug,取子集swbd_sre_aug_128k
- 结合增强数据与原始数据data/swbd_sre_combined
- 分离出SRE系列数据data/sre_combined
- 去除静音后用于训练网络data/swbd_sre_combined_no_sil
# 各Xvector集作用
根据sre16/0003_sre16_v2_1a/run.sh
脚本,在stage=7时,分别提取了如下Xvector:
- exp/xvectors_sre16_major:(域内)data/sre16_major,用于中心化,白化和得分归一化(但该脚本目前还没有得分归一化);自适应PLDA
- exp/xvectors_sre_combined:(域外)data/sre_combined,用于LDA/PLDA
- exp/xvectors_sre16_eval_test:测试Ivector,与注册Ivector的spk应一致,但utt不可重叠
- exp/xvectors_sre16_eval_enroll:注册Ivector
⚠️问题:
为什么LDA/PLDA,及中心化,白化和得分归一化不能用同一个数据集?
可以,但是为了说明域适应的优越性和域适应原理,本脚本分开处理
所谓域内数据是不是测试集?
不是,在实际应用中,域内数据是测试集的特征表示,通过无标签的域内数据我们可以使测试结果更加准确
# 主要步骤
$train_cmd exp/scores/log/sre16_eval_scoring.log \
ivector-plda-scoring --normalize-length=true \
--num-utts=ark:exp/xvectors_sre16_eval_enroll/num_utts.ark \
"ivector-copy-plda --smoothing=0.0 exp/xvectors_sre_combined/plda - |" \
"ark:ivector-mean ark:data/sre16_eval_enroll/spk2utt scp:exp/xvectors_sre16_eval_enroll/xvector.scp ark:- | ivector-subtract-global-mean exp/xvectors_sre16_major/mean.vec ark:- ark:- | transform-vec exp/xvectors_sre_combined/transform.mat ark:- ark:- | ivector-normalize-length ark:- ark:- |" \
"ark:ivector-subtract-global-mean exp/xvectors_sre16_major/mean.vec scp:exp/xvectors_sre16_eval_test/xvector.scp ark:- | transform-vec exp/xvectors_sre_combined/transform.mat ark:- ark:- | ivector-normalize-length ark:- ark:- |" \
"cat '$sre16_trials' | cut -d\ --fields=1,2 |" exp/scores/sre16_eval_scores || exit 1;
2
3
4
5
6
7
⚠️使用的是域外数据训练得到的PLDA模型,
--smoothing=0.0
,为什么不直接用plda呢?可能是为了程序的规范化⚠️后续该脚本用此域外PLDA模型进行自适应得到域内PLDA,但此时域内PLDA是没有自己的LDA投影矩阵的,依旧使用域外LDA矩阵
为什么不直接用域内数据训练LDA和PLDA呢?
因为域内数据通常是小样本的,直接训练无法得到准确的模型参数
需要自行准备
exp/xvectors_sre16_eval_enroll/xvector.scp
、exp/xvectors_enroll/num_utts.ark
、exp/xvectors_sre16_eval_test/xvector.scp
、sre16_trials
根据数据集的命名,enroll+test=eval,现在我们对数据集重新进行约定,test=enroll+eval,先对数据进行处理,再划分为注册集和验证集。使用TIMIT数据集,共630人。
# 表单准备
仿照aishell_data_prep.sh
生成spk2utt
、utt2spk
、wav.scp
:
find $audio_dir -iname "*.wav" | grep -i "wav/test" > $test_dir/wav.flist || exit 1;
echo Preparing $test_dir transcriptions
sed -e 's/\.wav//' $test_dir/wav.flist | awk -F '/' '{print $NF}' > $test_dir/utt.list
sed -e 's/\.wav//' $test_dir/wav.flist | awk -F '/' '{i=NF-1;printf("%s %s\n",$NF,$i)}' > $test_dir/utt2spk_all
paste -d' ' $test_dir/utt.list $test_dir/wav.flist > $test_dir/wav.scp_all
utils/filter_scp.pl -f 1 $test_dir/utt.list $test_dir/utt2spk_all | sort -u > $test_dir/utt2spk
utils/filter_scp.pl -f 1 $test_dir/utt.list $test_dir/wav.scp_all | sort -u > $test_dir/wav.scp
utils/utt2spk_to_spk2utt.pl $test_dir/utt2spk > $test_dir/spk2utt
mkdir -p data/test
for f in spk2utt utt2spk wav.scp; do
cp $test_dir/$f data/test/$f || exit 1;
done
2
3
4
5
6
7
8
9
10
11
12
13
14
# 提取Test集特征
steps/make_mfcc.sh --mfcc-config conf/mfcc.conf \
--nj 40 --cmd "$train_cmd" \
data/test exp/make_mfcc $mfccdir
utils/fix_data_dir.sh data/test
sid/compute_vad_decision.sh --nj 40 --cmd "$train_cmd" \
data/test exp/make_vad $vaddir
utils/fix_data_dir.sh data/test
2
3
4
5
6
7
- TIMIT采样率是16k,但是预训练模型中给出采样率为8k,因此根据log文件提示,设置
--allow-downsample=true
# 划分注册和验证集
参考aishell脚本中的local/split_data_enroll_eval.py
,每人取3句话用于注册,1句话用于测试:
local/split_enroll_eval.py data/test/utt2spk data/enroll/utt2spk data/eval/utt2spk 3 1
# 提取Xvector
sid/nnet3/xvector/extract_xvectors.sh --cmd "$train_cmd" --nj $nj \
$nnet_dir data/test/enroll exp/xvectors_enroll
sid/nnet3/xvector/extract_xvectors.sh --cmd "$train_cmd" --nj $nj \
$nnet_dir data/test/eval exp/xvectors_eval
2
3
4
5
- 只会使用到CPU,还是很快的
extract_xvectors.sh
会生成num_utts.ark
# trials文件准备
直接使用aishell脚本中的local/produce_trials.py
trials=data/test/speaker_ver.lst
local/produce_trials.py data/test/eval/utt2spk $trials
2
# 打分&EER
$train_cmd exp/scores/log/scoring.log \
ivector-plda-scoring --normalize-length=true \
--num-utts=ark:exp/xvectors_enroll/num_utts.ark \
"ivector-copy-plda --smoothing=0.0 exp/xvectors_sre_combined/plda - |" \
"ark:ivector-mean ark:data/test/enroll/spk2utt scp:exp/xvectors_enroll/xvector.scp ark:- | ivector-subtract-global-mean exp/xvectors_sre16_major/mean.vec ark:- ark:- | transform-vec exp/xvectors_sre_combined/transform.mat ark:- ark:- | ivector-normalize-length ark:- ark:- |" \
"ark:ivector-subtract-global-mean exp/xvectors_sre16_major/mean.vec scp:exp/xvectors_eval/xvector.scp ark:- | transform-vec exp/xvectors_sre_combined/transform.mat ark:- ark:- | ivector-normalize-length ark:- ark:- |" \
"cat '$trials' | awk '{print \\\$2, \\\$1}' |" exp/scores/eval_scores || exit 1;
eer=$(paste $trials exp/scores/eval_scores | awk '{print $6, $3}' | compute-eer - 2>/dev/null)
echo "Using Out-of-Domain PLDA, EER: ${eer}%"
2
3
4
5
6
7
8
9
10
- 注意格式,必须先是注册spk,再是测试utt,且trials文件的第1,2列也需要对应
- 结果:Equal error rate is 5.71429%, at threshold -22.9097 5.714
# 补充说明
# transform-feats
应用变化(e.g. LDA; HLDA; fMLLR/CMLLR; MLLT/STC)。当transform-num-cols == feature-dim时,为线性变换,当transform-num-cols == feature-dim+1 (->append 1.0 to features)时,为仿射变换。默认作用于每个utt,当utt2spk文件提供时,可作用于每个spk。若提供了transform-rxfilename,则作用于全局。
Usage: transform-feats [options] (<transform-rspecifier>|<transform-rxfilename>) <feats-rspecifier> <feats-wspecifier>
See also: transform-vec, copy-feats, compose-transforms
2
# utils/filter_scp.pl
从输入文件中挑选出其第f列(默认第一列)在id_list中的行。注意:只关心id_list的第一列,--exclude则挑选出不在id_list中的行。
Usage: filter_scp.pl [--exclude] [-f <field-to-filter-on>] id_list [in.scp] > out.scp
# 其他
'\r': command not found 解决办法 (opens new window)
#转化为unix格式 sed -i 's/\r$//' <filename>
1
2