Commit 1ea50549 authored by Dan Povey's avatar Dan Povey
Browse files

Modifications to s3 scripts; add system combination.

git-svn-id: https://svn.code.sf.net/p/kaldi/code/trunk@450 5e6a8d80-dfce-4ca6-a32a-6e07a63d50c8
parent a043cf56
#!/bin/bash
# This script just calls the supplied decoding script
# (typically steps/decode_combine.sh, which is not the
# same as this script) once for each test set,
# and then averages the resulting WERs.
script=$1
decode_dir_in1=$2
decode_dir_in2=$3
decode_dir_out=$4
if [ $# -ne 4 ]; then
echo "Usage: scripts/decode_combine.sh <decode-script> <decode-dir-in1> <decode-dir-in2> <decode-dir-out>"
exit 1;
fi
if [ ! -x $script -o ! -d $decode_dir_in1 -o ! -d $decode_dir_in2 ]; then
echo "scripts/decode.sh: Either no such script $script or not executable, or no such dir $decode_dir_in1 or $decode_dir_in2"
exit 1;
fi
mkdir -p $decode_dir_out
for test in mar87 oct87 feb89 oct89 feb91 sep92; do
$script data/test_$test data/lang $decode_dir_in1/$test $decode_dir_in2/$test $decode_dir_out/$test
done
wait
# Average the WERs... there may be various wer files named e.g. wer, wer_10, etc.,
# so do this for each one.
for w in $decode_dir_out/mar87/wer*; do
wername=`basename $w`
scripts/average_wer.sh $decode_dir_out/?????/$wername > $decode_dir_out/$wername
done
grep WER $decode_dir_out/wer* || echo "Error decoding $decode_dir_out: no WER results found."
......@@ -113,8 +113,15 @@ steps/train_sgmm_lda_etc.sh data/train data/lang exp/tri3d_ali exp/ubm4f/final.u
local/decode.sh steps/decode_sgmm_lda_etc.sh exp/sgmm4f/decode exp/tri3d/decode
# Some system combination experiments (just compose lattices).
local/decode_combine.sh steps/decode_combine.sh exp/tri1/decode exp/tri2a/decode exp/combine_1_2a/decode
local/decode_combine.sh steps/decode_combine.sh exp/sgmm4f/decode/ exp/tri3d/decode exp/combine_sgmm4f_tri3d/decode
for x in exp/*/decode; do grep WER $x/wer_* | scripts/best_wer.sh; done
exp/combine_1_2a/decode/wer_7:%WER 3.399027 [ 426 / 12533, 55 ins, 94 del, 277 sub ]
exp/combine_sgmm4f_tri3d/decode/wer_5:%WER 1.731429 [ 217 / 12533, 30 ins, 43 del, 144 sub ]
exp/mono/decode/wer_6:%WER 10.340701 [ 1296 / 12533, 95 ins, 391 del, 810 sub ]
exp/sgmm3d/decode/wer_5:%WER 2.267284 [ 284 / 12526, 38 ins, 51 del, 195 sub ]
exp/sgmm3e/decode/wer_6:%WER 2.122397 [ 266 / 12533, 37 ins, 51 del, 178 sub ]
......@@ -126,6 +133,7 @@ exp/tri2c/decode/wer_6:%WER 2.833653 [ 355 / 12528, 54 ins, 71 del, 230 sub ]
exp/tri3d/decode/wer_7:%WER 2.489428 [ 312 / 12533, 43 ins, 63 del, 206 sub ]
exp/tri4d/decode/wer_7:%WER 2.649007 [ 332 / 12533, 53 ins, 67 del, 212 sub ]
local/decode_combine.sh steps/decode_combine.sh exp/tri1/decode exp/tri2a/decode exp/combine_tri3d_sgmm4f
##### Below here is trash. ######
......
#!/usr/bin/perl -w
# Copyright 2010-2011 Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
# MERCHANTABLITY OR NON-INFRINGEMENT.
# See the Apache 2 License for the specific language governing permissions and
# limitations under the License.
# This script takes as input any two files in an "scp-like" format that
# has e.g. utterance id's as the first token on each line; and it outputs
# something that will normally be identical to the first file, except that
# if any utterance-id was present in the first input but not the second, it
# will choose the second. Basically this implements a form of backoff.
if(@ARGV != 2) {
die "Usage: backoff_scp.pl in1.scp in2.scp > out.scp ";
}
($f1, $f2) = @ARGV;
open(O, "|sort"); # Sort and put into standard out.
open(F1, "<$f1") || die "Could not open input $f1";
while(<F1>) {
@A = split;
@A>=1 || die "Invalid id-list file line $_";
$seen{$A[0]} = 1;
print O;
}
open(F2, "<$f2") || die "Could not open input $f2";
while(<F2>) {
@A = split;
@A > 0 || die "Invalid scp file line $_";
if(! $seen{$A[0]}) {
print O;
}
}
#!/bin/bash
# Copyright 2010-2011 Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
# MERCHANTABLITY OR NON-INFRINGEMENT.
# See the Apache 2 License for the specific language governing permissions and
# limitations under the License.
# Decoding script that combines two sets of lattices into one.
if [ $# != 5 ]; then
echo "Usage: steps/decode_combine.sh <data-dir> <lang-dir> <decode-dir-in1> <decode-dir-in2> <decode-dir-in3>"
echo " e.g.: steps/decode_combine.sh data/test_feb89 data/lang_test exp/tri1/decode/feb89 exp/tri2a/decode/feb89 exp/decode_combine.1.2a/feb89"
exit 1;
fi
data=$1
lang=$2
indir1=$3
indir2=$4
dir=$5
mkdir -p $dir
if [ -f path.sh ]; then . path.sh; fi
if [[ ! -f $indir1/lat.gz || ! -f $indir2/lat.gz ]]; then
echo "decode_combine.sh: expecting $indir1/lat.gz and $indir2/lat.gz to both exist."
exit 1;
fi
lattice-compose "ark:gunzip -c $indir1/lat.gz|" "ark:gunzip -c $indir2/lat.gz|" \
"ark:|gzip -c > $dir/lat.gz" > $dir/compose.log
# Now rescore lattices with various acoustic scales, and compute the WER.
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
# Fill in any holes in the transcription due to empty composition.
scripts/backoff_scp.pl $dir/${inv_acwt}.tra $indir1/${inv_acwt}.tra > $dir/${inv_acwt}_complete.tra
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
compute-wer --mode=present ark:- ark,p:$dir/${inv_acwt}_complete.tra \
>& $dir/wer_${inv_acwt}
done
......@@ -68,7 +68,7 @@ gmm-latgen-simple --beam=20.0 --acoustic-scale=0.1 --word-symbol-table=$lang/wor
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark:$dir/${inv_acwt}.tra \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
......
......@@ -86,7 +86,7 @@ gmm-latgen-simple --beam=20.0 --acoustic-scale=0.1 --word-symbol-table=$lang/wor
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark:$dir/${inv_acwt}.tra \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
......
......@@ -68,7 +68,7 @@ gmm-latgen-simple --beam=20.0 --acoustic-scale=0.1 --word-symbol-table=$lang/wor
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark:$dir/${inv_acwt}.tra \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
......
......@@ -86,7 +86,7 @@ gmm-latgen-simple --beam=20.0 --acoustic-scale=0.1 --word-symbol-table=$lang/wor
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark:$dir/${inv_acwt}.tra \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
......
......@@ -109,7 +109,7 @@ sgmm-latgen-simple --beam=20.0 --acoustic-scale=0.1 "$gselect_opt" \
for inv_acwt in 4 5 6 7 8 9 10; do
acwt=`perl -e "print (1.0/$inv_acwt);"`
lattice-best-path --acoustic-scale=$acwt --word-symbol-table=$lang/words.txt \
"ark:gunzip -c $dir/lat.gz|" ark:$dir/${inv_acwt}.tra \
"ark:gunzip -c $dir/lat.gz|" ark,t:$dir/${inv_acwt}.tra \
2>$dir/rescore_${inv_acwt}.log
scripts/sym2int.pl --ignore-first-field $lang/words.txt $data/text | \
......
......@@ -292,6 +292,27 @@ void RemoveAlignmentsFromCompactLattice(
}
}
template<class Weight, class Int>
bool CompactLatticeHasAlignment(
const ExpandedFst<ArcTpl<CompactLatticeWeightTpl<Weight, Int> > > &fst) {
typedef CompactLatticeWeightTpl<Weight, Int> W;
typedef ArcTpl<W> Arc;
typedef ExpandedFst<Arc> Fst;
typedef typename Arc::StateId StateId;
typedef typename Arc::Label Label;
StateId num_states = fst.NumStates();
for (StateId s = 0; s < num_states; s++) {
for (ArcIterator<Fst> aiter(fst, s);
!aiter.Done();
aiter.Next()) {
const Arc &arc = aiter.Value();
if (!arc.weight.String().empty()) return true;
}
W final_weight = fst.Final(s);
if (!final_weight.String().empty()) return true;
}
return false;
}
template<class Weight, class Int>
void PruneCompactLattice(
......
......@@ -162,6 +162,13 @@ template<class Weight, class Int>
void RemoveAlignmentsFromCompactLattice(
MutableFst<ArcTpl<CompactLatticeWeightTpl<Weight, Int> > > *fst);
/// Returns true if lattice has alignments, i.e. it has
/// any nonempty strings inside its weights.
template<class Weight, class Int>
bool CompactLatticeHasAlignment(
const ExpandedFst<ArcTpl<CompactLatticeWeightTpl<Weight, Int> > > &fst);
/// Class LatticeToStdMapper maps a normal arc (StdArc)
/// to a LatticeArc by putting the StdArc weight as the first
/// element of the LatticeWeight. Useful when doing LM
......
......@@ -461,7 +461,9 @@ class CompactLatticeWeightTpl {
}
static uint64 Properties() {
return kLeftSemiring | kRightSemiring | kPath | kIdempotent;
return kLeftSemiring | kRightSemiring | kPath | kIdempotent
| kCommutative; // It's not really commutative; this
// is a hack to get composition to work.
}
// This is used in OpenFst for binary I/O. This is OpenFst-style,
......
......@@ -6,7 +6,8 @@ include ../kaldi.mk
BINFILES = lattice-best-path lattice-prune lattice-equivalent lattice-nbest \
lattice-lmrescore lattice-scale lattice-union lattice-to-post \
lattice-determinize lattice-oracle string-to-lattice lattice-rmali
lattice-determinize lattice-oracle string-to-lattice lattice-rmali \
lattice-compose
OBJFILES =
......
// latbin/lattice-compose.cc
// Copyright 2009-2011 Microsoft Corporation; Saarland University
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-lib.h"
#include "lat/kaldi-lattice.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
typedef kaldi::int32 int32;
typedef kaldi::int64 int64;
using fst::SymbolTable;
using fst::VectorFst;
using fst::StdArc;
const char *usage =
"Takes two archives of lattices (indexed by utterances) and composes\n"
"the individual lattice pairs (one from each archive).\n"
"Does this using CompactLattice (acceptor) form. If both lattices\n"
"have alignments, will remove alignments from the first one.\n"
"Usage: lattice-compose [options] lattice-rspecifier1 lattice-rspecifier2"
" lattice-wspecifier\n"
" e.g.: lattice-compose ark:1.lats ark:2.lats ark:composed.lats\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() != 3) {
po.PrintUsage();
exit(1);
}
std::string lats_rspecifier1 = po.GetArg(1),
lats_rspecifier2 = po.GetArg(2),
lats_wspecifier = po.GetArg(3);
SequentialCompactLatticeReader lattice_reader1(lats_rspecifier1);
RandomAccessCompactLatticeReader lattice_reader2(lats_rspecifier2);
CompactLatticeWriter compact_lattice_writer(lats_wspecifier);
int32 n_processed = 0, n_removed_ali = 0,
n_empty = 0, n_success = 0, n_no_2ndlat=0;
for (; !lattice_reader1.Done(); lattice_reader1.Next()) {
std::string key = lattice_reader1.Key();
CompactLattice lat1 = lattice_reader1.Value();
lattice_reader1.FreeCurrent();
if (lattice_reader2.HasKey(key)) {
n_processed++;
const CompactLattice& lat2 = lattice_reader2.Value(key);
if (CompactLatticeHasAlignment(lat1) && CompactLatticeHasAlignment(lat2)) {
RemoveAlignmentsFromCompactLattice(&lat1);
n_removed_ali++;
}
CompactLattice lat3;
Compose(lat1, lat2, &lat3);
if (lat3.Start() == fst::kNoStateId) { // empty composition.
KALDI_WARN << "For utterance " << key << ", composed result is empty.";
n_empty++;
} else {
n_success++;
compact_lattice_writer.Write(key, lat3);
}
} else {
KALDI_WARN << "No lattice found for utterance " << key << " in "
<< lats_rspecifier2 << ". Result of union will be the "
<< "lattice found in " << lats_rspecifier1;
n_no_2ndlat++;
}
}
KALDI_LOG << "Done " << n_processed << " lattices; "
<< n_success << " had nonempty result, " << n_empty
<< " had empty composition; in " << n_no_2ndlat
<< ", had empty second lattice.";
return (n_success != 0 ? 0 : 1);
} catch(const std::exception& e) {
std::cerr << e.what();
return -1;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment