Blame view

egs/wsj/s5/steps/nnet/decode.sh 7.65 KB
8dcb6dfcb   Yannick Estève   first commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  #!/bin/bash
  
  # Copyright 2012-2015 Brno University of Technology (author: Karel Vesely), Daniel Povey
  # Apache 2.0
  
  # Begin configuration section.
  nnet=               # non-default location of DNN (optional)
  feature_transform=  # non-default location of feature_transform (optional)
  model=              # non-default location of transition model (optional)
  class_frame_counts= # non-default location of PDF counts (optional)
  srcdir=             # non-default location of DNN-dir (decouples model dir from decode dir)
  ivector=            # rx-specifier with i-vectors (ark-with-vectors),
  
  blocksoftmax_dims=   # 'csl' with block-softmax dimensions: dim1,dim2,dim3,...
  blocksoftmax_active= # '1' for the 1st block,
  
  stage=0 # stage=1 skips lattice generation
  nj=4
  cmd=run.pl
  
  acwt=0.10 # note: only really affects pruning (scoring is on lattices).
  beam=13.0
  lattice_beam=8.0
  min_active=200
  max_active=7000 # limit of active tokens
  max_mem=50000000 # approx. limit to memory consumption during minimization in bytes
  nnet_forward_opts="--no-softmax=true --prior-scale=1.0"
  
  skip_scoring=false
  scoring_opts="--min-lmwt 4 --max-lmwt 15"
  
  num_threads=1 # if >1, will use latgen-faster-parallel
  parallel_opts=   # Ignored now.
  use_gpu="no" # yes|no|optionaly
  # End configuration section.
  
  echo "$0 $@"  # Print the command line for logging
  
  [ -f ./path.sh ] && . ./path.sh; # source the path.
  . parse_options.sh || exit 1;
  
  set -euo pipefail
  
  if [ $# != 3 ]; then
     echo "Usage: $0 [options] <graph-dir> <data-dir> <decode-dir>"
     echo "... where <decode-dir> is assumed to be a sub-directory of the directory"
     echo " where the DNN and transition model is."
     echo "e.g.: $0 exp/dnn1/graph_tgpr data/test exp/dnn1/decode_tgpr"
     echo ""
     echo "This script works on plain or modified features (CMN,delta+delta-delta),"
     echo "which are then sent through feature-transform. It works out what type"
     echo "of features you used from content of srcdir."
     echo ""
     echo "main options (for others, see top of script file)"
     echo "  --config <config-file>                           # config containing options"
     echo "  --nj <nj>                                        # number of parallel jobs"
     echo "  --cmd (utils/run.pl|utils/queue.pl <queue opts>) # how to run jobs."
     echo ""
     echo "  --nnet <nnet>                                    # non-default location of DNN (opt.)"
     echo "  --srcdir <dir>                                   # non-default dir with DNN/models, can be different"
     echo "                                                   # from parent dir of <decode-dir>' (opt.)"
     echo ""
     echo "  --acwt <float>                                   # select acoustic scale for decoding"
     echo "  --scoring-opts <opts>                            # options forwarded to local/score.sh"
     echo "  --num-threads <N>                                # N>1: run multi-threaded decoder"
     exit 1;
  fi
  
  
  graphdir=$1
  data=$2
  dir=$3
  [ -z $srcdir ] && srcdir=`dirname $dir`; # Default model directory one level up from decoding directory.
  sdata=$data/split$nj;
  
  mkdir -p $dir/log
  
  [[ -d $sdata && $data/feats.scp -ot $sdata ]] || split_data.sh $data $nj || exit 1;
  echo $nj > $dir/num_jobs
  
  # Select default locations to model files (if not already set externally)
  [ -z "$nnet" ] && nnet=$srcdir/final.nnet
  [ -z "$model" ] && model=$srcdir/final.mdl
  [ -z "$feature_transform" -a -e $srcdir/final.feature_transform ] && feature_transform=$srcdir/final.feature_transform
  #
  [ -z "$class_frame_counts" -a -f $srcdir/prior_counts ] && class_frame_counts=$srcdir/prior_counts # priority,
  [ -z "$class_frame_counts" ] && class_frame_counts=$srcdir/ali_train_pdf.counts
  
  # Check that files exist,
  for f in $sdata/1/feats.scp $nnet $model $feature_transform $class_frame_counts $graphdir/HCLG.fst; do
    [ ! -f $f ] && echo "$0: missing file $f" && exit 1;
  done
  
  # Possibly use multi-threaded decoder
  thread_string=
  [ $num_threads -gt 1 ] && thread_string="-parallel --num-threads=$num_threads"
  
  
  # PREPARE FEATURE EXTRACTION PIPELINE
  # import config,
  online_cmvn_opts=
  cmvn_opts=
  delta_opts=
  D=$srcdir
  [ -e $D/online_cmvn_opts ] && online_cmvn_opts=$(cat $D/online_cmvn_opts)
  [ -e $D/cmvn_opts ] && cmvn_opts=$(cat $D/cmvn_opts)
  [ -e $D/delta_opts ] && delta_opts=$(cat $D/delta_opts)
  #
  # Create the feature stream,
  feats="ark,s,cs:copy-feats scp:$sdata/JOB/feats.scp ark:- |"
  # apply-cmvn-online (optional),
  [ -n "$online_cmvn_opts" -a ! -f $nndir/global_cmvn_stats.mat ] && echo "$0: Missing $nndir/global_cmvn_stats.mat" && exit 1
  [ -n "$online_cmvn_opts" ] && feats="$feats apply-cmvn-online $online_cmvn_opts --spk2utt=ark:$srcdata/spk2utt $nndir/global_cmvn_stats.mat ark:- ark:- |"
  # apply-cmvn (optional),
  [ -n "$cmvn_opts" -a ! -f $sdata/1/cmvn.scp ] && echo "$0: Missing $sdata/1/cmvn.scp" && exit 1
  [ -n "$cmvn_opts" ] && feats="$feats apply-cmvn $cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spk scp:$sdata/JOB/cmvn.scp ark:- ark:- |"
  # add-deltas (optional),
  [ -n "$delta_opts" ] && feats="$feats add-deltas $delta_opts ark:- ark:- |"
  
  # add-ivector (optional),
  if [ -e $D/ivector_dim ]; then
    [ -z $ivector ] && echo "Missing --ivector, they were used in training!" && exit 1
    # Get the tool,
    ivector_append_tool=append-vector-to-feats # default,
    [ -e $D/ivector_append_tool ] && ivector_append_tool=$(cat $D/ivector_append_tool)
    # Check dims,
    feats_job_1=$(sed 's:JOB:1:g' <(echo $feats))
    dim_raw=$(feat-to-dim "$feats_job_1" -)
    dim_raw_and_ivec=$(feat-to-dim "$feats_job_1 $ivector_append_tool ark:- '$ivector' ark:- |" -)
    dim_ivec=$((dim_raw_and_ivec - dim_raw))
    [ $dim_ivec != "$(cat $D/ivector_dim)" ] && \
      echo "Error, i-vector dim. mismatch (expected $(cat $D/ivector_dim), got $dim_ivec in '$ivector')" && \
      exit 1
    # Append to feats,
    feats="$feats $ivector_append_tool ark:- '$ivector' ark:- |"
  fi
  
  # select a block from blocksoftmax,
  if [ ! -z "$blocksoftmax_dims" ]; then
    # blocksoftmax_active is a csl! dim1,dim2,dim3,...
    [ -z "$blocksoftmax_active" ] && echo "$0 Missing option --blocksoftmax-active N" && exit 1
    # getting dims,
    dim_total=$(awk -F'[:,]' '{ for(i=1;i<=NF;i++) { sum += $i }; print sum; }' <(echo $blocksoftmax_dims))
    dim_block=$(awk -F'[:,]' -v active=$blocksoftmax_active '{ print $active; }' <(echo $blocksoftmax_dims))
    offset=$(awk -F'[:,]' -v active=$blocksoftmax_active '{ sum=0; for(i=1;i<active;i++) { sum += $i }; print sum; }' <(echo $blocksoftmax_dims))
    # create components which select a block,
    nnet-initialize <(echo "<Copy> <InputDim> $dim_total <OutputDim> $dim_block <BuildVector> $((1+offset)):$((offset+dim_block)) </BuildVector>";
                      echo "<Softmax> <InputDim> $dim_block <OutputDim> $dim_block") $dir/copy_and_softmax.nnet
    # nnet is assembled on-the fly, <BlockSoftmax> is removed, while <Copy> + <Softmax> is added,
    nnet="nnet-concat 'nnet-copy --remove-last-components=1 $nnet - |' $dir/copy_and_softmax.nnet - |"
  fi
  
  # Run the decoding in the queue,
  if [ $stage -le 0 ]; then
    $cmd --num-threads $((num_threads+1)) JOB=1:$nj $dir/log/decode.JOB.log \
      nnet-forward $nnet_forward_opts --feature-transform=$feature_transform --class-frame-counts=$class_frame_counts --use-gpu=$use_gpu "$nnet" "$feats" ark:- \| \
      latgen-faster-mapped$thread_string --min-active=$min_active --max-active=$max_active --max-mem=$max_mem --beam=$beam \
      --lattice-beam=$lattice_beam --acoustic-scale=$acwt --allow-partial=true --word-symbol-table=$graphdir/words.txt \
      $model $graphdir/HCLG.fst ark:- "ark:|gzip -c > $dir/lat.JOB.gz" || exit 1;
  fi
  
  # Run the scoring
  if ! $skip_scoring ; then
    [ ! -x local/score.sh ] && \
      echo "Not scoring because local/score.sh does not exist or not executable." && exit 1;
    local/score.sh $scoring_opts --cmd "$cmd" $data $graphdir $dir || exit 1;
  fi
  
  exit 0;