Initial commit: FunASR Speech Recognition Toolkit
Update API Documentation / build-api-docs (push) Has been cancelled

Add complete FunASR codebase including models, runtime, and documentation.
This commit is contained in:
freedakgmail
2026-07-09 22:38:58 +08:00
commit 6116b1f3c6
3683 changed files with 990984 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
# make "all" the target.
all:
# Disable linking math libs because not needed here. Just for compilation speed.
# no, it's now needed for context-fst-test.
# MATHLIB = NONE
EXTRA_CXXFLAGS = -Wno-sign-compare
include ../kaldi.mk
BINFILES = fstdeterminizestar \
fstrmsymbols fstisstochastic fstminimizeencoded fstmakecontextfst \
fstmakecontextsyms fstaddsubsequentialloop fstaddselfloops \
fstrmepslocal fstcomposecontext fsttablecompose fstrand \
fstdeterminizelog fstphicompose fstcopy \
fstpushspecial fsts-to-transcripts fsts-project fsts-union \
fsts-concat make-grammar-fst
OBJFILES =
TESTFILES =
# actually, this library is currently empty. Everything is a header.
LIBFILE =
ADDLIBS = ../decoder/kaldi-decoder.a ../fstext/kaldi-fstext.a \
../util/kaldi-util.a ../matrix/kaldi-matrix.a ../base/kaldi-base.a
include ../makefiles/default_rules.mk
@@ -0,0 +1,93 @@
// fstbin/fstaddselfloops.cc
// 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.
#include "base/kaldi-common.h"
#include "fst/fstlib.h"
#include "fstext/determinize-star.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
#include "util/parse-options.h"
#include "util/simple-io-funcs.h"
/* some test examples:
pushd ~/tmpdir
( echo 3; echo 4) > in.list
( echo 5; echo 6) > out.list
( echo "0 0 0 0"; echo "0 0" ) | fstcompile | fstaddselfloops in.list out.list | fstprint
( echo "0 1 0 1"; echo " 0 2 1 0"; echo "1 0"; echo "2 0"; ) | fstcompile | fstaddselfloops in.list out.list | fstprint
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Adds self-loops to states of an FST to propagate disambiguation symbols through it\n"
"They are added on each final state and each state with non-epsilon output symbols\n"
"on at least one arc out of the state. Useful in conjunction with predeterminize\n"
"\n"
"Usage: fstaddselfloops in-disambig-list out-disambig-list [in.fst [out.fst] ]\n"
"E.g: fstaddselfloops in.list out.list < in.fst > withloops.fst\n"
"in.list and out.list are lists of integers, one per line, of the\n"
"same length.\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() < 2 || po.NumArgs() > 4) {
po.PrintUsage();
exit(1);
}
std::string disambig_in_rxfilename = po.GetArg(1),
disambig_out_rxfilename = po.GetArg(2),
fst_in_filename = po.GetOptArg(3),
fst_out_filename = po.GetOptArg(4);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
std::vector<int32> disambig_in;
if (!ReadIntegerVectorSimple(disambig_in_rxfilename, &disambig_in))
KALDI_ERR << "fstaddselfloops: Could not read disambiguation symbols from "
<< kaldi::PrintableRxfilename(disambig_in_rxfilename);
std::vector<int32> disambig_out;
if (!ReadIntegerVectorSimple(disambig_out_rxfilename, &disambig_out))
KALDI_ERR << "fstaddselfloops: Could not read disambiguation symbols from "
<< kaldi::PrintableRxfilename(disambig_out_rxfilename);
if (disambig_in.size() != disambig_out.size())
KALDI_ERR << "fstaddselfloops: mismatch in size of disambiguation symbols";
AddSelfLoops(fst, disambig_in, disambig_out);
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
return 0;
}
@@ -0,0 +1,85 @@
// fstbin/fstaddsubsequentialloop.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/context-fst.h"
#include "fstext/kaldi-fst-io.h"
/* some test examples:
( echo "0 0 0 0"; echo "0 0" ) | fstcompile | fstaddsubsequentialloop 1 | fstprint
( echo "0 1 0 0"; echo " 0 2 0 0"; echo "1 0"; echo "2 0"; ) | fstcompile | fstaddsubsequentialloop 1 | fstprint
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Minimizes FST after encoding [this algorithm applicable to all FSTs in tropical semiring]\n"
"\n"
"Usage: fstaddsubsequentialloop subseq_sym [in.fst [out.fst] ]\n"
"E.g.: fstaddsubsequentialloop 52 < LG.fst > LG_sub.fst\n";
float delta = kDelta;
ParseOptions po(usage);
po.Register("delta", &delta,
"Delta likelihood used for quantization of weights");
po.Read(argc, argv);
if (po.NumArgs() < 1 || po.NumArgs() > 3) {
po.PrintUsage();
exit(1);
}
int32 subseq_sym;
if (!ConvertStringToInteger(po.GetArg(1), &subseq_sym))
KALDI_ERR << "Invalid subsequential symbol "<<po.GetArg(1);
std::string fst_in_filename = po.GetOptArg(2);
std::string fst_out_filename = po.GetOptArg(3);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
int32 h = HighestNumberedInputSymbol(*fst);
if (subseq_sym <= h) {
std::cerr << "fstaddsubsequentialloop.cc: subseq symbol does not seem right, "<<subseq_sym<<" <= "<<h<<'\n';
}
AddSubsequentialLoop(subseq_sym, fst);
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,183 @@
// fstbin/fstcomposecontext.cc
// 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.
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/context-fst.h"
#include "fstext/grammar-context-fst.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
/*
A couple of test examples:
pushd ~/tmpdir
# (1) with no disambig syms.
( echo "0 1 1 1"; echo "1 2 2 2"; echo "2 3 3 3"; echo "3 0" ) | fstcompile | fstcomposecontext ilabels.sym > tmp.fst
( echo "<eps> 0"; echo "a 1"; echo "b 2"; echo "c 3" ) > phones.txt
fstmakecontextsyms phones.txt ilabels.sym > context.txt
fstprint --isymbols=context.txt --osymbols=phones.txt tmp.fst
# and the result is:
WARNING (fstcomposecontext[5.4]:main():fstcomposecontext.cc:130) Disambiguation symbols list is empty; this likely indicates an error in data preparation.
0 1 <eps> a
1 2 <eps>/a/b b
2 3 a/b/c c
3 4 b/c/<eps> <eps>
4
# (2) with disambig syms:
( echo 4; echo 5) > disambig.list
( echo "<eps> 0"; echo "a 1"; echo "b 2"; echo "c 3"; echo "#0 4"; echo "#1 5") > phones.txt
( echo "0 1 1 1"; echo "1 2 2 2"; echo " 2 3 4 4"; echo "3 4 3 3"; echo "4 5 5 5"; echo "5 0" ) | fstcompile > in.fst
fstcomposecontext --read-disambig-syms=disambig.list ilabels.sym in.fst tmp.fst
fstmakecontextsyms phones.txt ilabels.sym > context.txt
cp phones.txt phones_disambig.txt; ( echo "#0 4"; echo "#1 5" ) >> phones_disambig.txt
fstprint --isymbols=context.txt --osymbols=phones_disambig.txt tmp.fst
0 1 #-1 a
1 2 <eps>/a/b b
2 3 #0 #0
3 4 a/b/c c
4 5 #1 #1
5 6 b/c/<eps> <eps>
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
/*
# fstcomposecontext composes efficiently with a context fst
# that it generates. Without --disambig-syms specified, it
# assumes that all input symbols of in.fst are phones.
# It adds the subsequential symbol itself (it does not
# appear in the output so doesn't need to be specified by the user).
# the disambig.list is a list of disambiguation symbols on the LHS
# of in.fst. The symbols on the LHS of out.fst are indexes into
# the ilabels.list file, which is a kaldi-format file containing a
# vector<vector<int32> >, which specifies what the labels mean in
# terms of windows of symbols.
fstcomposecontext ilabels.sym [ in.fst [ out.fst ] ]
--disambig-syms=disambig.list
--context-size=3
--central-position=1
--binary=false
*/
const char *usage =
"Composes on the left with a dynamically created context FST\n"
"\n"
"Usage: fstcomposecontext <ilabels-output-file> [<in.fst> [<out.fst>] ]\n"
"E.g: fstcomposecontext ilabels.sym < LG.fst > CLG.fst\n";
ParseOptions po(usage);
bool binary = true;
std::string disambig_rxfilename,
disambig_wxfilename;
int32 context_width = 3, central_position = 1;
int32 nonterm_phones_offset = -1;
po.Register("binary", &binary,
"If true, output ilabels-output-file in binary format");
po.Register("read-disambig-syms", &disambig_rxfilename,
"List of disambiguation symbols on input of in.fst");
po.Register("write-disambig-syms", &disambig_wxfilename,
"List of disambiguation symbols on input of out.fst");
po.Register("context-size", &context_width, "Size of phone context window");
po.Register("central-position", &central_position,
"Designated central position in context window");
po.Register("nonterm-phones-offset", &nonterm_phones_offset,
"The integer id of #nonterm_bos in your phones.txt, if present "
"(only relevant for grammar-FST construction, see "
"doc/grammar.dox");
po.Read(argc, argv);
if (po.NumArgs() < 1 || po.NumArgs() > 3) {
po.PrintUsage();
exit(1);
}
std::string ilabels_out_filename = po.GetArg(1),
fst_in_filename = po.GetOptArg(2),
fst_out_filename = po.GetOptArg(3);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
if ( (disambig_wxfilename != "") && (disambig_rxfilename == "") )
KALDI_ERR << "fstcomposecontext: cannot specify --write-disambig-syms if "
"not specifying --read-disambig-syms\n";
std::vector<int32> disambig_in;
if (disambig_rxfilename != "")
if (!ReadIntegerVectorSimple(disambig_rxfilename, &disambig_in))
KALDI_ERR << "fstcomposecontext: Could not read disambiguation symbols from "
<< PrintableRxfilename(disambig_rxfilename);
if (disambig_in.empty()) {
KALDI_WARN << "Disambiguation symbols list is empty; this likely "
<< "indicates an error in data preparation.";
}
std::vector<std::vector<int32> > ilabels;
VectorFst<StdArc> composed_fst;
// Work gets done here (see context-fst.h)
if (nonterm_phones_offset < 0) {
// The normal case.
ComposeContext(disambig_in, context_width, central_position,
fst, &composed_fst, &ilabels);
} else {
// The grammar-FST case. See ../doc/grammar.dox for an intro.
if (context_width != 2 || central_position != 1) {
KALDI_ERR << "Grammar-fst graph creation only supports models with left-"
"biphone context. (--nonterm-phones-offset option was supplied).";
}
ComposeContextLeftBiphone(nonterm_phones_offset, disambig_in,
*fst, &composed_fst, &ilabels);
}
WriteILabelInfo(Output(ilabels_out_filename, binary).Stream(),
binary, ilabels);
if (disambig_wxfilename != "") {
std::vector<int32> disambig_out;
for (size_t i = 0; i < ilabels.size(); i++)
if (ilabels[i].size() == 1 && ilabels[i][0] <= 0)
disambig_out.push_back(static_cast<int32>(i));
if (!WriteIntegerVectorSimple(disambig_wxfilename, disambig_out)) {
std::cerr << "fstcomposecontext: Could not write disambiguation symbols to "
<< PrintableWxfilename(disambig_wxfilename) << '\n';
return 1;
}
}
WriteFstKaldi(composed_fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
+78
View File
@@ -0,0 +1,78 @@
// fstbin/fstcopy.cc
// 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.
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/table-matcher.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
/*
Test:
the command below should print out something similar to the given
input. and if you remove ,t from the output side it should print something
binary.
cat <<EOF | fstcopy ark,t:- ark,t:-
foo
0 1 9 9
1 0.0
EOF
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Copy tables/archives of FSTs, indexed by a string (e.g. utterance-id)\n"
"\n"
"Usage: fstcopy <fst-rspecifier> <fst-wspecifier>\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() != 2) {
po.PrintUsage();
exit(1);
}
std::string fst_rspecifier = po.GetArg(1),
fst_wspecifier = po.GetArg(2);
SequentialTableReader<VectorFstHolder> fst_reader(fst_rspecifier);
TableWriter<VectorFstHolder> fst_writer(fst_wspecifier);
int32 n_done = 0;
for (; !fst_reader.Done(); fst_reader.Next(), n_done++)
fst_writer.Write(fst_reader.Key(), fst_reader.Value());
KALDI_LOG << "Copied " << n_done << " FSTs.";
return (n_done != 0 ? 0 : 1);
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,65 @@
// fstbin/fstdeterminizelog.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Determinizes in the log semiring\n"
"\n"
"Usage: fstdeterminizelog [in.fst [out.fst] ]\n"
"\n"
"See also fstdeterminizestar\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() > 2) {
po.PrintUsage();
exit(1);
}
std::string fst_in_filename = po.GetOptArg(1),
fst_out_filename = po.GetOptArg(2);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
DeterminizeInLog(fst);
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,119 @@
// fstbin/fstdeterminizestar.cc
// 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.
#include "base/kaldi-common.h"
#include "fst/fstlib.h"
#include "fstext/determinize-star.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
#include "util/parse-options.h"
#if !defined(_MSC_VER) && !defined(__APPLE__)
#include <signal.h> // Comment this line and the call to signal below if
// it causes compilation problems. It is only to enable a debugging procedure
// when determinization does not terminate. We are disabling this code if
// compiling on Windows because signal.h is not available there, and on
// MacOS due to a problem with <signal.h> in the initial release of Sierra.
#endif
/* some test examples:
( echo "0 0 0 0"; echo "0 0" ) | fstcompile | fstdeterminizestar | fstprint
( echo "0 0 1 0"; echo "0 0" ) | fstcompile | fstdeterminizestar | fstprint
( echo "0 0 1 0"; echo "0 1 1 0"; echo "0 0" ) | fstcompile | fstdeterminizestar | fstprint
# this last one fails [correctly]:
( echo "0 0 0 1"; echo "0 0" ) | fstcompile | fstdeterminizestar | fstprint
cd ~/tmpdir
while true; do
fstrand > 1.fst
fstpredeterminize out.lst 1.fst | fstdeterminizestar | fstrmsymbols out.lst > 2.fst
fstequivalent --random=true 1.fst 2.fst || echo "Test failed"
echo -n "."
done
Test of debugging [with non-determinizable input]:
( echo " 0 0 1 0 1.0"; echo "0 1 1 0"; echo "1 1 1 0 0"; echo "0 2 2 0"; echo "2"; echo "1" ) | fstcompile | fstdeterminizestar
kill -SIGUSR1 [the process-id of fstdeterminizestar]
# prints out a bunch of debugging output showing the mess it got itself into.
*/
bool debug_location = false;
void signal_handler(int) {
debug_location = true;
}
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Removes epsilons and determinizes in one step\n"
"\n"
"Usage: fstdeterminizestar [in.fst [out.fst] ]\n"
"\n"
"See also: fstdeterminizelog, lattice-determinize\n";
float delta = kDelta;
int max_states = -1;
bool use_log = false;
ParseOptions po(usage);
po.Register("use-log", &use_log, "Determinize in log semiring.");
po.Register("delta", &delta, "Delta value used to determine equivalence of weights.");
po.Register("max-states", &max_states, "Maximum number of states in determinized FST before it will abort.");
po.Read(argc, argv);
if (po.NumArgs() > 2) {
po.PrintUsage();
exit(1);
}
std::string fst_in_str = po.GetOptArg(1),
fst_out_str = po.GetOptArg(2);
// This enables us to get traceback info from determinization that is
// not seeming to terminate.
#if !defined(_MSC_VER) && !defined(__APPLE__)
signal(SIGUSR1, signal_handler);
#endif
// Normal case: just files.
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_str);
ArcSort(fst, ILabelCompare<StdArc>()); // improves speed.
if (use_log) {
DeterminizeStarInLog(fst, delta, &debug_location, max_states);
} else {
VectorFst<StdArc> det_fst;
DeterminizeStar(*fst, &det_fst, delta, &debug_location, max_states);
*fst = det_fst; // will do shallow copy and then det_fst goes
// out of scope anyway.
}
WriteFstKaldi(*fst, fst_out_str);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,85 @@
// fstbin/fstisstochastic.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
// e.g. of test:
// echo " 0 0" | fstcompile | fstisstochastic
// should return 0 and print "0 0" [meaning, min and
// max weight are one = exp(0)]
// echo " 0 1" | fstcompile | fstisstochastic
// should return 1, not stochastic, and print 1 1
// (echo "0 0 0 0 0.693147 "; echo "0 1 0 0 0.693147 "; echo "1 0" ) | fstcompile | fstisstochastic
// should return 0, stochastic; it prints "0 -1.78e-07" for me
// (echo "0 0 0 0 0.693147 "; echo "0 1 0 0 0.693147 "; echo "1 0" ) | fstcompile | fstisstochastic --test-in-log=false
// should return 1, not stochastic in tropical; it prints "0 0.693147" for me
// (echo "0 0 0 0 0 "; echo "0 1 0 0 0 "; echo "1 0" ) | fstcompile | fstisstochastic --test-in-log=false
// should return 0, stochastic in tropical; it prints "0 0" for me
// (echo "0 0 0 0 0.693147 "; echo "0 1 0 0 0.693147 "; echo "1 0" ) | fstcompile | fstisstochastic --test-in-log=false --delta=1
// returns 0 even though not stochastic because we gave it an absurdly large delta.
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Checks whether an FST is stochastic and exits with success if so.\n"
"Prints out maximum error (in log units).\n"
"\n"
"Usage: fstisstochastic [ in.fst ]\n";
float delta = 0.01;
bool test_in_log = true;
ParseOptions po(usage);
po.Register("delta", &delta, "Maximum error to accept.");
po.Register("test-in-log", &test_in_log, "Test stochasticity in log semiring.");
po.Read(argc, argv);
if (po.NumArgs() > 1) {
po.PrintUsage();
exit(1);
}
std::string fst_in_filename = po.GetOptArg(1);
Fst<StdArc> *fst = ReadFstKaldiGeneric(fst_in_filename);
bool ans;
StdArc::Weight min, max;
if (test_in_log) ans = IsStochasticFstInLog(*fst, delta, &min, &max);
else ans = IsStochasticFst(*fst, delta, &min, &max);
std::cout << min.Value() << " " << max.Value() << '\n';
delete fst;
if (ans) return 0; // success;
else return 1;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,143 @@
// fstbin/fstmakecontextfst.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/context-fst.h"
#include "fstext/kaldi-fst-io.h"
/* for example of testing setup, see fstmakecontextsymbols.cc */
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Constructs a context FST with a specified context-width and context-position.\n"
"Outputs the context FST, and a file in Kaldi format that describes what the\n"
"input labels mean. Note: this is very inefficient if there are a lot of phones,\n"
"better to use fstcomposecontext instead\n"
"\n"
"Usage: fstmakecontextfst <phones-symbol-table> <subsequential-symbol> <ilabels-output-file> [<out-fst>]\n"
"E.g.: fstmakecontextfst phones.txt 42 ilabels.sym > C.fst\n";
bool binary = true; // binary output to ilabels_output_file.
std::string disambig_rxfilename, disambig_wxfilename;
int32 context_width = 3, central_position = 1;
ParseOptions po(usage);
po.Register("read-disambig-syms", &disambig_rxfilename,
"List of disambiguation symbols to read");
po.Register("write-disambig-syms", &disambig_wxfilename,
"List of disambiguation symbols to write");
po.Register("context-size", &context_width, "Size of phonetic context window");
po.Register("central-position", &central_position,
"Designated central position in context window");
po.Register("binary", &binary,
"Write ilabels output file in binary Kaldi format");
po.Read(argc, argv);
if (po.NumArgs() < 3 || po.NumArgs() > 4) {
po.PrintUsage();
exit(1);
}
std::string phones_symtab_filename = po.GetArg(1);
int32 subseq_sym;
if (!ConvertStringToInteger(po.GetArg(2), &subseq_sym))
KALDI_ERR << "Invalid subsequential symbol " << po.GetArg(2);
std::string ilabels_out_filename = po.GetArg(3);
std::string fst_out_filename = po.GetOptArg(4);
std::vector<kaldi::int32> phone_syms;
{
fst::SymbolTable *phones_symtab = NULL;
{ // read phone symbol table.
std::ifstream is(phones_symtab_filename.c_str());
phones_symtab = fst::SymbolTable::ReadText(is, phones_symtab_filename);
if (!phones_symtab) KALDI_ERR << "Could not read phones symbol-table file "<<phones_symtab_filename;
}
GetSymbols(*phones_symtab,
false, // don't include eps,
&phone_syms);
delete phones_symtab;
}
if ( (disambig_wxfilename != "") && (disambig_rxfilename == "") )
KALDI_ERR << "fstmakecontextfst: cannot specify --write-disambig-syms if "
"not specifying --read-disambig-syms\n";
std::vector<int32> disambig_in;
if (disambig_rxfilename != "") {
if (!ReadIntegerVectorSimple(disambig_rxfilename, &disambig_in))
KALDI_ERR << "fstcomposecontext: Could not read disambiguation symbols from "
<< PrintableRxfilename(disambig_rxfilename);
}
if (std::binary_search(phone_syms.begin(), phone_syms.end(), subseq_sym)
|| std::binary_search(disambig_in.begin(), disambig_in.end(), subseq_sym))
KALDI_ERR << "Invalid subsequential symbol " << subseq_sym
<< ", already a phone or disambiguation symbol.";
// 'loop_fst' will be an acceptor FST with single (initial and final) state, with
// a loop for each phone and disambiguation symbol.
StdVectorFst loop_fst;
loop_fst.AddState(); // Add state zero.
loop_fst.SetStart(0);
loop_fst.SetFinal(0, TropicalWeight::One());
for (size_t i = 0; i < phone_syms.size(); i++) {
int32 sym = phone_syms[i];
loop_fst.AddArc(0, StdArc(sym, sym, TropicalWeight::One(), 0));
}
std::vector<std::vector<int32> > ilabels;
VectorFst<StdArc> context_fst;
ComposeContext(disambig_in, context_width, central_position,
&loop_fst, &context_fst, &ilabels, true);
WriteFstKaldi(context_fst, fst_out_filename);
WriteILabelInfo(Output(ilabels_out_filename, binary).Stream(),
binary, ilabels);
if (disambig_wxfilename != "") {
std::vector<int32> disambig_out;
for (size_t i = 0; i < ilabels.size(); i++)
if (ilabels[i].size() == 1 && ilabels[i][0] <= 0)
disambig_out.push_back(static_cast<int32>(i));
if (!WriteIntegerVectorSimple(disambig_wxfilename, disambig_out))
KALDI_ERR << "fstcomposecontext: Could not write disambiguation symbols to "
<< PrintableWxfilename(disambig_wxfilename);
}
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,122 @@
// fstbin/fstmakecontextsyms.cc
// 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.
#include "tree/context-dep.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/context-fst.h"
/*
Test for this and makecontextfst:
mkdir -p ~/tmpdir
pushd ~/tmpdir
(echo "<eps> 0"; echo "a 1"; echo "b 2"; echo "#0 3"; echo "#1 4"; echo "#$ 5" ) > phones.txt
( echo 3; echo 4 ) > disambig.list
fstmakecontextfst --read-disambig-syms=disambig.list <(grep -v '#' phones.txt) 5 ilabels.int > C.fst
fstmakecontextsyms phones.txt ilabels.int > context_syms.txt
fstprint --isymbols=context_syms.txt --osymbols=phones.txt C.fst > C.txt
fstrandgen C.fst | fstprint --isymbols=context_syms.txt --osymbols=phones.txt
Example output:
fstrandgen C.fst | fstprint --isymbols=context_syms.txt --osymbols=phones.txt
0 1 #-1 b
1 2 <eps>/b/<eps> #$
2 3 #1 #1
3 4 #0 #0
4 5 #0 #0
5 6 #0 #0
6 7 #0 #0
7 8 #0 #0
8 9 #1 #1
9
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
typedef fst::StdArc::Label Label;
const char *usage = "Create input symbols for CLG\n"
"Usage: fstmakecontextsyms phones-symtab ilabels_input_file [output-symtab.txt]\n"
"E.g.: fstmakecontextsyms phones.txt ilabels.sym > context_symbols.txt\n";
ParseOptions po(usage);
std::string disambig_list_file = "",
phone_separator = "/",
initial_disambig = "#-1";
po.Register("phone-separator", &phone_separator,
"Separator for phones in phone-in-context symbols.");
po.Register("initial-disambig", &initial_disambig,
"Name for special disambiguation symbol that occurs at start "
"of context-dependent phone sequences");
po.Read(argc, argv);
if (po.NumArgs() < 2 || po.NumArgs() > 3) {
po.PrintUsage();
exit(1);
}
std::string phones_symtab_filename = po.GetArg(1),
ilabel_info_filename = po.GetArg(2),
clg_symtab_filename = po.GetOptArg(3);
std::vector<std::vector<kaldi::int32> > ilabel_info;
{
bool binary;
Input ki(ilabel_info_filename, &binary);
ReadILabelInfo(ki.Stream(),
binary, &ilabel_info);
}
fst::SymbolTable *phones_symtab = NULL;
{ // read phone symbol table.
std::ifstream is(phones_symtab_filename.c_str());
phones_symtab = fst::SymbolTable::ReadText(is, phones_symtab_filename);
if (!phones_symtab) KALDI_ERR << "Could not read phones symbol-table file "<<phones_symtab_filename;
}
fst::SymbolTable *clg_symtab =
CreateILabelInfoSymbolTable(ilabel_info,
*phones_symtab,
phone_separator,
initial_disambig);
if (clg_symtab_filename == "") {
if (!clg_symtab->WriteText(std::cout))
KALDI_ERR << "Cannot write symbol table to standard output.";
} else {
if (!clg_symtab->WriteText(clg_symtab_filename))
KALDI_ERR << "Cannot open symbol table file "<<clg_symtab_filename<<" for writing.";
}
delete clg_symtab;
delete phones_symtab;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,73 @@
// fstbin/fstminimizeencoded.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fst/fstlib.h"
#include "fstext/determinize-star.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
/* some test examples:
( echo "0 0 0 0"; echo "0 0" ) | fstcompile | fstminimizeencoded | fstprint
( echo "0 1 0 0"; echo " 0 2 0 0"; echo "1 0"; echo "2 0"; ) | fstcompile | fstminimizeencoded | fstprint
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Minimizes FST after encoding [similar to fstminimize, but no weight-pushing]\n"
"\n"
"Usage: fstminimizeencoded [in.fst [out.fst] ]\n";
float delta = kDelta;
ParseOptions po(usage);
po.Register("delta", &delta, "Delta likelihood used for quantization of weights");
po.Read(argc, argv);
if (po.NumArgs() > 2) {
po.PrintUsage();
exit(1);
}
std::string fst_in_filename = po.GetOptArg(1),
fst_out_filename = po.GetOptArg(2);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
MinimizeEncoded(fst, delta);
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
return 0;
}
@@ -0,0 +1,183 @@
// fstbin/fstphicompose.cc
// 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.
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/table-matcher.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
/*
The following commands represent a basic test of this program.
cat <<EOF | fstcompile > a.fst
0 1 10 10
0 1 11 11
1
EOF
cat <<EOF | fstcompile > g.fst
0 1 10 10 2.0
0 2 100 100 6.6
2 1 10 10 0.0
2 1 11 11 1.0
1
EOF
fstcompose a.fst g.fst | fstprint
# gives, as expected:
# 0 1 10 10 2
# 1
fstphicompose 100 a.fst g.fst | fstprint
# gives, again correctly:
#0 1 10 10 2
#0 1 11 11 7.5999999
#1
Next, test that it's working as desired for final-probs,
i.e. it takes the backoff arc when looking for a final-prob,
only if no final-prob present at current state.
cat <<EOF | fstcompile > a.fst
0 1 10 10
0 1 11 11
1
EOF
cat <<EOF | fstcompile > g.fst
0 1 10 10 2.0
0 3 11 11 2.0
1 2 100 110 6.6
3 10.0
3 2 100 110 0.0
2
EOF
fstphicompose 100 a.fst g.fst | fstprint
# output is:
#0 1 10 10 2
#0 2 11 11 2
#1 6.5999999
#2 10
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
/*
fstphicompose does composition, but treats the second FST
specially (basically, like a backoff LM); whenever the
composition algorithm fails to find a match for a label
in the second FST, if it sees a phi transition it will
take it instead, and look for a match at the destination.
phi is the label on the input side of the backoff arc of
the LM (the label on the output side doesn't matter).
Also modifies the second fst so that it treats final-probs
"correctly", i.e. takes the failure transition when looking
for a final-prob. This would not work if there were
epsilons.
*/
const char *usage =
"Composition, where the right FST has \"failure\" (phi) transitions\n"
"that are only taken where there was no match of a \"real\" label\n"
"You supply the label corresponding to phi.\n"
"\n"
"Usage: fstphicompose phi-label (fst1-rxfilename|fst1-rspecifier) "
"(fst2-rxfilename|fst2-rspecifier) [(out-rxfilename|out-rspecifier)]\n"
"E.g.: fstphicompose 54 a.fst b.fst c.fst\n"
"or: fstphicompose 11 ark:a.fsts G.fst ark:b.fsts\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() < 3 || po.NumArgs() > 4) {
po.PrintUsage();
exit(1);
}
std::string
phi_str = po.GetArg(1),
fst1_in_str = po.GetArg(2),
fst2_in_str = po.GetArg(3),
fst_out_str = po.GetOptArg(4);
bool is_table_1 =
(ClassifyRspecifier(fst1_in_str, NULL, NULL) != kNoRspecifier),
is_table_2 =
(ClassifyRspecifier(fst2_in_str, NULL, NULL) != kNoRspecifier),
is_table_out =
(ClassifyWspecifier(fst_out_str, NULL, NULL, NULL) != kNoWspecifier);
int32 phi_label;
if (!ConvertStringToInteger(phi_str, &phi_label)
|| phi_label <= 0)
KALDI_ERR << "Invalid first argument (phi label), expect positive integer.";
if (is_table_out != (is_table_1 || is_table_2))
KALDI_ERR << "Incompatible combination of archives and files";
if (!is_table_1 && !is_table_2) { // Only dealing with files...
VectorFst<StdArc> *fst1 = ReadFstKaldi(fst1_in_str);
VectorFst<StdArc> *fst2 = ReadFstKaldi(fst2_in_str);
PropagateFinal(phi_label, fst2); // makes it work correctly
// w.r.t. final-probs.
VectorFst<StdArc> composed_fst;
PhiCompose(*fst1, *fst2, phi_label, &composed_fst);
delete fst1;
delete fst2;
WriteFstKaldi(composed_fst, fst_out_str);
return 0;
} else if (is_table_1 && !is_table_2) {
VectorFst<StdArc> *fst2 = ReadFstKaldi(fst2_in_str);
PropagateFinal(phi_label, fst2); // makes it work correctly
// w.r.t. final-probs.
SequentialTableReader<VectorFstHolder> fst1_reader(fst1_in_str);
TableWriter<VectorFstHolder> fst_writer(fst_out_str);
int32 n_done = 0;
for (; !fst1_reader.Done(); fst1_reader.Next(), n_done++) {
VectorFst<StdArc> fst1(fst1_reader.Value());
VectorFst<StdArc> fst_out;
PhiCompose(fst1, *fst2, phi_label, &fst_out);
fst_writer.Write(fst1_reader.Key(), fst_out);
}
KALDI_LOG << "Composed " << n_done << " FSTs.";
return (n_done != 0 ? 0 : 1);
} else {
KALDI_ERR << "The combination of tables/non-tables that you "
<< "supplied is not currently supported. Either implement this, "
<< "ask the maintainers to implement it, or call this program "
<< "differently.";
}
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,72 @@
// fstbin/fstpushspecial.cc
// Copyright 2012 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 "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fst/fstlib.h"
#include "fstext/fstext-utils.h"
#include "fstext/push-special.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Pushes weights in an FST such that all the states\n"
"in the FST have arcs and final-probs with weights that\n"
"sum to the same amount (viewed as being in the log semiring).\n"
"Thus, the \"extra weight\" is distributed throughout the FST.\n"
"Tolerance parameter --delta controls how exact this is, and the\n"
"speed.\n"
"\n"
"Usage: fstpushspecial [options] [in.fst [out.fst] ]\n";
BaseFloat delta = kDelta;
ParseOptions po(usage);
po.Register("delta", &delta, "Delta cost: after pushing, all states will "
"have a total weight that differs from the average by no more "
"than this.");
po.Read(argc, argv);
if (po.NumArgs() > 2) {
po.PrintUsage();
exit(1);
}
std::string fst_in_filename = po.GetOptArg(1),
fst_out_filename = po.GetOptArg(2);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
PushSpecial(fst, delta);
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
+67
View File
@@ -0,0 +1,67 @@
// fstbin/fstrand.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fstext/rand-fst.h"
#include "time.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace fst;
using kaldi::int32;
const char *usage =
"Generate random FST\n"
"\n"
"Usage: fstrand [out.fst]\n";
srand(time(NULL));
RandFstOptions opts;
kaldi::ParseOptions po(usage);
po.Register("allow-empty", &opts.allow_empty,
"If true, we may generate an empty FST.");
po.Read(argc, argv);
if (po.NumArgs() > 1) {
po.PrintUsage();
exit(1);
}
std::string fst_out_filename = po.GetOptArg(1);
VectorFst <StdArc> *rand_fst = RandFst<StdArc>(opts);
WriteFstKaldi(*rand_fst, fst_out_filename);
delete rand_fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,101 @@
// fstbin/fstrmepslocal.cc
// 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.
#include "base/kaldi-common.h"
#include "util/kaldi-io.h"
#include "util/parse-options.h"
#include "util/text-utils.h"
#include "fst/fstlib.h"
#include "fstext/determinize-star.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
/*
A test example:
( echo "0 1 1 0"; echo "1 2 0 2"; echo "2 0"; ) | fstcompile | fstrmepslocal | fstprint
# prints:
# 0 1 1 2
# 1
( echo "0 1 0 0"; echo "0 0"; echo "1 0" ) | fstcompile | fstrmepslocal | fstprint
# 0
( echo "0 1 0 0"; echo "0 0"; echo "1 0" ) | fstcompile | fstrmepslocal | fstprint
( echo "0 1 0 0"; echo "0 0"; echo "1 0" ) | fstcompile | fstrmepslocal --use-log=true | fstprint
# 0 -0.693147182
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Removes some (but not all) epsilons in an algorithm that will always reduce the number of\n"
"arcs+states. Option to preserves equivalence in tropical or log semiring, and\n"
"if in tropical, stochasticit in either log or tropical.\n"
"\n"
"Usage: fstrmepslocal [in.fst [out.fst] ]\n";
ParseOptions po(usage);
bool use_log = false;
bool stochastic_in_log = true;
po.Register("use-log", &use_log,
"Preserve equivalence in log semiring [false->tropical]\n");
po.Register("stochastic-in-log", &stochastic_in_log,
"Preserve stochasticity in log semiring [false->tropical]\n");
po.Read(argc, argv);
if (po.NumArgs() > 2) {
po.PrintUsage();
exit(1);
}
std::string fst_in_filename = po.GetOptArg(1),
fst_out_filename = po.GetOptArg(2);
VectorFst<StdArc> *fst = ReadFstKaldi(fst_in_filename);
if (!use_log && stochastic_in_log) {
RemoveEpsLocalSpecial(fst);
} else if (use_log && !stochastic_in_log) {
std::cerr << "fstrmsymbols: invalid combination of flags\n";
return 1;
} else if (use_log) {
VectorFst<LogArc> log_fst;
Cast(*fst, &log_fst);
delete fst;
RemoveEpsLocal(&log_fst);
fst = new VectorFst<StdArc>;
Cast(log_fst, fst);
} else {
RemoveEpsLocal(fst);
}
WriteFstKaldi(*fst, fst_out_filename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,193 @@
// fstbin/fstrmsymbols.cc
// 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.
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/determinize-star.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
namespace fst {
// we can move these functions elsewhere later, if they are needed in other
// places.
template<class Arc, class I>
void RemoveArcsWithSomeInputSymbols(const std::vector<I> &symbols_in,
VectorFst<Arc> *fst) {
typedef typename Arc::StateId StateId;
kaldi::ConstIntegerSet<I> symbol_set(symbols_in);
StateId num_states = fst->NumStates();
StateId dead_state = fst->AddState();
for (StateId s = 0; s < num_states; s++) {
for (MutableArcIterator<VectorFst<Arc> > iter(fst, s);
!iter.Done(); iter.Next()) {
if (symbol_set.count(iter.Value().ilabel) != 0) {
Arc arc = iter.Value();
arc.nextstate = dead_state;
iter.SetValue(arc);
}
}
}
// Connect() will actually remove the arcs, and the dead state.
Connect(fst);
if (fst->NumStates() == 0)
KALDI_WARN << "After Connect(), fst was empty.";
}
template<class Arc, class I>
void PenalizeArcsWithSomeInputSymbols(const std::vector<I> &symbols_in,
float penalty,
VectorFst<Arc> *fst) {
typedef typename Arc::StateId StateId;
typedef typename Arc::Label Label;
typedef typename Arc::Weight Weight;
Weight penalty_weight(penalty);
kaldi::ConstIntegerSet<I> symbol_set(symbols_in);
StateId num_states = fst->NumStates();
for (StateId s = 0; s < num_states; s++) {
for (MutableArcIterator<VectorFst<Arc> > iter(fst, s);
!iter.Done(); iter.Next()) {
if (symbol_set.count(iter.Value().ilabel) != 0) {
Arc arc = iter.Value();
arc.weight = Times(arc.weight, penalty_weight);
iter.SetValue(arc);
}
}
}
}
}
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
bool apply_to_output = false;
bool remove_arcs = false;
float penalty = -std::numeric_limits<BaseFloat>::infinity();
const char *usage =
"With no options, replaces a subset of symbols with epsilon, wherever\n"
"they appear on the input side of an FST."
"With --remove-arcs=true, will remove arcs that contain these symbols\n"
"on the input\n"
"With --penalty=<float>, will add the specified penalty to the\n"
"cost of any arc that has one of the given symbols on its input side\n"
"In all cases, the option --apply-to-output=true (or for\n"
"back-compatibility, --remove-from-output=true) makes this apply\n"
"to the output side.\n"
"\n"
"Usage: fstrmsymbols [options] <in-disambig-list> [<in.fst> [<out.fst>]]\n"
"E.g: fstrmsymbols in.list < in.fst > out.fst\n"
"<in-disambig-list> is an rxfilename specifying a file containing list of integers\n"
"representing symbols, in text form, one per line.\n";
ParseOptions po(usage);
po.Register("remove-from-output", &apply_to_output, "If true, this applies to symbols "
"on the output, not the input, side. (For back compatibility; use "
"--apply-to-output insead)");
po.Register("apply-to-output", &apply_to_output, "If true, this applies to symbols "
"on the output, not the input, side.");
po.Register("remove-arcs", &remove_arcs, "If true, instead of converting the symbol "
"to <eps>, remove the arcs.");
po.Register("penalty", &penalty, "If specified, instead of converting "
"the symbol to <eps>, penalize the arc it is on by adding this "
"value to its cost.");
po.Read(argc, argv);
if (remove_arcs &&
penalty != -std::numeric_limits<BaseFloat>::infinity())
KALDI_ERR << "--remove-arc and --penalty options are mutually exclusive";
if (po.NumArgs() < 1 || po.NumArgs() > 3) {
po.PrintUsage();
exit(1);
}
std::string disambig_rxfilename = po.GetArg(1),
fst_rxfilename = po.GetOptArg(2),
fst_wxfilename = po.GetOptArg(3);
VectorFst<StdArc> *fst = CastOrConvertToVectorFst(
ReadFstKaldiGeneric(fst_rxfilename));
std::vector<int32> disambig_in;
if (!ReadIntegerVectorSimple(disambig_rxfilename, &disambig_in))
KALDI_ERR << "fstrmsymbols: Could not read disambiguation symbols from "
<< (disambig_rxfilename == "" ? "standard input" : disambig_rxfilename);
if (apply_to_output) Invert(fst);
if (remove_arcs) {
RemoveArcsWithSomeInputSymbols(disambig_in, fst);
} else if (penalty != -std::numeric_limits<BaseFloat>::infinity()) {
PenalizeArcsWithSomeInputSymbols(disambig_in, penalty, fst);
} else {
RemoveSomeInputSymbols(disambig_in, fst);
}
if (apply_to_output) Invert(fst);
WriteFstKaldi(*fst, fst_wxfilename);
delete fst;
return 0;
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
/* some test examples:
( echo "0 0 1 1"; echo " 0 0 3 2"; echo "0 0"; ) | fstcompile | fstrmsymbols "echo 3; echo 4|" | fstprint
# should produce:
# 0 0 1 1
# 0 0 0 2
# 0
( echo "0 0 1 1"; echo " 0 0 3 2"; echo "0 0"; ) | fstcompile | fstrmsymbols --apply-to-output=true "echo 2; echo 3|" | fstprint
# should produce:
# 0 0 1 1
# 0 0 3 0
# 0
( echo "0 0 1 1"; echo " 0 0 3 2"; echo "0 0"; ) | fstcompile | fstrmsymbols --remove-arcs=true "echo 3; echo 4|" | fstprint
# should produce:
# 0 0 1 1
# 0
( echo "0 0 1 1"; echo " 0 0 3 2"; echo "0 0"; ) | fstcompile | fstrmsymbols --penalty=2 "echo 3; echo 4; echo 5|" | fstprint
# should produce:
# 0 0 1 1
# 0 0 3 2 2
# 0
*/
@@ -0,0 +1,112 @@
// fstbin/fsts-concat.cc
// Copyright 2016 Johns Hopkins University (Authors: Jan "Yenda" Trmal)
// 2018 Soapbox Labs (Author: Karel Vesely)
// 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 "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
typedef kaldi::int32 int32;
typedef kaldi::uint64 uint64;
const char *usage =
"Reads kaldi archives with FSTs. Concatenates the fsts from all the rspecifiers.\n"
"The fsts to concatenate must have same key. The sequencing is given by the position of arguments.\n"
"\n"
"Usage: fsts-concat [options] <fsts-rspecifier1> <fsts-rspecifier2> ... <fsts-wspecifier>\n"
" e.g.: fsts-concat scp:fsts1.scp scp:fsts2.scp ... ark:fsts_out.ark\n"
"\n"
"see also: fstconcat (from the OpenFst toolkit)\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() < 3) {
po.PrintUsage();
exit(1);
}
std::string fsts_rspecifier = po.GetArg(1),
fsts_wspecifier = po.GetArg(po.NumArgs());
SequentialTableReader<VectorFstHolder> fst_reader(fsts_rspecifier);
std::vector<RandomAccessTableReader<VectorFstHolder>*> fst_readers;
TableWriter<VectorFstHolder> fst_writer(fsts_wspecifier);
for (int32 i = 2; i < po.NumArgs(); i++)
fst_readers.push_back(new RandomAccessTableReader<VectorFstHolder>(po.GetArg(i)));
const int32 num_fst_readers = fst_readers.size();
int32 n_done = 0,
n_skipped = 0;
for (; !fst_reader.Done(); fst_reader.Next()) {
std::string key = fst_reader.Key();
// Check that the key exists in all 'fst_readers'.
bool skip_key = false;
for (int32 i = 0; i < num_fst_readers; i++) {
if (!fst_readers[i]->HasKey(key)) {
KALDI_WARN << "Skipping '" << key << "'"
<< " due to missing the fst in " << (i+2) << "th <rspecifier> : "
<< "'" << po.GetArg(i+2) << "'";
skip_key = true;
}
}
if (skip_key) {
n_skipped++;
continue;
}
// Concatenate!
VectorFst<StdArc> fst_out = fst_readers.back()->Value(key);
// Loop from (last-1) to first, as 'prepending' the fsts is faster,
// see: http://www.openfst.org/twiki/bin/view/FST/ConcatDoc
for (int32 i = num_fst_readers-2; i >= 0; i--) {
fst::Concat(fst_readers[i]->Value(key), &fst_out);
}
// Finally, prepend the fst from the 'Sequential' reader.
fst::Concat(fst_reader.Value(), &fst_out);
// Write the output.
fst_writer.Write(key, fst_out);
n_done++;
}
// Cleanup.
for (int32 i = 0; i < num_fst_readers; i++)
delete fst_readers[i];
fst_readers.clear();
KALDI_LOG << "Produced " << n_done << " FSTs by concatenating " << po.NumArgs()-1
<< " streams " << "(" << n_skipped << " keys skipped).";
return (n_done != 0 ? 0 : 1);
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,82 @@
// fstbin/fsts-project.cc
// Copyright 2016 Johns Hopkins University (Authors: Jan "Yenda" Trmal)
// 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 "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
typedef kaldi::int32 int32;
typedef kaldi::uint64 uint64;
const char *usage =
"Reads kaldi archive of FSTs; for each element, performs the project\n"
"operation either on input (default) or on the output (if the option\n"
"--project-output is true).\n"
"\n"
"Usage: fsts-project [options] <fsts-rspecifier> <fsts-wspecifier>\n"
" e.g.: fsts-project ark:train.fsts ark,t:train.fsts\n"
"\n"
"see also: fstproject (from the OpenFst toolkit)\n";
ParseOptions po(usage);
bool project_output = false;
po.Register("project-output", &project_output,
"If true, project output vs input");
po.Read(argc, argv);
if (po.NumArgs() != 2) {
po.PrintUsage();
exit(1);
}
std::string fsts_rspecifier = po.GetArg(1),
fsts_wspecifier = po.GetArg(2);
SequentialTableReader<VectorFstHolder> fst_reader(fsts_rspecifier);
TableWriter<VectorFstHolder> fst_writer(fsts_wspecifier);
int32 n_done = 0;
for (; !fst_reader.Done(); fst_reader.Next()) {
std::string key = fst_reader.Key();
VectorFst<StdArc> fst(fst_reader.Value());
Project(&fst, project_output ? PROJECT_OUTPUT : PROJECT_INPUT);
fst_writer.Write(key, fst);
n_done++;
}
KALDI_LOG << "Projected " << n_done << " FSTs";
return (n_done != 0 ? 0 : 1);
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,103 @@
// fstbin/fsts-to-transcripts.cc
// Copyright 2012-2013 Johns Hopkins University (Authors: Guoguo Chen,
// 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 "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
typedef kaldi::int32 int32;
typedef kaldi::uint64 uint64;
const char *usage =
"Reads a table of FSTs; for each element, finds the best path and \n"
"prints out the output-symbol sequence (if --output-side=true), or \n"
"input-symbol sequence otherwise.\n"
"\n"
"Usage:\n"
" fsts-to-transcripts [options] <fsts-rspecifier>"
" <transcriptions-wspecifier>\n"
"e.g.:\n"
" fsts-to-transcripts ark:train.fsts ark,t:train.text\n";
ParseOptions po(usage);
bool output_side = true;
po.Register("output-side", &output_side, "If true, extract the symbols on "
"the output side of the FSTs, else the input side.");
po.Read(argc, argv);
if (po.NumArgs() != 2) {
po.PrintUsage();
exit(1);
}
std::string fst_rspecifier = po.GetArg(1),
transcript_wspecifier = po.GetArg(2);
SequentialTableReader<VectorFstHolder> fst_reader(fst_rspecifier);
Int32VectorWriter transcript_writer(transcript_wspecifier);
int32 n_done = 0, n_err = 0;
for (; !fst_reader.Done(); fst_reader.Next()) {
std::string key = fst_reader.Key();
const VectorFst<StdArc> &fst = fst_reader.Value();
VectorFst<StdArc> shortest_path;
ShortestPath(fst, &shortest_path); // the OpenFst algorithm ShortestPath.
if (shortest_path.NumStates() == 0) {
KALDI_WARN << "Input FST (after shortest path) was empty. Producing "
<< "no output for key " << key;
n_err++;
continue;
}
std::vector<int32> transcript;
bool ans;
if (output_side) ans = fst::GetLinearSymbolSequence<StdArc, int32>(
shortest_path, NULL, &transcript, NULL);
else
ans = fst::GetLinearSymbolSequence<StdArc, int32>(
shortest_path, &transcript, NULL, NULL);
if (!ans) {
KALDI_ERR << "GetLinearSymbolSequence returned false (code error);";
}
transcript_writer.Write(key, transcript);
n_done++;
}
KALDI_LOG << "Converted " << n_done << " FSTs, " << n_err << " with errors";
return (n_done != 0 ? 0 : 1);
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,100 @@
// fstbin/fsts-union.cc
// Copyright 2016 Johns Hopkins University (Authors: Jan "Yenda" Trmal)
// 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 "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
typedef kaldi::int32 int32;
typedef kaldi::uint64 uint64;
const char *usage =
"Reads a kaldi archive of FSTs. Performs the FST operation union on\n"
"all fsts sharing the same key. Assumes the archive is sorted by key.\n"
"\n"
"Usage: fsts-union [options] <fsts-rspecifier> <fsts-wspecifier>\n"
" e.g.: fsts-union ark:keywords_tmp.fsts ark,t:keywords.fsts\n"
"\n"
"see also: fstunion (from the OpenFst toolkit)\n";
ParseOptions po(usage);
po.Read(argc, argv);
if (po.NumArgs() != 2) {
po.PrintUsage();
exit(1);
}
std::string fsts_rspecifier = po.GetArg(1),
fsts_wspecifier = po.GetArg(2);
SequentialTableReader<VectorFstHolder> fst_reader(fsts_rspecifier);
TableWriter<VectorFstHolder> fst_writer(fsts_wspecifier);
int32 n_out_done = 0,
n_in_done = 0;
std::string res_key = "";
VectorFst<StdArc> res_fst;
for (; !fst_reader.Done(); fst_reader.Next()) {
std::string key = fst_reader.Key();
VectorFst<StdArc> fst(fst_reader.Value());
n_in_done++;
if (key == res_key) {
fst::Union(&res_fst, fst);
} else {
if (res_key != "") {
VectorFst<StdArc> out_fst;
fst::Determinize(res_fst, &out_fst);
fst::Minimize(&out_fst);
fst::RmEpsilon(&out_fst);
fst_writer.Write(res_key, out_fst);
n_out_done++;
}
res_fst = fst;
res_key = key;
}
}
if (res_key != "") {
VectorFst<StdArc> out_fst;
fst::Determinize(res_fst, &out_fst);
fst::Minimize(&out_fst);
fst::RmEpsilon(&out_fst);
fst_writer.Write(res_key, out_fst);
n_out_done++;
}
KALDI_LOG << "Applied fst union on " << n_in_done
<< " FSTs, produced " << n_out_done << " FSTs";
return (n_out_done != 0 ? 0 : 1);
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,202 @@
// fstbin/fsttablecompose.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 "base/kaldi-common.h"
//#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/table-matcher.h"
#include "fstext/fstext-utils.h"
#include "fstext/kaldi-fst-io.h"
#include "util/parse-options.h"
/*
cd ~/tmpdir
while true; do
fstrand | fstarcsort --sort_type=olabel > 1.fst; fstrand | fstarcsort > 2.fst
fstcompose 1.fst 2.fst > 3a.fst
fsttablecompose 1.fst 2.fst > 3b.fst
fstequivalent --random=true 3a.fst 3b.fst || echo "Test failed"
echo -n "."
done
*/
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
/*
fsttablecompose should always give equivalent results to compose,
but it is more efficient for certain kinds of inputs.
In particular, it is useful when, say, the left FST has states
that typically either have epsilon olabels, or
one transition out for each of the possible symbols (as the
olabel). The same with the input symbols of the right-hand FST
is possible.
*/
const char *usage =
"Composition algorithm [between two FSTs of standard type, in tropical\n"
"semiring] that is more efficient for certain cases-- in particular,\n"
"where one of the FSTs (the left one, if --match-side=left) has large\n"
"out-degree\n"
"\n"
"Usage: fsttablecompose (fst1-rxfilename|fst1-rspecifier) "
"(fst2-rxfilename|fst2-rspecifier) [(out-rxfilename|out-rspecifier)]\n";
ParseOptions po(usage);
TableComposeOptions opts;
std::string match_side = "left";
std::string compose_filter = "sequence";
po.Register("connect", &opts.connect, "If true, trim FST before output.");
po.Register("match-side", &match_side, "Side of composition to do table "
"match, one of: \"left\" or \"right\".");
po.Register("compose-filter", &compose_filter, "Composition filter to use, "
"one of: \"alt_sequence\", \"auto\", \"match\", \"sequence\"");
po.Read(argc, argv);
if (match_side == "left") {
opts.table_match_type = MATCH_OUTPUT;
} else if (match_side == "right") {
opts.table_match_type = MATCH_INPUT;
} else {
KALDI_ERR << "Invalid match-side option: " << match_side;
}
if (compose_filter == "alt_sequence") {
opts.filter_type = ALT_SEQUENCE_FILTER;
} else if (compose_filter == "auto") {
opts.filter_type = AUTO_FILTER;
} else if (compose_filter == "match") {
opts.filter_type = MATCH_FILTER;
} else if (compose_filter == "sequence") {
opts.filter_type = SEQUENCE_FILTER;
} else {
KALDI_ERR << "Invalid compose-filter option: " << compose_filter;
}
if (po.NumArgs() < 2 || po.NumArgs() > 3) {
po.PrintUsage();
exit(1);
}
std::string fst1_in_str = po.GetArg(1),
fst2_in_str = po.GetArg(2),
fst_out_str = po.GetOptArg(3);
//// Note: the "table" in is_table_1 and similar variables has nothing
//// to do with the "table" in "fsttablecompose"; is_table_1 relates to
//// whether we are dealing with a single FST or a whole set of FSTs.
//bool is_table_1 =
// (ClassifyRspecifier(fst1_in_str, NULL, NULL) != kNoRspecifier),
// is_table_2 =
// (ClassifyRspecifier(fst2_in_str, NULL, NULL) != kNoRspecifier),
// is_table_out =
// (ClassifyWspecifier(fst_out_str, NULL, NULL, NULL) != kNoWspecifier);
//if (is_table_out != (is_table_1 || is_table_2))
// KALDI_ERR << "Incompatible combination of archives and files";
//
//if (!is_table_1 && !is_table_2) { // Only dealing with files...
VectorFst<StdArc> *fst1 = ReadFstKaldi(fst1_in_str);
VectorFst<StdArc> *fst2 = ReadFstKaldi(fst2_in_str);
// Checks if <fst1> is olabel sorted and <fst2> is ilabel sorted.
if (fst1->Properties(fst::kOLabelSorted, true) == 0) {
KALDI_WARN << "The first FST is not olabel sorted.";
}
if (fst2->Properties(fst::kILabelSorted, true) == 0) {
KALDI_WARN << "The second FST is not ilabel sorted.";
}
VectorFst<StdArc> composed_fst;
TableCompose(*fst1, *fst2, &composed_fst, opts);
delete fst1;
delete fst2;
WriteFstKaldi(composed_fst, fst_out_str);
return 0;
//} else if (!is_table_1 && is_table_2
// && opts.table_match_type == MATCH_OUTPUT) {
// // second arg is an archive, and match-side=left (default).
// TableComposeCache<Fst<StdArc> > cache(opts);
// VectorFst<StdArc> *fst1 = ReadFstKaldi(fst1_in_str);
// SequentialTableReader<VectorFstHolder> fst2_reader(fst2_in_str);
// TableWriter<VectorFstHolder> fst_writer(fst_out_str);
// int32 n_done = 0;
// // Checks if <fst1> is olabel sorted.
// if (fst1->Properties(fst::kOLabelSorted, true) == 0) {
// KALDI_WARN << "The first FST is not olabel sorted.";
// }
// for (; !fst2_reader.Done(); fst2_reader.Next(), n_done++) {
// VectorFst<StdArc> fst2(fst2_reader.Value());
// VectorFst<StdArc> fst_out;
// TableCompose(*fst1, fst2, &fst_out, &cache);
// fst_writer.Write(fst2_reader.Key(), fst_out);
// }
// KALDI_LOG << "Composed " << n_done << " FSTs.";
// return (n_done != 0 ? 0 : 1);
//} else if (is_table_1 && is_table_2) {
// SequentialTableReader<VectorFstHolder> fst1_reader(fst1_in_str);
// RandomAccessTableReader<VectorFstHolder> fst2_reader(fst2_in_str);
// TableWriter<VectorFstHolder> fst_writer(fst_out_str);
// int32 n_done = 0, n_err = 0;
// for (; !fst1_reader.Done(); fst1_reader.Next()) {
// std::string key = fst1_reader.Key();
// if (!fst2_reader.HasKey(key)) {
// KALDI_WARN << "No such key " << key << " in second table.";
// n_err++;
// } else {
// const VectorFst<StdArc> &fst1(fst1_reader.Value()),
// &fst2(fst2_reader.Value(key));
// VectorFst<StdArc> result;
// TableCompose(fst1, fst2, &result, opts);
// if (result.NumStates() == 0) {
// KALDI_WARN << "Empty output for key " << key;
// n_err++;
// } else {
// fst_writer.Write(key, result);
// n_done++;
// }
// }
// }
// KALDI_LOG << "Successfully composed " << n_done << " FSTs, errors or "
// << "empty output on " << n_err;
//} else {
// KALDI_ERR << "The combination of tables/non-tables and match-type that you "
// << "supplied is not currently supported. Either implement this, "
// << "ask the maintainers to implement it, or call this program "
// << "differently.";
//}
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}
@@ -0,0 +1,167 @@
// fstbin/make-grammar-fst.cc
// Copyright 2018 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 "base/kaldi-common.h"
#include "util/common-utils.h"
#include "fst/fstlib.h"
#include "fstext/table-matcher.h"
#include "fstext/kaldi-fst-io.h"
#include "decoder/grammar-fst.h"
template<typename FST>
void MakeGrammarFst(kaldi::ParseOptions po,
int32 nonterm_phones_offset,
bool write_as_grammar){
using namespace kaldi;
using namespace fst;
using kaldi::int32;
std::string fst_out_str = po.GetArg(po.NumArgs());
std::string top_fst_str = po.GetArg(1);
ConstFst<StdArc> *top_tmp_fst = ConstFst<StdArc>::Read(top_fst_str);
std::shared_ptr<FST> top_fst(new FST(*top_tmp_fst));
std::vector<std::pair<int32, std::shared_ptr<FST> > > pairs;
int32 num_pairs = (po.NumArgs() - 2) / 2;
for (int32 i = 1; i <= num_pairs; i++) {
int32 nonterminal;
std::string nonterm_str = po.GetArg(2*i);
if (!ConvertStringToInteger(nonterm_str, &nonterminal) ||
nonterminal <= 0)
KALDI_ERR << "Expected positive integer as nonterminal, got: "
<< nonterm_str;
std::string fst_str = po.GetArg(2*i + 1);
ConstFst<StdArc> *tmp_fst = ConstFst<StdArc>::Read(fst_str);
std::shared_ptr<FST> this_fst(new FST(*tmp_fst));
pairs.push_back(std::pair<int32, std::shared_ptr<FST> >(
nonterminal, this_fst));
};
GrammarFstTpl<FST> *grammar_fst = new GrammarFstTpl<FST>(nonterm_phones_offset,
top_fst,
pairs);
if (write_as_grammar) {
bool binary = true; // GrammarFst does not support non-binary write.
WriteKaldiObject(*grammar_fst, fst_out_str, binary);
} else {
VectorFst<StdArc> vfst;
CopyToVectorFst<FST>(grammar_fst, &vfst);
ConstFst<StdArc> cfst(vfst);
// We don't have a wrapper in kaldi-fst-io.h for writing type
// ConstFst<StdArc>, so do it manually.
bool binary = true, write_binary_header = false; // suppress the ^@B
Output ko(fst_out_str, binary, write_binary_header);
FstWriteOptions wopts(kaldi::PrintableWxfilename(fst_out_str));
cfst.Write(ko.Stream(), wopts);
}
KALDI_LOG << "Created grammar FST and wrote it to "
<< fst_out_str;
}
int main(int argc, char *argv[]) {
try {
using namespace kaldi;
using namespace fst;
using kaldi::int32;
const char *usage =
"Construct GrammarFst and write it to disk (or convert it to ConstFst\n"
"and write that to disk instead). Mostly intended for demonstration\n"
"and testing purposes (since it may be more convenient to construct\n"
"GrammarFst from code). See kaldi-asr.org/doc/grammar.html\n"
"Can also be used to prepares FSTs for this use, by calling\n"
"PrepareForGrammarFst(), which does things like adding final-probs and\n"
"making small structural tweaks to the FST\n"
"\n"
"Usage (1): make-grammar-fst [options] <top-level-fst> <symbol1> <fst1> \\\n"
" [<symbol2> <fst2> ...]] <fst-out>\n"
"\n"
"<symbol1>, <symbol2> are the integer ids of the corresponding\n"
" user-defined nonterminal symbols (e.g. #nonterm:contact_list) in the\n"
" phones.txt file.\n"
"e.g.: make-grammar-fst --nonterm-phones-offset=317 HCLG.fst \\\n"
" 320 HCLG1.fst HCLG_grammar.fst\n"
"\n"
"Usage (2): make-grammar-fst <fst-in> <fst-out>\n"
" Prepare individual FST for compilation into GrammarFst.\n"
" E.g. make-grammar-fst HCLG.fst HCLGmod.fst. The outputs of this\n"
" will then become the arguments <top-level-fst>, <fst1>, ... for usage\n"
" pattern (1).\n"
"\n"
"The --nonterm-phones-offset option is required for both usage patterns.\n";
ParseOptions po(usage);
int32 nonterm_phones_offset = -1;
bool write_as_grammar = true;
bool make_mutable = false;
po.Register("nonterm-phones-offset", &nonterm_phones_offset,
"Integer id of #nonterm_bos in phones.txt");
po.Register("write-as-grammar", &write_as_grammar, "If true, "
"write as GrammarFst object; if false, convert to "
"ConstFst<StdArc> (readable by standard decoders) "
"and write that.");
po.Register("make-mutable", &make_mutable, "If true, "
"Make a GrammarFst using StdVectorFst as the "
"underlying FST instance type."
"Use const ConstFst<StdArc> otherwise.");
po.Read(argc, argv);
if (po.NumArgs() < 2 || po.NumArgs() % 2 != 0) {
po.PrintUsage();
exit(1);
}
if (nonterm_phones_offset < 0)
KALDI_ERR << "The --nonterm-phones-offset option must be supplied "
"and positive.";
if (po.NumArgs() == 2) {
// this usage pattern calls PrepareForGrammarFst().
VectorFst<StdArc> *fst = ReadFstKaldi(po.GetArg(1));
PrepareForGrammarFst(nonterm_phones_offset, fst);
// This will write it as VectorFst; to avoid it having to be converted to
// ConstFst when read again by make-grammar-fst, you may want to pipe
// through fstconvert --fst_type=const.
WriteFstKaldi(*fst, po.GetArg(2));
exit(0);
}
if (make_mutable) {
MakeGrammarFst<StdVectorFst>(po, nonterm_phones_offset, write_as_grammar);
} else {
MakeGrammarFst<const ConstFst<StdArc> >(po, nonterm_phones_offset, write_as_grammar);
}
} catch(const std::exception &e) {
std::cerr << e.what();
return -1;
}
}