6504f98c59141f96af130c6f29d34cc96376bd38
[processor-sdk/kaldi.git] / egs / babel_multilang / s5 / local / nnet3 / run_tdnn_multilingual.sh
1 #!/bin/bash
3 # Copyright 2016 Pegah Ghahremani
5 # This script can be used for training multilingual setup using different
6 # languages (specifically babel languages) with no shared phones.
7 # It will generates separate egs directory for each dataset and combine them
8 # during training.
9 # In the new multilingual training setup, mini-batches of data corresponding to
10 # different languages are randomly combined to generate egs.*.scp files
11 # using steps/nnet3/multilingual/combine_egs.sh and generated egs.*.scp files used
12 # for multilingual training.
13 #
14 # For all languages, we share all except last hidden layer and there is separate final
15 # layer per language.
16 # The bottleneck layer can be added to the network structure using --bnf-dim option
17 #
18 # The script requires baseline PLP features and alignment (e.g. tri5_ali) for all languages.
19 # and it will generate 40dim MFCC + pitch features for all languages.
20 #
21 # The global iVector extractor trained using all languages by specifying
22 # --use-global-ivector-extractor and the iVectors are extracts for all languages.
23 #
24 # local.conf should exists (check README.txt), which contains configs for
25 # multilingual training such as lang_list as array of space-separated languages used
26 # for multilingual training.
27 #
28 echo "$0 $@"  # Print the command line for logging
29 . ./cmd.sh
30 set -e
32 remove_egs=false
33 cmd=queue.pl
34 srand=0
35 stage=0
36 train_stage=-10
37 get_egs_stage=-10
38 decode_stage=-10
39 num_jobs_initial=2
40 num_jobs_final=8
41 speed_perturb=true
42 use_pitch=true  # if true, pitch feature used to train multilingual setup
43 use_pitch_ivector=false # if true, pitch feature used in ivector extraction.
44 use_ivector=true
45 megs_dir=
46 alidir=tri5_ali
47 ivector_extractor=  # If empty, the global iVector extractor trained on pooled data
48                     # from all languages and iVectors are
49                     # extracted using global ivector extractor and ivector_suffix ='_gb'.
50                     # Otherwise this extractor is used to extract iVector and
51                     # ivector_suffix = ''.
53 bnf_dim=           # If non-empty, the bottleneck layer with this dimension is added at two layers before softmax.
54 dir=exp/nnet3/multi_bnf
56 . ./path.sh
57 . ./cmd.sh
58 . ./utils/parse_options.sh
60 [ ! -f local.conf ] && echo 'the file local.conf does not exist! Read README.txt for more details.' && exit 1;
61 . local.conf || exit 1;
64 num_langs=${#lang_list[@]}
65 feat_suffix=_hires      # The feature suffix describing features used in
66                         # multilingual training
67                         # _hires -> 40dim MFCC
68                         # _hires_pitch -> 40dim MFCC + pitch
69                         # _hires_pitch_bnf -> 40dim MFCC +pitch + BNF
71 echo "$0 $@"  # Print the command line for logging
72 if ! cuda-compiled; then
73   cat <<EOF && exit 1
74 This script is intended to be used with GPUs but you have not compiled Kaldi with CUDA
75 If you want to use GPUs (and have them), go to src/, and configure and make on a machine
76 where "nvcc" is installed.
77 EOF
78 fi
80 for lang_index in `seq 0 $[$num_langs-1]`; do
81   for f in data/${lang_list[$lang_index]}/train/{feats.scp,text} exp/${lang_list[$lang_index]}/$alidir/ali.1.gz exp/${lang_list[$lang_index]}/$alidir/tree; do
82     [ ! -f $f ] && echo "$0: no such file $f" && exit 1;
83   done
84 done
86 if [ "$speed_perturb" == "true" ]; then suffix=_sp; fi
87 dir=${dir}${suffix}
89 ivec_feat_suffix=${feat_suffix}
90 if $use_pitch; then feat_suffix=${feat_suffix}_pitch ; fi
91 if $use_pitch_ivector; then nnet3_affix=_pitch; ivec_feat_suffix=${feat_suffix}_pitch ; fi
93 for lang_index in `seq 0 $[$num_langs-1]`; do
94   echo "$0: extract high resolution 40dim MFCC + pitch for speed-perturbed data "
95   echo "and extract alignment."
96   local/nnet3/run_common_langs.sh --stage $stage \
97     --feat-suffix $feat_suffix \
98     --use-pitch $use_pitch \
99     --speed-perturb $speed_perturb ${lang_list[$lang_index]} || exit 1;
100   if $use_pitch && ! $use_pitch_ivector; then
101     echo "$0: select MFCC features for ivector extraction."
102     featdir=data/${lang_list[$lang_index]}/train${suffix}${feat_suffix}
103     ivec_featdir=data/${lang_list[$lang_index]}/train${suffix}${ivec_feat_suffix}
104     mfcc_only_dim=`feat-to-dim scp:$featdir/feats.scp - | awk '{print $1-3}'`
105     if [ ! -f $ivec_featdir/.done ]; then
106       steps/select_feats.sh --cmd "$train_cmd" --nj 70 0-$[$mfcc_only_dim-1] \
107         $featdir ${ivec_featdir} || exit 1;
108       steps/compute_cmvn_stats.sh ${ivec_featdir} || exit 1;
109       touch ${ivec_featdir}/.done || exit 1;
110     fi
111   fi
112 done
114 if $use_ivector; then
115   ivector_suffix=""
116   if [ -z "$ivector_extractor" ]; then
117     mkdir -p data/multi
118     global_extractor=exp/multi/nnet3${nnet3_affix}
119     mkdir -p $global_extractor
120     ivector_extractor=$global_extractor/extractor
121     multi_data_dir_for_ivec=data/multi/train${suffix}${ivec_feat_suffix}
122     ivector_suffix=_gb
123     echo "$0: combine training data using all langs for training global i-vector extractor."
124     if [ ! -f $multi_data_dir_for_ivec/.done ]; then
125       echo ---------------------------------------------------------------------
126       echo "Pooling training data in $multi_data_dir_for_ivec on" `date`
127       echo ---------------------------------------------------------------------
128       mkdir -p $multi_data_dir_for_ivec
129       combine_lang_list=""
130       for lang_index in `seq 0 $[$num_langs-1]`;do
131         combine_lang_list="$combine_lang_list data/${lang_list[$lang_index]}/train${suffix}${ivec_feat_suffix}"
132       done
133       utils/combine_data.sh $multi_data_dir_for_ivec $combine_lang_list
134       utils/validate_data_dir.sh --no-feats $multi_data_dir_for_ivec
135       touch $multi_data_dir_for_ivec/.done
136     fi
137   fi
138   if [ ! -f $global_extractor/extractor/.done ]; then
139     if [ -z $lda_mllt_lang ]; then lda_mllt_lang=${lang_list[0]}; fi
140     echo "$0: Generate global i-vector extractor on pooled data from all "
141     echo "languages in $multi_data_dir_for_ivec, using an LDA+MLLT transform trained "
142     echo "on ${lda_mllt_lang}."
143     local/nnet3/run_shared_ivector_extractor.sh  \
144       --suffix "$suffix" --nnet3-affix "$nnet3_affix" \
145       --feat-suffix "$ivec_feat_suffix" \
146       --stage $stage $lda_mllt_lang \
147       $multi_data_dir_for_ivec $global_extractor || exit 1;
148     touch $global_extractor/extractor/.done
149   fi
150   echo "$0: Extracts ivector for all languages using $global_extractor/extractor."
151   for lang_index in `seq 0 $[$num_langs-1]`; do
152     local/nnet3/extract_ivector_lang.sh --stage $stage \
153       --train-set train${suffix}${ivec_feat_suffix} \
154       --ivector-suffix "$ivector_suffix" \
155       --nnet3-affix "$nnet3_affix" \
156       ${lang_list[$lang_index]} \
157       $ivector_extractor || exit;
158   done
159 fi
161 for lang_index in `seq 0 $[$num_langs-1]`; do
162   multi_data_dirs[$lang_index]=data/${lang_list[$lang_index]}/train${suffix}${feat_suffix}
163   multi_egs_dirs[$lang_index]=exp/${lang_list[$lang_index]}/nnet3${nnet3_affix}/egs${feat_suffix}${ivector_suffix}
164   multi_ali_dirs[$lang_index]=exp/${lang_list[$lang_index]}/${alidir}${suffix}
165   multi_ivector_dirs[$lang_index]=exp/${lang_list[$lang_index]}/nnet3${nnet3_affix}/ivectors_train${suffix}${ivec_feat_suffix}${ivector_suffix}
166 done
168 if $use_ivector; then
169   ivector_dim=$(feat-to-dim scp:${multi_ivector_dirs[0]}/ivector_online.scp -) || exit 1;
170 else
171   echo "$0: Not using iVectors in multilingual training."
172   ivector_dim=0
173 fi
174 feat_dim=`feat-to-dim scp:${multi_data_dirs[0]}/feats.scp -`
176 if [ $stage -le 8 ]; then
177   echo "$0: creating multilingual neural net configs using the xconfig parser";
178   if [ -z $bnf_dim ]; then
179     bnf_dim=1024
180   fi
181   mkdir -p $dir/configs
182   cat <<EOF > $dir/configs/network.xconfig
183   input dim=$ivector_dim name=ivector
184   input dim=$feat_dim name=input
186   # please note that it is important to have input layer with the name=input
187   # as the layer immediately preceding the fixed-affine-layer to enable
188   # the use of short notation for the descriptor
189   # the first splicing is moved before the lda layer, so no splicing here
190   relu-renorm-layer name=tdnn1 input=Append(input@-2,input@-1,input,input@1,input@2,ReplaceIndex(ivector, t, 0)) dim=1024
191   relu-renorm-layer name=tdnn2 dim=1024
192   relu-renorm-layer name=tdnn3 input=Append(-1,2) dim=1024
193   relu-renorm-layer name=tdnn4 input=Append(-3,3) dim=1024
194   relu-renorm-layer name=tdnn5 input=Append(-3,3) dim=1024
195   relu-renorm-layer name=tdnn6 input=Append(-7,2) dim=1024
196   relu-renorm-layer name=tdnn_bn dim=$bnf_dim
197   # adding the layers for diffrent language's output
198 EOF
199   # added separate outptut layer and softmax for all languages.
200   for lang_index in `seq 0 $[$num_langs-1]`;do
201     num_targets=`tree-info ${multi_ali_dirs[$lang_index]}/tree 2>/dev/null | grep num-pdfs | awk '{print $2}'` || exit 1;
203     echo " relu-renorm-layer name=prefinal-affine-lang-${lang_index} input=tdnn_bn dim=1024"
204     echo " output-layer name=output-${lang_index} dim=$num_targets max-change=1.5"
205   done >> $dir/configs/network.xconfig
207   steps/nnet3/xconfig_to_configs.py --xconfig-file $dir/configs/network.xconfig \
208     --config-dir $dir/configs/ \
209     --nnet-edits="rename-node old-name=output-0 new-name=output"
210 fi
212 if [ $stage -le 9 ]; then
213   echo "$0: Generates separate egs dir per language for multilingual training."
214   # sourcing the "vars" below sets
215   #model_left_context=(something)
216   #model_right_context=(something)
217   #num_hidden_layers=(something)
218   . $dir/configs/vars || exit 1;
219   ivec="${multi_ivector_dirs[@]}"
220   if $use_ivector; then
221     ivector_opts=(--online-multi-ivector-dirs "$ivec")
222   fi
223   local/nnet3/prepare_multilingual_egs.sh --cmd "$decode_cmd" \
224     "${ivector_opts[@]}" \
225     --cmvn-opts "--norm-means=false --norm-vars=false" \
226     --left-context $model_left_context --right-context $model_right_context \
227     $num_langs ${multi_data_dirs[@]} ${multi_ali_dirs[@]} ${multi_egs_dirs[@]} || exit 1;
228 fi
230 if [ -z $megs_dir ];then
231   megs_dir=$dir/egs
232 fi
234 if [ $stage -le 10 ] && [ ! -z $megs_dir ]; then
235   echo "$0: Generate multilingual egs dir using "
236   echo "separate egs dirs for multilingual training."
237   if [ ! -z "$lang2weight" ]; then
238       egs_opts="--lang2weight '$lang2weight'"
239   fi
240   common_egs_dir="${multi_egs_dirs[@]} $megs_dir"
241   steps/nnet3/multilingual/combine_egs.sh $egs_opts \
242     --cmd "$decode_cmd" \
243     --samples-per-iter 400000 \
244     $num_langs ${common_egs_dir[@]} || exit 1;
245 fi
247 if [ $stage -le 11 ]; then
248   steps/nnet3/train_raw_dnn.py --stage=$train_stage \
249     --cmd="$decode_cmd" \
250     --feat.cmvn-opts="--norm-means=false --norm-vars=false" \
251     --trainer.num-epochs 2 \
252     --trainer.optimization.num-jobs-initial=2 \
253     --trainer.optimization.num-jobs-final=12 \
254     --trainer.optimization.initial-effective-lrate=0.0015 \
255     --trainer.optimization.final-effective-lrate=0.00015 \
256     --trainer.optimization.minibatch-size=256,128 \
257     --trainer.samples-per-iter=400000 \
258     --trainer.max-param-change=2.0 \
259     --trainer.srand=$srand \
260     --feat-dir ${multi_data_dirs[0]} \
261     --feat.online-ivector-dir ${multi_ivector_dirs[0]} \
262     --egs.dir $megs_dir \
263     --use-dense-targets false \
264     --targets-scp ${multi_ali_dirs[0]} \
265     --cleanup.remove-egs $remove_egs \
266     --cleanup.preserve-model-interval 50 \
267     --use-gpu true \
268     --dir=$dir  || exit 1;
269 fi
271 if [ $stage -le 12 ]; then
272   for lang_index in `seq 0 $[$num_langs-1]`;do
273     lang_dir=$dir/${lang_list[$lang_index]}
274     mkdir -p  $lang_dir
275     echo "$0: rename output name for each lang to 'output' and "
276     echo "add transition model."
277     nnet3-copy --edits="rename-node old-name=output-$lang_index new-name=output" \
278       $dir/final.raw - | \
279       nnet3-am-init ${multi_ali_dirs[$lang_index]}/final.mdl - \
280       $lang_dir/final.mdl || exit 1;
281     cp $dir/cmvn_opts $lang_dir/cmvn_opts || exit 1;
282     echo "$0: compute average posterior and readjust priors for language ${lang_list[$lang_index]}."
283     steps/nnet3/adjust_priors.sh --cmd "$decode_cmd" \
284       --use-gpu true \
285       --iter final --use-raw-nnet false --use-gpu true \
286       $lang_dir ${multi_egs_dirs[$lang_index]} || exit 1;
287   done
288 fi
290 # decoding different languages
291 if [ $stage -le 13 ]; then
292   num_decode_lang=${#decode_lang_list[@]}
293   for lang_index in `seq 0 $[$num_decode_lang-1]`; do
294     if [ ! -f $dir/${decode_lang_list[$lang_index]}/decode_dev10h.pem/.done ]; then
295       echo "Decoding lang ${decode_lang_list[$lang_index]} using multilingual hybrid model $dir"
296       run-4-anydecode-langs.sh --use-ivector $use_ivector \
297         --use-pitch-ivector $use_pitch_ivector \
298         --nnet3-dir $dir --iter final_adj \
299         --nnet3-affix "$nnet3_affix" \
300         ${decode_lang_list[$lang_index]} || exit 1;
301       touch $dir/${decode_lang_list[$lang_index]}/decode_dev10h.pem/.done
302     fi
303   done
304 fi