competition update
This commit is contained in:
3
language_model/runtime/core/kaldi/lat/CPPLINT.cfg
Normal file
3
language_model/runtime/core/kaldi/lat/CPPLINT.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
# So many lint errors now, we just ignore it now.
|
||||
# We will try to fix it in the future.
|
||||
exclude_files=.*
|
||||
1545
language_model/runtime/core/kaldi/lat/determinize-lattice-pruned.cc
Normal file
1545
language_model/runtime/core/kaldi/lat/determinize-lattice-pruned.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,296 @@
|
||||
// lat/determinize-lattice-pruned.h
|
||||
|
||||
// Copyright 2009-2012 Microsoft Corporation
|
||||
// 2012-2013 Johns Hopkins University (Author: Daniel Povey)
|
||||
// 2014 Guoguo Chen
|
||||
|
||||
// See ../../COPYING for clarification regarding multiple authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef KALDI_LAT_DETERMINIZE_LATTICE_PRUNED_H_
|
||||
#define KALDI_LAT_DETERMINIZE_LATTICE_PRUNED_H_
|
||||
#include <fst/fstlib.h>
|
||||
#include <fst/fst-decl.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "fstext/lattice-weight.h"
|
||||
// #include "hmm/transition-model.h"
|
||||
#include "itf/options-itf.h"
|
||||
#include "lat/kaldi-lattice.h"
|
||||
|
||||
namespace fst {
|
||||
|
||||
/// \addtogroup fst_extensions
|
||||
/// @{
|
||||
|
||||
|
||||
// For example of usage, see test-determinize-lattice-pruned.cc
|
||||
|
||||
/*
|
||||
DeterminizeLatticePruned implements a special form of determinization with
|
||||
epsilon removal, optimized for a phase of lattice generation. This algorithm
|
||||
also does pruning at the same time-- the combination is more efficient as it
|
||||
somtimes prevents us from creating a lot of states that would later be pruned
|
||||
away. This allows us to increase the lattice-beam and not have the algorithm
|
||||
blow up. Also, because our algorithm processes states in order from those
|
||||
that appear on high-scoring paths down to those that appear on low-scoring
|
||||
paths, we can easily terminate the algorithm after a certain specified number
|
||||
of states or arcs.
|
||||
|
||||
The input is an FST with weight-type BaseWeightType (usually a pair of floats,
|
||||
with a lexicographical type of order, such as LatticeWeightTpl<float>).
|
||||
Typically this would be a state-level lattice, with input symbols equal to
|
||||
words, and output-symbols equal to p.d.f's (so like the inverse of HCLG). Imagine representing this as an
|
||||
acceptor of type CompactLatticeWeightTpl<float>, in which the input/output
|
||||
symbols are words, and the weights contain the original weights together with
|
||||
strings (with zero or one symbol in them) containing the original output labels
|
||||
(the p.d.f.'s). We determinize this using acceptor determinization with
|
||||
epsilon removal. Remember (from lattice-weight.h) that
|
||||
CompactLatticeWeightTpl has a special kind of semiring where we always take
|
||||
the string corresponding to the best cost (of type BaseWeightType), and
|
||||
discard the other. This corresponds to taking the best output-label sequence
|
||||
(of p.d.f.'s) for each input-label sequence (of words). We couldn't use the
|
||||
Gallic weight for this, or it would die as soon as it detected that the input
|
||||
FST was non-functional. In our case, any acyclic FST (and many cyclic ones)
|
||||
can be determinized.
|
||||
We assume that there is a function
|
||||
Compare(const BaseWeightType &a, const BaseWeightType &b)
|
||||
that returns (-1, 0, 1) according to whether (a < b, a == b, a > b) in the
|
||||
total order on the BaseWeightType... this information should be the
|
||||
same as NaturalLess would give, but it's more efficient to do it this way.
|
||||
You can define this for things like TropicalWeight if you need to instantiate
|
||||
this class for that weight type.
|
||||
|
||||
We implement this determinization in a special way to make it efficient for
|
||||
the types of FSTs that we will apply it to. One issue is that if we
|
||||
explicitly represent the strings (in CompactLatticeWeightTpl) as vectors of
|
||||
type vector<IntType>, the algorithm takes time quadratic in the length of
|
||||
words (in states), because propagating each arc involves copying a whole
|
||||
vector (of integers representing p.d.f.'s). Instead we use a hash structure
|
||||
where each string is a pointer (Entry*), and uses a hash from (Entry*,
|
||||
IntType), to the successor string (and a way to get the latest IntType and the
|
||||
ancestor Entry*). [this is the class LatticeStringRepository].
|
||||
|
||||
Another issue is that rather than representing a determinized-state as a
|
||||
collection of (state, weight), we represent it in a couple of reduced forms.
|
||||
Suppose a determinized-state is a collection of (state, weight) pairs; call
|
||||
this the "canonical representation". Note: these collections are always
|
||||
normalized to remove any common weight and string part. Define end-states as
|
||||
the subset of states that have an arc out of them with a label on, or are
|
||||
final. If we represent a determinized-state a the set of just its (end-state,
|
||||
weight) pairs, this will be a valid and more compact representation, and will
|
||||
lead to a smaller set of determinized states (like early minimization). Call
|
||||
this collection of (end-state, weight) pairs the "minimal representation". As
|
||||
a mechanism to reduce compute, we can also consider another representation.
|
||||
In the determinization algorithm, we start off with a set of (begin-state,
|
||||
weight) pairs (where the "begin-states" are initial or have a label on the
|
||||
transition into them), and the "canonical representation" consists of the
|
||||
epsilon-closure of this set (i.e. follow epsilons). Call this set of
|
||||
(begin-state, weight) pairs, appropriately normalized, the "initial
|
||||
representation". If two initial representations are the same, the "canonical
|
||||
representation" and hence the "minimal representation" will be the same. We
|
||||
can use this to reduce compute. Note that if two initial representations are
|
||||
different, this does not preclude the other representations from being the same.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
struct DeterminizeLatticePrunedOptions {
|
||||
float delta; // A small offset used to measure equality of weights.
|
||||
int max_mem; // If >0, determinization will fail and return false
|
||||
// when the algorithm's (approximate) memory consumption crosses this threshold.
|
||||
int max_loop; // If >0, can be used to detect non-determinizable input
|
||||
// (a case that wouldn't be caught by max_mem).
|
||||
int max_states;
|
||||
int max_arcs;
|
||||
float retry_cutoff;
|
||||
DeterminizeLatticePrunedOptions(): delta(kDelta),
|
||||
max_mem(-1),
|
||||
max_loop(-1),
|
||||
max_states(-1),
|
||||
max_arcs(-1),
|
||||
retry_cutoff(0.5) { }
|
||||
void Register (kaldi::OptionsItf *opts) {
|
||||
opts->Register("delta", &delta, "Tolerance used in determinization");
|
||||
opts->Register("max-mem", &max_mem, "Maximum approximate memory usage in "
|
||||
"determinization (real usage might be many times this)");
|
||||
opts->Register("max-arcs", &max_arcs, "Maximum number of arcs in "
|
||||
"output FST (total, not per state");
|
||||
opts->Register("max-states", &max_states, "Maximum number of arcs in output "
|
||||
"FST (total, not per state");
|
||||
opts->Register("max-loop", &max_loop, "Option used to detect a particular "
|
||||
"type of determinization failure, typically due to invalid input "
|
||||
"(e.g., negative-cost loops)");
|
||||
opts->Register("retry-cutoff", &retry_cutoff, "Controls pruning un-determinized "
|
||||
"lattice and retrying determinization: if effective-beam < "
|
||||
"retry-cutoff * beam, we prune the raw lattice and retry. Avoids "
|
||||
"ever getting empty output for long segments.");
|
||||
}
|
||||
};
|
||||
|
||||
struct DeterminizeLatticePhonePrunedOptions {
|
||||
// delta: a small offset used to measure equality of weights.
|
||||
float delta;
|
||||
// max_mem: if > 0, determinization will fail and return false when the
|
||||
// algorithm's (approximate) memory consumption crosses this threshold.
|
||||
int max_mem;
|
||||
// phone_determinize: if true, do a first pass determinization on both phones
|
||||
// and words.
|
||||
bool phone_determinize;
|
||||
// word_determinize: if true, do a second pass determinization on words only.
|
||||
bool word_determinize;
|
||||
// minimize: if true, push and minimize after determinization.
|
||||
bool minimize;
|
||||
DeterminizeLatticePhonePrunedOptions(): delta(kDelta),
|
||||
max_mem(50000000),
|
||||
phone_determinize(true),
|
||||
word_determinize(true),
|
||||
minimize(false) {}
|
||||
void Register (kaldi::OptionsItf *opts) {
|
||||
opts->Register("delta", &delta, "Tolerance used in determinization");
|
||||
opts->Register("max-mem", &max_mem, "Maximum approximate memory usage in "
|
||||
"determinization (real usage might be many times this).");
|
||||
opts->Register("phone-determinize", &phone_determinize, "If true, do an "
|
||||
"initial pass of determinization on both phones and words (see"
|
||||
" also --word-determinize)");
|
||||
opts->Register("word-determinize", &word_determinize, "If true, do a second "
|
||||
"pass of determinization on words only (see also "
|
||||
"--phone-determinize)");
|
||||
opts->Register("minimize", &minimize, "If true, push and minimize after "
|
||||
"determinization.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
This function implements the normal version of DeterminizeLattice, in which the
|
||||
output strings are represented using sequences of arcs, where all but the
|
||||
first one has an epsilon on the input side. It also prunes using the beam
|
||||
in the "prune" parameter. The input FST must be topologically sorted in order
|
||||
for the algorithm to work. For efficiency it is recommended to sort ilabel as well.
|
||||
Returns true on success, and false if it had to terminate the determinization
|
||||
earlier than specified by the "prune" beam-- that is, if it terminated because
|
||||
of the max_mem, max_loop or max_arcs constraints in the options.
|
||||
CAUTION: you may want to use the version below which outputs to CompactLattice.
|
||||
*/
|
||||
template<class Weight>
|
||||
bool DeterminizeLatticePruned(
|
||||
const ExpandedFst<ArcTpl<Weight> > &ifst,
|
||||
double prune,
|
||||
MutableFst<ArcTpl<Weight> > *ofst,
|
||||
DeterminizeLatticePrunedOptions opts = DeterminizeLatticePrunedOptions());
|
||||
|
||||
|
||||
/* This is a version of DeterminizeLattice with a slightly more "natural" output format,
|
||||
where the output sequences are encoded using the CompactLatticeArcTpl template
|
||||
(i.e. the sequences of output symbols are represented directly as strings The input
|
||||
FST must be topologically sorted in order for the algorithm to work. For efficiency
|
||||
it is recommended to sort the ilabel for the input FST as well.
|
||||
Returns true on normal success, and false if it had to terminate the determinization
|
||||
earlier than specified by the "prune" beam-- that is, if it terminated because
|
||||
of the max_mem, max_loop or max_arcs constraints in the options.
|
||||
CAUTION: if Lattice is the input, you need to Invert() before calling this,
|
||||
so words are on the input side.
|
||||
*/
|
||||
template<class Weight, class IntType>
|
||||
bool DeterminizeLatticePruned(
|
||||
const ExpandedFst<ArcTpl<Weight> >&ifst,
|
||||
double prune,
|
||||
MutableFst<ArcTpl<CompactLatticeWeightTpl<Weight, IntType> > > *ofst,
|
||||
DeterminizeLatticePrunedOptions opts = DeterminizeLatticePrunedOptions());
|
||||
|
||||
// /** This function takes in lattices and inserts phones at phone boundaries. It
|
||||
// uses the transition model to work out the transition_id to phone map. The
|
||||
// returning value is the starting index of the phone label. Typically we pick
|
||||
// (maximum_output_label_index + 1) as this value. The inserted phones are then
|
||||
// mapped to (returning_value + original_phone_label) in the new lattice. The
|
||||
// returning value will be used by DeterminizeLatticeDeletePhones() where it
|
||||
// works out the phones according to this value.
|
||||
// */
|
||||
// template<class Weight>
|
||||
// typename ArcTpl<Weight>::Label DeterminizeLatticeInsertPhones(
|
||||
// const kaldi::TransitionModel &trans_model,
|
||||
// MutableFst<ArcTpl<Weight> > *fst);
|
||||
//
|
||||
// /** This function takes in lattices and deletes "phones" from them. The "phones"
|
||||
// here are actually any label that is larger than first_phone_label because
|
||||
// when we insert phones into the lattice, we map the original phone label to
|
||||
// (first_phone_label + original_phone_label). It is supposed to be used
|
||||
// together with DeterminizeLatticeInsertPhones()
|
||||
// */
|
||||
// template<class Weight>
|
||||
// void DeterminizeLatticeDeletePhones(
|
||||
// typename ArcTpl<Weight>::Label first_phone_label,
|
||||
// MutableFst<ArcTpl<Weight> > *fst);
|
||||
//
|
||||
// /** This function is a wrapper of DeterminizeLatticePhonePrunedFirstPass() and
|
||||
// DeterminizeLatticePruned(). If --phone-determinize is set to true, it first
|
||||
// calls DeterminizeLatticePhonePrunedFirstPass() to do the initial pass of
|
||||
// determinization on the phone + word lattices. If --word-determinize is set
|
||||
// true, it then does a second pass of determinization on the word lattices by
|
||||
// calling DeterminizeLatticePruned(). If both are set to false, then it gives
|
||||
// a warning and copying the lattices without determinization.
|
||||
//
|
||||
// Note: the point of doing first a phone-level determinization pass and then
|
||||
// a word-level determinization pass is that it allows us to determinize
|
||||
// deeper lattices without "failing early" and returning a too-small lattice
|
||||
// due to the max-mem constraint. The result should be the same as word-level
|
||||
// determinization in general, but for deeper lattices it is a bit faster,
|
||||
// despite the fact that we now have two passes of determinization by default.
|
||||
// */
|
||||
// template<class Weight, class IntType>
|
||||
// bool DeterminizeLatticePhonePruned(
|
||||
// const kaldi::TransitionModel &trans_model,
|
||||
// const ExpandedFst<ArcTpl<Weight> > &ifst,
|
||||
// double prune,
|
||||
// MutableFst<ArcTpl<CompactLatticeWeightTpl<Weight, IntType> > > *ofst,
|
||||
// DeterminizeLatticePhonePrunedOptions opts
|
||||
// = DeterminizeLatticePhonePrunedOptions());
|
||||
//
|
||||
// /** "Destructive" version of DeterminizeLatticePhonePruned() where the input
|
||||
// lattice might be changed.
|
||||
// */
|
||||
// template<class Weight, class IntType>
|
||||
// bool DeterminizeLatticePhonePruned(
|
||||
// const kaldi::TransitionModel &trans_model,
|
||||
// MutableFst<ArcTpl<Weight> > *ifst,
|
||||
// double prune,
|
||||
// MutableFst<ArcTpl<CompactLatticeWeightTpl<Weight, IntType> > > *ofst,
|
||||
// DeterminizeLatticePhonePrunedOptions opts
|
||||
// = DeterminizeLatticePhonePrunedOptions());
|
||||
//
|
||||
// /** This function is a wrapper of DeterminizeLatticePhonePruned() that works for
|
||||
// Lattice type FSTs. It simplifies the calling process by calling
|
||||
// TopSort() Invert() and ArcSort() for you.
|
||||
// Unlike other determinization routines, the function
|
||||
// requires "ifst" to have transition-id's on the input side and words on the
|
||||
// output side.
|
||||
// This function can be used as the top-level interface to all the determinization
|
||||
// code.
|
||||
// */
|
||||
// bool DeterminizeLatticePhonePrunedWrapper(
|
||||
// const kaldi::TransitionModel &trans_model,
|
||||
// MutableFst<kaldi::LatticeArc> *ifst,
|
||||
// double prune,
|
||||
// MutableFst<kaldi::CompactLatticeArc> *ofst,
|
||||
// DeterminizeLatticePhonePrunedOptions opts
|
||||
// = DeterminizeLatticePhonePrunedOptions());
|
||||
|
||||
/// @} end "addtogroup fst_extensions"
|
||||
|
||||
} // end namespace fst
|
||||
|
||||
#endif
|
||||
506
language_model/runtime/core/kaldi/lat/kaldi-lattice.cc
Normal file
506
language_model/runtime/core/kaldi/lat/kaldi-lattice.cc
Normal file
@@ -0,0 +1,506 @@
|
||||
// lat/kaldi-lattice.cc
|
||||
|
||||
// Copyright 2009-2011 Microsoft Corporation
|
||||
// 2013 Johns Hopkins University (author: Daniel Povey)
|
||||
|
||||
// See ../../COPYING for clarification regarding multiple authors
|
||||
//
|
||||
// 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 "lat/kaldi-lattice.h"
|
||||
#include "fst/script/print-impl.h"
|
||||
|
||||
namespace kaldi {
|
||||
|
||||
/// Converts lattice types if necessary, deleting its input.
|
||||
template<class OrigWeightType>
|
||||
CompactLattice* ConvertToCompactLattice(fst::VectorFst<OrigWeightType> *ifst) {
|
||||
if (!ifst) return NULL;
|
||||
CompactLattice *ofst = new CompactLattice();
|
||||
ConvertLattice(*ifst, ofst);
|
||||
delete ifst;
|
||||
return ofst;
|
||||
}
|
||||
|
||||
// This overrides the template if there is no type conversion going on
|
||||
// (for efficiency).
|
||||
template<>
|
||||
CompactLattice* ConvertToCompactLattice(CompactLattice *ifst) {
|
||||
return ifst;
|
||||
}
|
||||
|
||||
/// Converts lattice types if necessary, deleting its input.
|
||||
template<class OrigWeightType>
|
||||
Lattice* ConvertToLattice(fst::VectorFst<OrigWeightType> *ifst) {
|
||||
if (!ifst) return NULL;
|
||||
Lattice *ofst = new Lattice();
|
||||
ConvertLattice(*ifst, ofst);
|
||||
delete ifst;
|
||||
return ofst;
|
||||
}
|
||||
|
||||
// This overrides the template if there is no type conversion going on
|
||||
// (for efficiency).
|
||||
template<>
|
||||
Lattice* ConvertToLattice(Lattice *ifst) {
|
||||
return ifst;
|
||||
}
|
||||
|
||||
|
||||
bool WriteCompactLattice(std::ostream &os, bool binary,
|
||||
const CompactLattice &t) {
|
||||
if (binary) {
|
||||
fst::FstWriteOptions opts;
|
||||
// Leave all the options default. Normally these lattices wouldn't have any
|
||||
// osymbols/isymbols so no point directing it not to write them (who knows what
|
||||
// we'd want to if we had them).
|
||||
return t.Write(os, opts);
|
||||
} else {
|
||||
// Text-mode output. Note: we expect that t.InputSymbols() and
|
||||
// t.OutputSymbols() would always return NULL. The corresponding input
|
||||
// routine would not work if the FST actually had symbols attached.
|
||||
// Write a newline after the key, so the first line of the FST appears
|
||||
// on its own line.
|
||||
os << '\n';
|
||||
bool acceptor = true, write_one = false;
|
||||
fst::FstPrinter<CompactLatticeArc> printer(t, t.InputSymbols(),
|
||||
t.OutputSymbols(),
|
||||
NULL, acceptor, write_one, "\t");
|
||||
printer.Print(&os, "<unknown>");
|
||||
if (os.fail())
|
||||
KALDI_WARN << "Stream failure detected.";
|
||||
// Write another newline as a terminating character. The read routine will
|
||||
// detect this [this is a Kaldi mechanism, not somethig in the original
|
||||
// OpenFst code].
|
||||
os << '\n';
|
||||
return os.good();
|
||||
}
|
||||
}
|
||||
|
||||
/// LatticeReader provides (static) functions for reading both Lattice
|
||||
/// and CompactLattice, in text form.
|
||||
class LatticeReader {
|
||||
typedef LatticeArc Arc;
|
||||
typedef LatticeWeight Weight;
|
||||
typedef CompactLatticeArc CArc;
|
||||
typedef CompactLatticeWeight CWeight;
|
||||
typedef Arc::Label Label;
|
||||
typedef Arc::StateId StateId;
|
||||
public:
|
||||
// everything is static in this class.
|
||||
|
||||
/** This function reads from the FST text format; it does not know in advance
|
||||
whether it's a Lattice or CompactLattice in the stream so it tries to
|
||||
read both formats until it becomes clear which is the correct one.
|
||||
*/
|
||||
static std::pair<Lattice*, CompactLattice*> ReadText(
|
||||
std::istream &is) {
|
||||
typedef std::pair<Lattice*, CompactLattice*> PairT;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
Lattice *fst = new Lattice();
|
||||
CompactLattice *cfst = new CompactLattice();
|
||||
string line;
|
||||
size_t nline = 0;
|
||||
string separator = FLAGS_fst_field_separator + "\r\n";
|
||||
while (std::getline(is, line)) {
|
||||
nline++;
|
||||
vector<string> col;
|
||||
// on Windows we'll write in text and read in binary mode.
|
||||
SplitStringToVector(line, separator.c_str(), true, &col);
|
||||
if (col.size() == 0) break; // Empty line is a signal to stop, in our
|
||||
// archive format.
|
||||
if (col.size() > 5) {
|
||||
KALDI_WARN << "Reading lattice: bad line in FST: " << line;
|
||||
delete fst;
|
||||
delete cfst;
|
||||
return PairT(static_cast<Lattice*>(NULL),
|
||||
static_cast<CompactLattice*>(NULL));
|
||||
}
|
||||
StateId s;
|
||||
if (!ConvertStringToInteger(col[0], &s)) {
|
||||
KALDI_WARN << "FstCompiler: bad line in FST: " << line;
|
||||
delete fst;
|
||||
delete cfst;
|
||||
return PairT(static_cast<Lattice*>(NULL),
|
||||
static_cast<CompactLattice*>(NULL));
|
||||
}
|
||||
if (fst)
|
||||
while (s >= fst->NumStates())
|
||||
fst->AddState();
|
||||
if (cfst)
|
||||
while (s >= cfst->NumStates())
|
||||
cfst->AddState();
|
||||
if (nline == 1) {
|
||||
if (fst) fst->SetStart(s);
|
||||
if (cfst) cfst->SetStart(s);
|
||||
}
|
||||
|
||||
if (fst) { // we still have fst; try to read that arc.
|
||||
bool ok = true;
|
||||
Arc arc;
|
||||
Weight w;
|
||||
StateId d = s;
|
||||
switch (col.size()) {
|
||||
case 1 :
|
||||
fst->SetFinal(s, Weight::One());
|
||||
break;
|
||||
case 2:
|
||||
if (!StrToWeight(col[1], true, &w)) ok = false;
|
||||
else fst->SetFinal(s, w);
|
||||
break;
|
||||
case 3: // 3 columns not ok for Lattice format; it's not an acceptor.
|
||||
ok = false;
|
||||
break;
|
||||
case 4:
|
||||
ok = ConvertStringToInteger(col[1], &arc.nextstate) &&
|
||||
ConvertStringToInteger(col[2], &arc.ilabel) &&
|
||||
ConvertStringToInteger(col[3], &arc.olabel);
|
||||
if (ok) {
|
||||
d = arc.nextstate;
|
||||
arc.weight = Weight::One();
|
||||
fst->AddArc(s, arc);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
ok = ConvertStringToInteger(col[1], &arc.nextstate) &&
|
||||
ConvertStringToInteger(col[2], &arc.ilabel) &&
|
||||
ConvertStringToInteger(col[3], &arc.olabel) &&
|
||||
StrToWeight(col[4], false, &arc.weight);
|
||||
if (ok) {
|
||||
d = arc.nextstate;
|
||||
fst->AddArc(s, arc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
}
|
||||
while (d >= fst->NumStates())
|
||||
fst->AddState();
|
||||
if (!ok) {
|
||||
delete fst;
|
||||
fst = NULL;
|
||||
}
|
||||
}
|
||||
if (cfst) {
|
||||
bool ok = true;
|
||||
CArc arc;
|
||||
CWeight w;
|
||||
StateId d = s;
|
||||
switch (col.size()) {
|
||||
case 1 :
|
||||
cfst->SetFinal(s, CWeight::One());
|
||||
break;
|
||||
case 2:
|
||||
if (!StrToCWeight(col[1], true, &w)) ok = false;
|
||||
else cfst->SetFinal(s, w);
|
||||
break;
|
||||
case 3: // compact-lattice is acceptor format: state, next-state, label.
|
||||
ok = ConvertStringToInteger(col[1], &arc.nextstate) &&
|
||||
ConvertStringToInteger(col[2], &arc.ilabel);
|
||||
if (ok) {
|
||||
d = arc.nextstate;
|
||||
arc.olabel = arc.ilabel;
|
||||
arc.weight = CWeight::One();
|
||||
cfst->AddArc(s, arc);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
ok = ConvertStringToInteger(col[1], &arc.nextstate) &&
|
||||
ConvertStringToInteger(col[2], &arc.ilabel) &&
|
||||
StrToCWeight(col[3], false, &arc.weight);
|
||||
if (ok) {
|
||||
d = arc.nextstate;
|
||||
arc.olabel = arc.ilabel;
|
||||
cfst->AddArc(s, arc);
|
||||
}
|
||||
break;
|
||||
case 5: default:
|
||||
ok = false;
|
||||
}
|
||||
while (d >= cfst->NumStates())
|
||||
cfst->AddState();
|
||||
if (!ok) {
|
||||
delete cfst;
|
||||
cfst = NULL;
|
||||
}
|
||||
}
|
||||
if (!fst && !cfst) {
|
||||
KALDI_WARN << "Bad line in lattice text format: " << line;
|
||||
// read until we get an empty line, so at least we
|
||||
// have a chance to read the next one (although this might
|
||||
// be a bit futile since the calling code will get unhappy
|
||||
// about failing to read this one.
|
||||
while (std::getline(is, line)) {
|
||||
SplitStringToVector(line, separator.c_str(), true, &col);
|
||||
if (col.empty()) break;
|
||||
}
|
||||
return PairT(static_cast<Lattice*>(NULL),
|
||||
static_cast<CompactLattice*>(NULL));
|
||||
}
|
||||
}
|
||||
return PairT(fst, cfst);
|
||||
}
|
||||
|
||||
static bool StrToWeight(const std::string &s, bool allow_zero, Weight *w) {
|
||||
std::istringstream strm(s);
|
||||
strm >> *w;
|
||||
if (!strm || (!allow_zero && *w == Weight::Zero())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool StrToCWeight(const std::string &s, bool allow_zero, CWeight *w) {
|
||||
std::istringstream strm(s);
|
||||
strm >> *w;
|
||||
if (!strm || (!allow_zero && *w == CWeight::Zero())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
CompactLattice *ReadCompactLatticeText(std::istream &is) {
|
||||
std::pair<Lattice*, CompactLattice*> lat_pair = LatticeReader::ReadText(is);
|
||||
if (lat_pair.second != NULL) {
|
||||
delete lat_pair.first;
|
||||
return lat_pair.second;
|
||||
} else if (lat_pair.first != NULL) {
|
||||
// note: ConvertToCompactLattice frees its input.
|
||||
return ConvertToCompactLattice(lat_pair.first);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Lattice *ReadLatticeText(std::istream &is) {
|
||||
std::pair<Lattice*, CompactLattice*> lat_pair = LatticeReader::ReadText(is);
|
||||
if (lat_pair.first != NULL) {
|
||||
delete lat_pair.second;
|
||||
return lat_pair.first;
|
||||
} else if (lat_pair.second != NULL) {
|
||||
// note: ConvertToLattice frees its input.
|
||||
return ConvertToLattice(lat_pair.second);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadCompactLattice(std::istream &is, bool binary,
|
||||
CompactLattice **clat) {
|
||||
KALDI_ASSERT(*clat == NULL);
|
||||
if (binary) {
|
||||
fst::FstHeader hdr;
|
||||
if (!hdr.Read(is, "<unknown>")) {
|
||||
KALDI_WARN << "Reading compact lattice: error reading FST header.";
|
||||
return false;
|
||||
}
|
||||
if (hdr.FstType() != "vector") {
|
||||
KALDI_WARN << "Reading compact lattice: unsupported FST type: "
|
||||
<< hdr.FstType();
|
||||
return false;
|
||||
}
|
||||
fst::FstReadOptions ropts("<unspecified>",
|
||||
&hdr);
|
||||
|
||||
typedef fst::CompactLatticeWeightTpl<fst::LatticeWeightTpl<float>, int32> T1;
|
||||
typedef fst::CompactLatticeWeightTpl<fst::LatticeWeightTpl<double>, int32> T2;
|
||||
typedef fst::LatticeWeightTpl<float> T3;
|
||||
typedef fst::LatticeWeightTpl<double> T4;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T1> > F1;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T2> > F2;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T3> > F3;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T4> > F4;
|
||||
|
||||
CompactLattice *ans = NULL;
|
||||
if (hdr.ArcType() == T1::Type()) {
|
||||
ans = ConvertToCompactLattice(F1::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T2::Type()) {
|
||||
ans = ConvertToCompactLattice(F2::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T3::Type()) {
|
||||
ans = ConvertToCompactLattice(F3::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T4::Type()) {
|
||||
ans = ConvertToCompactLattice(F4::Read(is, ropts));
|
||||
} else {
|
||||
KALDI_WARN << "FST with arc type " << hdr.ArcType()
|
||||
<< " cannot be converted to CompactLattice.\n";
|
||||
return false;
|
||||
}
|
||||
if (ans == NULL) {
|
||||
KALDI_WARN << "Error reading compact lattice (after reading header).";
|
||||
return false;
|
||||
}
|
||||
*clat = ans;
|
||||
return true;
|
||||
} else {
|
||||
// The next line would normally consume the \r on Windows, plus any
|
||||
// extra spaces that might have got in there somehow.
|
||||
while (std::isspace(is.peek()) && is.peek() != '\n') is.get();
|
||||
if (is.peek() == '\n') is.get(); // consume the newline.
|
||||
else { // saw spaces but no newline.. this is not expected.
|
||||
KALDI_WARN << "Reading compact lattice: unexpected sequence of spaces "
|
||||
<< " at file position " << is.tellg();
|
||||
return false;
|
||||
}
|
||||
*clat = ReadCompactLatticeText(is); // that routine will warn on error.
|
||||
return (*clat != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CompactLatticeHolder::Read(std::istream &is) {
|
||||
Clear(); // in case anything currently stored.
|
||||
int c = is.peek();
|
||||
if (c == -1) {
|
||||
KALDI_WARN << "End of stream detected reading CompactLattice.";
|
||||
return false;
|
||||
} else if (isspace(c)) { // The text form of the lattice begins
|
||||
// with space (normally, '\n'), so this means it's text (the binary form
|
||||
// cannot begin with space because it starts with the FST Type() which is not
|
||||
// space).
|
||||
return ReadCompactLattice(is, false, &t_);
|
||||
} else if (c != 214) { // 214 is first char of FST magic number,
|
||||
// on little-endian machines which is all we support (\326 octal)
|
||||
KALDI_WARN << "Reading compact lattice: does not appear to be an FST "
|
||||
<< " [non-space but no magic number detected], file pos is "
|
||||
<< is.tellg();
|
||||
return false;
|
||||
} else {
|
||||
return ReadCompactLattice(is, true, &t_);
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteLattice(std::ostream &os, bool binary, const Lattice &t) {
|
||||
if (binary) {
|
||||
fst::FstWriteOptions opts;
|
||||
// Leave all the options default. Normally these lattices wouldn't have any
|
||||
// osymbols/isymbols so no point directing it not to write them (who knows what
|
||||
// we'd want to do if we had them).
|
||||
return t.Write(os, opts);
|
||||
} else {
|
||||
// Text-mode output. Note: we expect that t.InputSymbols() and
|
||||
// t.OutputSymbols() would always return NULL. The corresponding input
|
||||
// routine would not work if the FST actually had symbols attached.
|
||||
// Write a newline after the key, so the first line of the FST appears
|
||||
// on its own line.
|
||||
os << '\n';
|
||||
bool acceptor = false, write_one = false;
|
||||
fst::FstPrinter<LatticeArc> printer(t, t.InputSymbols(),
|
||||
t.OutputSymbols(),
|
||||
NULL, acceptor, write_one, "\t");
|
||||
printer.Print(&os, "<unknown>");
|
||||
if (os.fail())
|
||||
KALDI_WARN << "Stream failure detected.";
|
||||
// Write another newline as a terminating character. The read routine will
|
||||
// detect this [this is a Kaldi mechanism, not somethig in the original
|
||||
// OpenFst code].
|
||||
os << '\n';
|
||||
return os.good();
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadLattice(std::istream &is, bool binary,
|
||||
Lattice **lat) {
|
||||
KALDI_ASSERT(*lat == NULL);
|
||||
if (binary) {
|
||||
fst::FstHeader hdr;
|
||||
if (!hdr.Read(is, "<unknown>")) {
|
||||
KALDI_WARN << "Reading lattice: error reading FST header.";
|
||||
return false;
|
||||
}
|
||||
if (hdr.FstType() != "vector") {
|
||||
KALDI_WARN << "Reading lattice: unsupported FST type: "
|
||||
<< hdr.FstType();
|
||||
return false;
|
||||
}
|
||||
fst::FstReadOptions ropts("<unspecified>",
|
||||
&hdr);
|
||||
|
||||
typedef fst::CompactLatticeWeightTpl<fst::LatticeWeightTpl<float>, int32> T1;
|
||||
typedef fst::CompactLatticeWeightTpl<fst::LatticeWeightTpl<double>, int32> T2;
|
||||
typedef fst::LatticeWeightTpl<float> T3;
|
||||
typedef fst::LatticeWeightTpl<double> T4;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T1> > F1;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T2> > F2;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T3> > F3;
|
||||
typedef fst::VectorFst<fst::ArcTpl<T4> > F4;
|
||||
|
||||
Lattice *ans = NULL;
|
||||
if (hdr.ArcType() == T1::Type()) {
|
||||
ans = ConvertToLattice(F1::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T2::Type()) {
|
||||
ans = ConvertToLattice(F2::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T3::Type()) {
|
||||
ans = ConvertToLattice(F3::Read(is, ropts));
|
||||
} else if (hdr.ArcType() == T4::Type()) {
|
||||
ans = ConvertToLattice(F4::Read(is, ropts));
|
||||
} else {
|
||||
KALDI_WARN << "FST with arc type " << hdr.ArcType()
|
||||
<< " cannot be converted to Lattice.\n";
|
||||
return false;
|
||||
}
|
||||
if (ans == NULL) {
|
||||
KALDI_WARN << "Error reading lattice (after reading header).";
|
||||
return false;
|
||||
}
|
||||
*lat = ans;
|
||||
return true;
|
||||
} else {
|
||||
// The next line would normally consume the \r on Windows, plus any
|
||||
// extra spaces that might have got in there somehow.
|
||||
while (std::isspace(is.peek()) && is.peek() != '\n') is.get();
|
||||
if (is.peek() == '\n') is.get(); // consume the newline.
|
||||
else { // saw spaces but no newline.. this is not expected.
|
||||
KALDI_WARN << "Reading compact lattice: unexpected sequence of spaces "
|
||||
<< " at file position " << is.tellg();
|
||||
return false;
|
||||
}
|
||||
*lat = ReadLatticeText(is); // that routine will warn on error.
|
||||
return (*lat != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Since we don't write the binary headers for this type of holder,
|
||||
we use a different method to work out whether we're in binary mode.
|
||||
*/
|
||||
bool LatticeHolder::Read(std::istream &is) {
|
||||
Clear(); // in case anything currently stored.
|
||||
int c = is.peek();
|
||||
if (c == -1) {
|
||||
KALDI_WARN << "End of stream detected reading Lattice.";
|
||||
return false;
|
||||
} else if (isspace(c)) { // The text form of the lattice begins
|
||||
// with space (normally, '\n'), so this means it's text (the binary form
|
||||
// cannot begin with space because it starts with the FST Type() which is not
|
||||
// space).
|
||||
return ReadLattice(is, false, &t_);
|
||||
} else if (c != 214) { // 214 is first char of FST magic number,
|
||||
// on little-endian machines which is all we support (\326 octal)
|
||||
KALDI_WARN << "Reading compact lattice: does not appear to be an FST "
|
||||
<< " [non-space but no magic number detected], file pos is "
|
||||
<< is.tellg();
|
||||
return false;
|
||||
} else {
|
||||
return ReadLattice(is, true, &t_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace kaldi
|
||||
156
language_model/runtime/core/kaldi/lat/kaldi-lattice.h
Normal file
156
language_model/runtime/core/kaldi/lat/kaldi-lattice.h
Normal file
@@ -0,0 +1,156 @@
|
||||
// lat/kaldi-lattice.h
|
||||
|
||||
// Copyright 2009-2011 Microsoft Corporation
|
||||
|
||||
// See ../../COPYING for clarification regarding multiple authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef KALDI_LAT_KALDI_LATTICE_H_
|
||||
#define KALDI_LAT_KALDI_LATTICE_H_
|
||||
|
||||
#include "fstext/fstext-lib.h"
|
||||
#include "base/kaldi-common.h"
|
||||
// #include "util/common-utils.h"
|
||||
|
||||
|
||||
namespace kaldi {
|
||||
// will import some things above...
|
||||
|
||||
typedef fst::LatticeWeightTpl<BaseFloat> LatticeWeight;
|
||||
|
||||
// careful: kaldi::int32 is not always the same C type as fst::int32
|
||||
typedef fst::CompactLatticeWeightTpl<LatticeWeight, int32> CompactLatticeWeight;
|
||||
|
||||
typedef fst::CompactLatticeWeightCommonDivisorTpl<LatticeWeight, int32>
|
||||
CompactLatticeWeightCommonDivisor;
|
||||
|
||||
typedef fst::ArcTpl<LatticeWeight> LatticeArc;
|
||||
|
||||
typedef fst::ArcTpl<CompactLatticeWeight> CompactLatticeArc;
|
||||
|
||||
typedef fst::VectorFst<LatticeArc> Lattice;
|
||||
|
||||
typedef fst::VectorFst<CompactLatticeArc> CompactLattice;
|
||||
|
||||
// The following functions for writing and reading lattices in binary or text
|
||||
// form are provided here in case you need to include lattices in larger,
|
||||
// Kaldi-type objects with their own Read and Write functions. Caution: these
|
||||
// functions return false on stream failure rather than throwing an exception as
|
||||
// most similar Kaldi functions would do.
|
||||
|
||||
bool WriteCompactLattice(std::ostream &os, bool binary,
|
||||
const CompactLattice &clat);
|
||||
bool WriteLattice(std::ostream &os, bool binary,
|
||||
const Lattice &lat);
|
||||
|
||||
// the following function requires that *clat be
|
||||
// NULL when called.
|
||||
bool ReadCompactLattice(std::istream &is, bool binary,
|
||||
CompactLattice **clat);
|
||||
// the following function requires that *lat be
|
||||
// NULL when called.
|
||||
bool ReadLattice(std::istream &is, bool binary,
|
||||
Lattice **lat);
|
||||
|
||||
|
||||
class CompactLatticeHolder {
|
||||
public:
|
||||
typedef CompactLattice T;
|
||||
|
||||
CompactLatticeHolder() { t_ = NULL; }
|
||||
|
||||
static bool Write(std::ostream &os, bool binary, const T &t) {
|
||||
// Note: we don't include the binary-mode header when writing
|
||||
// this object to disk; this ensures that if we write to single
|
||||
// files, the result can be read by OpenFst.
|
||||
return WriteCompactLattice(os, binary, t);
|
||||
}
|
||||
|
||||
bool Read(std::istream &is);
|
||||
|
||||
static bool IsReadInBinary() { return true; }
|
||||
|
||||
T &Value() {
|
||||
KALDI_ASSERT(t_ != NULL && "Called Value() on empty CompactLatticeHolder");
|
||||
return *t_;
|
||||
}
|
||||
|
||||
void Clear() { delete t_; t_ = NULL; }
|
||||
|
||||
void Swap(CompactLatticeHolder *other) {
|
||||
std::swap(t_, other->t_);
|
||||
}
|
||||
|
||||
bool ExtractRange(const CompactLatticeHolder &other, const std::string &range) {
|
||||
KALDI_ERR << "ExtractRange is not defined for this type of holder.";
|
||||
return false;
|
||||
}
|
||||
|
||||
~CompactLatticeHolder() { Clear(); }
|
||||
private:
|
||||
T *t_;
|
||||
};
|
||||
|
||||
class LatticeHolder {
|
||||
public:
|
||||
typedef Lattice T;
|
||||
|
||||
LatticeHolder() { t_ = NULL; }
|
||||
|
||||
static bool Write(std::ostream &os, bool binary, const T &t) {
|
||||
// Note: we don't include the binary-mode header when writing
|
||||
// this object to disk; this ensures that if we write to single
|
||||
// files, the result can be read by OpenFst.
|
||||
return WriteLattice(os, binary, t);
|
||||
}
|
||||
|
||||
bool Read(std::istream &is);
|
||||
|
||||
static bool IsReadInBinary() { return true; }
|
||||
|
||||
T &Value() {
|
||||
KALDI_ASSERT(t_ != NULL && "Called Value() on empty LatticeHolder");
|
||||
return *t_;
|
||||
}
|
||||
|
||||
void Clear() { delete t_; t_ = NULL; }
|
||||
|
||||
void Swap(LatticeHolder *other) {
|
||||
std::swap(t_, other->t_);
|
||||
}
|
||||
|
||||
bool ExtractRange(const LatticeHolder &other, const std::string &range) {
|
||||
KALDI_ERR << "ExtractRange is not defined for this type of holder.";
|
||||
return false;
|
||||
}
|
||||
|
||||
~LatticeHolder() { Clear(); }
|
||||
private:
|
||||
T *t_;
|
||||
};
|
||||
|
||||
// typedef TableWriter<LatticeHolder> LatticeWriter;
|
||||
// typedef SequentialTableReader<LatticeHolder> SequentialLatticeReader;
|
||||
// typedef RandomAccessTableReader<LatticeHolder> RandomAccessLatticeReader;
|
||||
//
|
||||
// typedef TableWriter<CompactLatticeHolder> CompactLatticeWriter;
|
||||
// typedef SequentialTableReader<CompactLatticeHolder> SequentialCompactLatticeReader;
|
||||
// typedef RandomAccessTableReader<CompactLatticeHolder> RandomAccessCompactLatticeReader;
|
||||
|
||||
|
||||
} // namespace kaldi
|
||||
|
||||
#endif // KALDI_LAT_KALDI_LATTICE_H_
|
||||
1992
language_model/runtime/core/kaldi/lat/lattice-functions.cc
Normal file
1992
language_model/runtime/core/kaldi/lat/lattice-functions.cc
Normal file
File diff suppressed because it is too large
Load Diff
455
language_model/runtime/core/kaldi/lat/lattice-functions.h
Normal file
455
language_model/runtime/core/kaldi/lat/lattice-functions.h
Normal file
@@ -0,0 +1,455 @@
|
||||
// lat/lattice-functions.h
|
||||
|
||||
// Copyright 2009-2012 Saarland University (author: Arnab Ghoshal)
|
||||
// 2012-2013 Johns Hopkins University (Author: Daniel Povey);
|
||||
// Bagher BabaAli
|
||||
// 2014 Guoguo Chen
|
||||
|
||||
// See ../../COPYING for clarification regarding multiple authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef KALDI_LAT_LATTICE_FUNCTIONS_H_
|
||||
#define KALDI_LAT_LATTICE_FUNCTIONS_H_
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "base/kaldi-common.h"
|
||||
// #include "hmm/posterior.h"
|
||||
#include "fstext/fstext-lib.h"
|
||||
// #include "hmm/transition-model.h"
|
||||
#include "lat/kaldi-lattice.h"
|
||||
// #include "itf/decodable-itf.h"
|
||||
|
||||
namespace kaldi {
|
||||
|
||||
// /**
|
||||
// This function extracts the per-frame log likelihoods from a linear
|
||||
// lattice (which we refer to as an 'nbest' lattice elsewhere in Kaldi code).
|
||||
// The dimension of *per_frame_loglikes will be set to the
|
||||
// number of input symbols in 'nbest'. The elements of
|
||||
// '*per_frame_loglikes' will be set to the .Value2() elements of the lattice
|
||||
// weights, which represent the acoustic costs; you may want to scale this
|
||||
// vector afterward by -1/acoustic_scale to get the original loglikes.
|
||||
// If there are acoustic costs on input-epsilon arcs or the final-prob in 'nbest'
|
||||
// (and this should not normally be the case in situations where it makes
|
||||
// sense to call this function), they will be included to the cost of the
|
||||
// preceding input symbol, or the following input symbol for input-epsilons
|
||||
// encountered prior to any input symbol. If 'nbest' has no input symbols,
|
||||
// 'per_frame_loglikes' will be set to the empty vector.
|
||||
// **/
|
||||
// void GetPerFrameAcousticCosts(const Lattice &nbest,
|
||||
// Vector<BaseFloat> *per_frame_loglikes);
|
||||
//
|
||||
// /// This function iterates over the states of a topologically sorted lattice and
|
||||
// /// counts the time instance corresponding to each state. The times are returned
|
||||
// /// in a vector of integers 'times' which is resized to have a size equal to the
|
||||
// /// number of states in the lattice. The function also returns the maximum time
|
||||
// /// in the lattice (this will equal the number of frames in the file).
|
||||
// int32 LatticeStateTimes(const Lattice &lat, std::vector<int32> *times);
|
||||
//
|
||||
// /// As LatticeStateTimes, but in the CompactLattice format. Note: must
|
||||
// /// be topologically sorted. Returns length of the utterance in frames, which
|
||||
// /// might not be the same as the maximum time in the lattice, due to frames
|
||||
// /// in the final-prob.
|
||||
// int32 CompactLatticeStateTimes(const CompactLattice &clat,
|
||||
// std::vector<int32> *times);
|
||||
//
|
||||
// /// This function does the forward-backward over lattices and computes the
|
||||
// /// posterior probabilities of the arcs. It returns the total log-probability
|
||||
// /// of the lattice. The Posterior quantities contain pairs of (transition-id, weight)
|
||||
// /// on each frame.
|
||||
// /// If the pointer "acoustic_like_sum" is provided, this value is set to
|
||||
// /// the sum over the arcs, of the posterior of the arc times the
|
||||
// /// acoustic likelihood [i.e. negated acoustic score] on that link.
|
||||
// /// This is used in combination with other quantities to work out
|
||||
// /// the objective function in MMI discriminative training.
|
||||
// BaseFloat LatticeForwardBackward(const Lattice &lat,
|
||||
// Posterior *arc_post,
|
||||
// double *acoustic_like_sum = NULL);
|
||||
//
|
||||
// // This function is something similar to LatticeForwardBackward(), but it is on
|
||||
// // the CompactLattice lattice format. Also we only need the alpha in the forward
|
||||
// // path, not the posteriors.
|
||||
// bool ComputeCompactLatticeAlphas(const CompactLattice &lat,
|
||||
// std::vector<double> *alpha);
|
||||
//
|
||||
// // A sibling of the function CompactLatticeAlphas()... We compute the beta from
|
||||
// // the backward path here.
|
||||
// bool ComputeCompactLatticeBetas(const CompactLattice &lat,
|
||||
// std::vector<double> *beta);
|
||||
//
|
||||
//
|
||||
// // Computes (normal or Viterbi) alphas and betas; returns (total-prob, or
|
||||
// // best-path negated cost) Note: in either case, the alphas and betas are
|
||||
// // negated costs. Requires that lat be topologically sorted. This code
|
||||
// // will work for either CompactLattice or Latice.
|
||||
// template<typename LatticeType>
|
||||
// double ComputeLatticeAlphasAndBetas(const LatticeType &lat,
|
||||
// bool viterbi,
|
||||
// std::vector<double> *alpha,
|
||||
// std::vector<double> *beta);
|
||||
//
|
||||
//
|
||||
// /// Topologically sort the compact lattice if not already topologically sorted.
|
||||
// /// Will crash if the lattice cannot be topologically sorted.
|
||||
// void TopSortCompactLatticeIfNeeded(CompactLattice *clat);
|
||||
//
|
||||
//
|
||||
// /// Topologically sort the lattice if not already topologically sorted.
|
||||
// /// Will crash if lattice cannot be topologically sorted.
|
||||
// void TopSortLatticeIfNeeded(Lattice *clat);
|
||||
//
|
||||
// /// Returns the depth of the lattice, defined as the average number of arcs (or
|
||||
// /// final-prob strings) crossing any given frame. Returns 1 for empty lattices.
|
||||
// /// Requires that clat is topologically sorted!
|
||||
// BaseFloat CompactLatticeDepth(const CompactLattice &clat,
|
||||
// int32 *num_frames = NULL);
|
||||
//
|
||||
// /// This function returns, for each frame, the number of arcs crossing that
|
||||
// /// frame.
|
||||
// void CompactLatticeDepthPerFrame(const CompactLattice &clat,
|
||||
// std::vector<int32> *depth_per_frame);
|
||||
//
|
||||
//
|
||||
// /// This function limits the depth of the lattice, per frame: that means, it
|
||||
// /// does not allow more than a specified number of arcs active on any given
|
||||
// /// frame. This can be used to reduce the size of the "very deep" portions of
|
||||
// /// the lattice.
|
||||
// void CompactLatticeLimitDepth(int32 max_arcs_per_frame,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
//
|
||||
// /// Given a lattice, and a transition model to map pdf-ids to phones,
|
||||
// /// outputs for each frame the set of phones active on that frame. If
|
||||
// /// sil_phones (which must be sorted and uniq) is nonempty, it excludes
|
||||
// /// phones in this list.
|
||||
// void LatticeActivePhones(const Lattice &lat, const TransitionModel &trans,
|
||||
// const std::vector<int32> &sil_phones,
|
||||
// std::vector<std::set<int32> > *active_phones);
|
||||
//
|
||||
// /// Given a lattice, and a transition model to map pdf-ids to phones,
|
||||
// /// replace the output symbols (presumably words), with phones; we
|
||||
// /// use the TransitionModel to work out the phone sequence. Note
|
||||
// /// that the phone labels are not exactly aligned with the phone
|
||||
// /// boundaries. We put a phone label to coincide with any transition
|
||||
// /// to the final, nonemitting state of a phone (this state always exists,
|
||||
// /// we ensure this in HmmTopology::Check()). This would be the last
|
||||
// /// transition-id in the phone if reordering is not done (but typically
|
||||
// /// we do reorder).
|
||||
// /// Also see PhoneAlignLattice, in phone-align-lattice.h.
|
||||
// void ConvertLatticeToPhones(const TransitionModel &trans_model,
|
||||
// Lattice *lat);
|
||||
|
||||
/// Prunes a lattice or compact lattice. Returns true on success, false if
|
||||
/// there was some kind of failure.
|
||||
template<class LatticeType>
|
||||
bool PruneLattice(BaseFloat beam, LatticeType *lat);
|
||||
|
||||
//
|
||||
// /// Given a lattice, and a transition model to map pdf-ids to phones,
|
||||
// /// replace the sequences of transition-ids with sequences of phones.
|
||||
// /// Note that this is different from ConvertLatticeToPhones, in that
|
||||
// /// we replace the transition-ids not the words.
|
||||
// void ConvertCompactLatticeToPhones(const TransitionModel &trans_model,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
// /// Boosts LM probabilities by b * [number of frame errors]; equivalently, adds
|
||||
// /// -b*[number of frame errors] to the graph-component of the cost of each arc/path.
|
||||
// /// There is a frame error if a particular transition-id on a particular frame
|
||||
// /// corresponds to a phone not matching transcription's alignment for that frame.
|
||||
// /// This is used in "margin-inspired" discriminative training, esp. Boosted MMI.
|
||||
// /// The TransitionModel is used to map transition-ids in the lattice
|
||||
// /// input-side to phones; the phones appearing in
|
||||
// /// "silence_phones" are treated specially in that we replace the frame error f
|
||||
// /// (either zero or 1) for a frame, with the minimum of f or max_silence_error.
|
||||
// /// For the normal recipe, max_silence_error would be zero.
|
||||
// /// Returns true on success, false if there was some kind of mismatch.
|
||||
// /// At input, silence_phones must be sorted and unique.
|
||||
// bool LatticeBoost(const TransitionModel &trans,
|
||||
// const std::vector<int32> &alignment,
|
||||
// const std::vector<int32> &silence_phones,
|
||||
// BaseFloat b,
|
||||
// BaseFloat max_silence_error,
|
||||
// Lattice *lat);
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// This function implements either the MPFE (minimum phone frame error) or SMBR
|
||||
// (state-level minimum bayes risk) forward-backward, depending on whether
|
||||
// "criterion" is "mpfe" or "smbr". It returns the MPFE
|
||||
// criterion of SMBR criterion for this utterance, and outputs the posteriors (which
|
||||
// may be positive or negative) into "post".
|
||||
//
|
||||
// @param [in] trans The transition model. Used to map the
|
||||
// transition-ids to phones or pdfs.
|
||||
// @param [in] silence_phones A list of integer ids of silence phones. The
|
||||
// silence frames i.e. the frames where num_ali
|
||||
// corresponds to a silence phones are treated specially.
|
||||
// The behavior is determined by 'one_silence_class'
|
||||
// being false (traditional behavior) or true.
|
||||
// Usually in our setup, several phones including
|
||||
// the silence, vocalized noise, non-spoken noise
|
||||
// and unk are treated as "silence phones"
|
||||
// @param [in] lat The denominator lattice
|
||||
// @param [in] num_ali The numerator alignment
|
||||
// @param [in] criterion The objective function. Must be "mpfe" or "smbr"
|
||||
// for MPFE (minimum phone frame error) or sMBR
|
||||
// (state minimum bayes risk) training.
|
||||
// @param [in] one_silence_class Determines how the silence frames are treated.
|
||||
// Setting this to false gives the old traditional behavior,
|
||||
// where the silence frames (according to num_ali) are
|
||||
// treated as incorrect. However, this means that the
|
||||
// insertions are not penalized by the objective.
|
||||
// Setting this to true gives the new behaviour, where we
|
||||
// treat silence as any other phone, except that all pdfs
|
||||
// of silence phones are collapsed into a single class for
|
||||
// the frame-error computation. This can possible reduce
|
||||
// the insertions in the trained model. This is closer to
|
||||
// the WER metric that we actually care about, since WER is
|
||||
// generally computed after filtering out noises, but
|
||||
// does penalize insertions.
|
||||
// @param [out] post The "MBR posteriors" i.e. derivatives w.r.t to the
|
||||
// pseudo log-likelihoods of states at each frame.
|
||||
// */
|
||||
// BaseFloat LatticeForwardBackwardMpeVariants(
|
||||
// const TransitionModel &trans,
|
||||
// const std::vector<int32> &silence_phones,
|
||||
// const Lattice &lat,
|
||||
// const std::vector<int32> &num_ali,
|
||||
// std::string criterion,
|
||||
// bool one_silence_class,
|
||||
// Posterior *post);
|
||||
//
|
||||
// /**
|
||||
// This function can be used to compute posteriors for MMI, with a positive contribution
|
||||
// for the numerator and a negative one for the denominator. This function is not actually
|
||||
// used in our normal MMI training recipes, where it's instead done using various command
|
||||
// line programs that each do a part of the job. This function was written for use in
|
||||
// neural-net MMI training.
|
||||
//
|
||||
// @param [in] trans The transition model. Used to map the
|
||||
// transition-ids to phones or pdfs.
|
||||
// @param [in] lat The denominator lattice
|
||||
// @param [in] num_ali The numerator alignment
|
||||
// @param [in] drop_frames If "drop_frames" is true, it will not compute any
|
||||
// posteriors on frames where the num and den have disjoint
|
||||
// pdf-ids.
|
||||
// @param [in] convert_to_pdf_ids If "convert_to_pdfs_ids" is true, it will
|
||||
// convert the output to be at the level of pdf-ids, not
|
||||
// transition-ids.
|
||||
// @param [in] cancel If "cancel" is true, it will cancel out any positive and
|
||||
// negative parts from the same transition-id (or pdf-id,
|
||||
// if convert_to_pdf_ids == true).
|
||||
// @param [out] arc_post The output MMI posteriors of transition-ids (or
|
||||
// pdf-ids if convert_to_pdf_ids == true) at each frame
|
||||
// i.e. the difference between the numerator
|
||||
// and denominator posteriors.
|
||||
//
|
||||
// It returns the forward-backward likelihood of the lattice. */
|
||||
// BaseFloat LatticeForwardBackwardMmi(
|
||||
// const TransitionModel &trans,
|
||||
// const Lattice &lat,
|
||||
// const std::vector<int32> &num_ali,
|
||||
// bool drop_frames,
|
||||
// bool convert_to_pdf_ids,
|
||||
// bool cancel,
|
||||
// Posterior *arc_post);
|
||||
//
|
||||
//
|
||||
// /// This function takes a CompactLattice that should only contain a single
|
||||
// /// linear sequence (e.g. derived from lattice-1best), and that should have been
|
||||
// /// processed so that the arcs in the CompactLattice align correctly with the
|
||||
// /// word boundaries (e.g. by lattice-align-words). It outputs 3 vectors of the
|
||||
// /// same size, which give, for each word in the lattice (in sequence), the word
|
||||
// /// label and the begin time and length in frames. This is done even for zero
|
||||
// /// (epsilon) words, generally corresponding to optional silence-- if you don't
|
||||
// /// want them, just ignore them in the output.
|
||||
// /// This function will print a warning and return false, if the lattice
|
||||
// /// did not have the correct format (e.g. if it is empty or it is not
|
||||
// /// linear).
|
||||
// bool CompactLatticeToWordAlignment(const CompactLattice &clat,
|
||||
// std::vector<int32> *words,
|
||||
// std::vector<int32> *begin_times,
|
||||
// std::vector<int32> *lengths);
|
||||
//
|
||||
// /// This function takes a CompactLattice that should only contain a single
|
||||
// /// linear sequence (e.g. derived from lattice-1best), and that should have been
|
||||
// /// processed so that the arcs in the CompactLattice align correctly with the
|
||||
// /// word boundaries (e.g. by lattice-align-words). It outputs 4 vectors of the
|
||||
// /// same size, which give, for each word in the lattice (in sequence), the word
|
||||
// /// label, the begin time and length in frames, and the pronunciation (sequence
|
||||
// /// of phones). This is done even for zero words, corresponding to optional
|
||||
// /// silences -- if you don't want them, just ignore them in the output.
|
||||
// /// This function will print a warning and return false, if the lattice
|
||||
// /// did not have the correct format (e.g. if it is empty or it is not
|
||||
// /// linear).
|
||||
// bool CompactLatticeToWordProns(
|
||||
// const TransitionModel &tmodel,
|
||||
// const CompactLattice &clat,
|
||||
// std::vector<int32> *words,
|
||||
// std::vector<int32> *begin_times,
|
||||
// std::vector<int32> *lengths,
|
||||
// std::vector<std::vector<int32> > *prons,
|
||||
// std::vector<std::vector<int32> > *phone_lengths);
|
||||
//
|
||||
//
|
||||
// /// A form of the shortest-path/best-path algorithm that's specially coded for
|
||||
// /// CompactLattice. Requires that clat be acyclic.
|
||||
// void CompactLatticeShortestPath(const CompactLattice &clat,
|
||||
// CompactLattice *shortest_path);
|
||||
//
|
||||
// /// This function expands a CompactLattice to ensure high-probability paths
|
||||
// /// have unique histories. Arcs with posteriors larger than epsilon get splitted.
|
||||
// void ExpandCompactLattice(const CompactLattice &clat,
|
||||
// double epsilon,
|
||||
// CompactLattice *expand_clat);
|
||||
//
|
||||
// /// For each state, compute forward and backward best (viterbi) costs and its
|
||||
// /// traceback states (for generating best paths later). The forward best cost
|
||||
// /// for a state is the cost of the best path from the start state to the state.
|
||||
// /// The traceback state of this state is its predecessor state in the best path.
|
||||
// /// The backward best cost for a state is the cost of the best path from the
|
||||
// /// state to a final one. Its traceback state is the successor state in the best
|
||||
// /// path in the forward direction.
|
||||
// /// Note: final weights of states are in backward_best_cost_and_pred.
|
||||
// /// Requires the input CompactLattice clat be acyclic.
|
||||
// typedef std::vector<std::pair<double,
|
||||
// CompactLatticeArc::StateId> > CostTraceType;
|
||||
// void CompactLatticeBestCostsAndTracebacks(
|
||||
// const CompactLattice &clat,
|
||||
// CostTraceType *forward_best_cost_and_pred,
|
||||
// CostTraceType *backward_best_cost_and_pred);
|
||||
//
|
||||
// /// This function adds estimated neural language model scores of words in a
|
||||
// /// minimal list of hypotheses that covers a lattice, to the graph scores on the
|
||||
// /// arcs. The list of hypotheses are generated by latbin/lattice-path-cover.
|
||||
// typedef unordered_map<std::pair<int32, int32>, double, PairHasher<int32> > MapT;
|
||||
// void AddNnlmScoreToCompactLattice(const MapT &nnlm_scores,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
// /// This function add the word insertion penalty to graph score of each word
|
||||
// /// in the compact lattice
|
||||
// void AddWordInsPenToCompactLattice(BaseFloat word_ins_penalty,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
// /// This function *adds* the negated scores obtained from the Decodable object,
|
||||
// /// to the acoustic scores on the arcs. If you want to replace them, you should
|
||||
// /// use ScaleCompactLattice to first set the acoustic scores to zero. Returns
|
||||
// /// true on success, false on error (typically some kind of mismatched inputs).
|
||||
// bool RescoreCompactLattice(DecodableInterface *decodable,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
//
|
||||
// /// This function returns the number of words in the longest sentence in a
|
||||
// /// CompactLattice (i.e. the the maximum of any path, of the count of
|
||||
// /// olabels on that path).
|
||||
// int32 LongestSentenceLength(const Lattice &lat);
|
||||
//
|
||||
// /// This function returns the number of words in the longest sentence in a
|
||||
// /// CompactLattice, i.e. the the maximum of any path, of the count of
|
||||
// /// labels on that path... note, in CompactLattice, the ilabels and olabels
|
||||
// /// are identical because it is an acceptor.
|
||||
// int32 LongestSentenceLength(const CompactLattice &lat);
|
||||
//
|
||||
//
|
||||
// /// This function is like RescoreCompactLattice, but it is modified to avoid
|
||||
// /// computing probabilities on most frames where all the pdf-ids are the same.
|
||||
// /// (it needs the transition-model to work out whether two transition-ids map to
|
||||
// /// the same pdf-id, and it assumes that the lattice has transition-ids on it).
|
||||
// /// The naive thing would be to just set all probabilities to zero on frames
|
||||
// /// where all the pdf-ids are the same (because this value won't affect the
|
||||
// /// lattice posterior). But this would become confusing when we compute
|
||||
// /// corpus-level diagnostics such as the MMI objective function. Instead,
|
||||
// /// imagine speedup_factor = 100 (it must be >= 1.0)... with probability (1.0 /
|
||||
// /// speedup_factor) we compute those likelihoods and multiply them by
|
||||
// /// speedup_factor; otherwise we set them to zero. This gives the right
|
||||
// /// expected probability so our corpus-level diagnostics will be about right.
|
||||
// bool RescoreCompactLatticeSpeedup(
|
||||
// const TransitionModel &tmodel,
|
||||
// BaseFloat speedup_factor,
|
||||
// DecodableInterface *decodable,
|
||||
// CompactLattice *clat);
|
||||
//
|
||||
//
|
||||
// /// This function *adds* the negated scores obtained from the Decodable object,
|
||||
// /// to the acoustic scores on the arcs. If you want to replace them, you should
|
||||
// /// use ScaleCompactLattice to first set the acoustic scores to zero. Returns
|
||||
// /// true on success, false on error (e.g. some kind of mismatched inputs).
|
||||
// /// The input labels, if nonzero, are interpreted as transition-ids or whatever
|
||||
// /// other index the Decodable object expects.
|
||||
// bool RescoreLattice(DecodableInterface *decodable,
|
||||
// Lattice *lat);
|
||||
//
|
||||
// /// This function Composes a CompactLattice format lattice with a
|
||||
// /// DeterministicOnDemandFst<fst::StdFst> format fst, and outputs another
|
||||
// /// CompactLattice format lattice. The first element (the one that corresponds
|
||||
// /// to LM weight) in CompactLatticeWeight is used for composition.
|
||||
// ///
|
||||
// /// Note that the DeterministicOnDemandFst interface is not "const", therefore
|
||||
// /// we cannot use "const" for <det_fst>.
|
||||
// void ComposeCompactLatticeDeterministic(
|
||||
// const CompactLattice& clat,
|
||||
// fst::DeterministicOnDemandFst<fst::StdArc>* det_fst,
|
||||
// CompactLattice* composed_clat);
|
||||
//
|
||||
// /// This function computes the mapping from the pair
|
||||
// /// (frame-index, transition-id) to the pair
|
||||
// /// (sum-of-acoustic-scores, num-of-occurences) over all occurences of the
|
||||
// /// transition-id in that frame.
|
||||
// /// frame-index in the lattice.
|
||||
// /// This function is useful for retaining the acoustic scores in a
|
||||
// /// non-compact lattice after a process like determinization where the
|
||||
// /// frame-level acoustic scores are typically lost.
|
||||
// /// The function ReplaceAcousticScoresFromMap is used to restore the
|
||||
// /// acoustic scores computed by this function.
|
||||
// ///
|
||||
// /// @param [in] lat Input lattice. Expected to be top-sorted. Otherwise the
|
||||
// /// function will crash.
|
||||
// /// @param [out] acoustic_scores
|
||||
// /// Pointer to a map from the pair (frame-index,
|
||||
// /// transition-id) to a pair (sum-of-acoustic-scores,
|
||||
// /// num-of-occurences).
|
||||
// /// Usually the acoustic scores for a pdf-id (and hence
|
||||
// /// transition-id) on a frame will be the same for all the
|
||||
// /// occurences of the pdf-id in that frame.
|
||||
// /// But if not, we will take the average of the acoustic
|
||||
// /// scores. Hence, we store both the sum-of-acoustic-scores
|
||||
// /// and the num-of-occurences of the transition-id in that
|
||||
// /// frame.
|
||||
// void ComputeAcousticScoresMap(
|
||||
// const Lattice &lat,
|
||||
// unordered_map<std::pair<int32, int32>, std::pair<BaseFloat, int32>,
|
||||
// PairHasher<int32> > *acoustic_scores);
|
||||
//
|
||||
// /// This function restores acoustic scores computed using the function
|
||||
// /// ComputeAcousticScoresMap into the lattice.
|
||||
// ///
|
||||
// /// @param [in] acoustic_scores
|
||||
// /// A map from the pair (frame-index, transition-id) to a
|
||||
// /// pair (sum-of-acoustic-scores, num-of-occurences) of
|
||||
// /// the occurences of the transition-id in that frame.
|
||||
// /// See the comments for ComputeAcousticScoresMap for
|
||||
// /// details.
|
||||
// /// @param [out] lat Pointer to the output lattice.
|
||||
// void ReplaceAcousticScoresFromMap(
|
||||
// const unordered_map<std::pair<int32, int32>, std::pair<BaseFloat, int32>,
|
||||
// PairHasher<int32> > &acoustic_scores,
|
||||
// Lattice *lat);
|
||||
|
||||
} // namespace kaldi
|
||||
|
||||
#endif // KALDI_LAT_LATTICE_FUNCTIONS_H_
|
||||
Reference in New Issue
Block a user