make-grammar-fst.cc
Go to the documentation of this file.
1 // fstbin/make-grammar-fst.cc
2 
3 // Copyright 2018 Johns Hopkins University (author: Daniel Povey)
4 
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
19 
20 
21 #include "base/kaldi-common.h"
22 #include "util/common-utils.h"
23 #include "fst/fstlib.h"
24 #include "fstext/table-matcher.h"
25 #include "fstext/kaldi-fst-io.h"
26 #include "decoder/grammar-fst.h"
27 
28 namespace fst {
29 
30 // Reads an FST from disk using Kaldi I/O mechanisms, and if it is not of type
31 // ConstFst, copies it to that stype.
32 ConstFst<StdArc>* ReadAsConstFst(std::string rxfilename) {
33  // the following call will throw if there is an error.
34  Fst<StdArc> *fst = ReadFstKaldiGeneric(rxfilename);
35  ConstFst<StdArc> *const_fst = dynamic_cast<ConstFst<StdArc>* >(fst);
36  if (!const_fst) {
37  const_fst = new ConstFst<StdArc>(*fst);
38  delete fst;
39  }
40  return const_fst;
41 }
42 
43 }
44 
45 int main(int argc, char *argv[]) {
46  try {
47  using namespace kaldi;
48  using namespace fst;
49  using kaldi::int32;
50 
51  const char *usage =
52  "Construct GrammarFst and write it to disk (or convert it to ConstFst\n"
53  "and write that to disk instead). Mostly intended for demonstration\n"
54  "and testing purposes (since it may be more convenient to construct\n"
55  "GrammarFst from code). See kaldi-asr.org/doc/grammar.html\n"
56  "Can also be used to prepares FSTs for this use, by calling\n"
57  "PrepareForGrammarFst(), which does things like adding final-probs and\n"
58  "making small structural tweaks to the FST\n"
59  "\n"
60  "Usage (1): make-grammar-fst [options] <top-level-fst> <symbol1> <fst1> \\\n"
61  " [<symbol2> <fst2> ...]] <fst-out>\n"
62  "\n"
63  "<symbol1>, <symbol2> are the integer ids of the corresponding\n"
64  " user-defined nonterminal symbols (e.g. #nonterm:contact_list) in the\n"
65  " phones.txt file.\n"
66  "e.g.: make-grammar-fst --nonterm-phones-offset=317 HCLG.fst \\\n"
67  " 320 HCLG1.fst HCLG_grammar.fst\n"
68  "\n"
69  "Usage (2): make-grammar-fst <fst-in> <fst-out>\n"
70  " Prepare individual FST for compilation into GrammarFst.\n"
71  " E.g. make-grammar-fst HCLG.fst HCLGmod.fst. The outputs of this\n"
72  " will then become the arguments <top-level-fst>, <fst1>, ... for usage\n"
73  " pattern (1).\n"
74  "\n"
75  "The --nonterm-phones-offset option is required for both usage patterns.\n";
76 
77 
78  ParseOptions po(usage);
79 
80 
81  int32 nonterm_phones_offset = -1;
82  bool write_as_grammar = true;
83 
84  po.Register("nonterm-phones-offset", &nonterm_phones_offset,
85  "Integer id of #nonterm_bos in phones.txt");
86  po.Register("write-as-grammar", &write_as_grammar, "If true, "
87  "write as GrammarFst object; if false, convert to "
88  "ConstFst<StdArc> (readable by standard decoders) "
89  "and write that.");
90 
91  po.Read(argc, argv);
92 
93 
94  if (po.NumArgs() < 2 || po.NumArgs() % 2 != 0) {
95  po.PrintUsage();
96  exit(1);
97  }
98 
99  if (nonterm_phones_offset < 0)
100  KALDI_ERR << "The --nonterm-phones-offset option must be supplied "
101  "and positive.";
102 
103  if (po.NumArgs() == 2) {
104  // this usage pattern calls PrepareForGrammarFst().
105  VectorFst<StdArc> *fst = ReadFstKaldi(po.GetArg(1));
106  PrepareForGrammarFst(nonterm_phones_offset, fst);
107  // This will write it as VectorFst; to avoid it having to be converted to
108  // ConstFst when read again by make-grammar-fst, you may want to pipe
109  // through fstconvert --fst_type=const.
110  WriteFstKaldi(*fst, po.GetArg(2));
111  exit(0);
112  }
113 
114  std::string top_fst_str = po.GetArg(1),
115  fst_out_str = po.GetArg(po.NumArgs());
116 
117  std::shared_ptr<const ConstFst<StdArc> > top_fst(
118  ReadAsConstFst(top_fst_str));
119  std::vector<std::pair<int32, std::shared_ptr<const ConstFst<StdArc> > > > pairs;
120 
121  int32 num_pairs = (po.NumArgs() - 2) / 2;
122  for (int32 i = 1; i <= num_pairs; i++) {
123  int32 nonterminal;
124  std::string nonterm_str = po.GetArg(2*i);
125  if (!ConvertStringToInteger(nonterm_str, &nonterminal) ||
126  nonterminal <= 0)
127  KALDI_ERR << "Expected positive integer as nonterminal, got: "
128  << nonterm_str;
129  std::string fst_str = po.GetArg(2*i + 1);
130  std::shared_ptr<const ConstFst<StdArc> > this_fst(ReadAsConstFst(fst_str));
131  pairs.push_back(std::pair<int32, std::shared_ptr<const ConstFst<StdArc> > >(
132  nonterminal, this_fst));
133  }
134 
135  GrammarFst *grammar_fst = new GrammarFst(nonterm_phones_offset,
136  top_fst,
137  pairs);
138 
139  if (write_as_grammar) {
140  bool binary = true; // GrammarFst does not support non-binary write.
141  WriteKaldiObject(*grammar_fst, fst_out_str, binary);
142  delete grammar_fst;
143  } else {
144  VectorFst<StdArc> vfst;
145  CopyToVectorFst(grammar_fst, &vfst);
146  delete grammar_fst;
147  ConstFst<StdArc> cfst(vfst);
148  // We don't have a wrapper in kaldi-fst-io.h for writing type
149  // ConstFst<StdArc>, so do it manually.
150  bool binary = true, write_binary_header = false; // suppress the ^@B
151  Output ko(fst_out_str, binary, write_binary_header);
152  FstWriteOptions wopts(kaldi::PrintableWxfilename(fst_out_str));
153  cfst.Write(ko.Stream(), wopts);
154  }
155 
156  KALDI_LOG << "Created grammar FST and wrote it to "
157  << fst_out_str;
158  } catch(const std::exception &e) {
159  std::cerr << e.what();
160  return -1;
161  }
162 }
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
bool ConvertStringToInteger(const std::string &str, Int *out)
Converts a string into an integer via strtoll and returns false if there was any kind of problem (i...
Definition: text-utils.h:118
Fst< StdArc > * ReadFstKaldiGeneric(std::string rxfilename, bool throw_on_err)
Definition: kaldi-fst-io.cc:45
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
void PrintUsage(bool print_command_line=false)
Prints the usage documentation [provided in the constructor].
int main(int argc, char *argv[])
kaldi::int32 int32
void PrepareForGrammarFst(int32 nonterm_phones_offset, VectorFst< StdArc > *fst)
This function prepares &#39;ifst&#39; for use in GrammarFst: it ensures that it has the expected properties...
Definition: grammar-fst.cc:982
void Register(const std::string &name, bool *ptr, const std::string &doc)
The class ParseOptions is for parsing command-line options; see Parsing command-line options for more...
Definition: parse-options.h:36
std::ostream & Stream()
Definition: kaldi-io.cc:701
ConstFst< StdArc > * ReadAsConstFst(std::string rxfilename)
int Read(int argc, const char *const *argv)
Parses the command line options and fills the ParseOptions-registered variables.
#define KALDI_ERR
Definition: kaldi-error.h:147
GrammarFst is an FST that is &#39;stitched together&#39; from multiple FSTs, that can recursively incorporate...
Definition: grammar-fst.h:96
std::string GetArg(int param) const
Returns one of the positional parameters; 1-based indexing for argc/argv compatibility.
int NumArgs() const
Number of positional parameters (c.f. argc-1).
void WriteFstKaldi(std::ostream &os, bool binary, const VectorFst< Arc > &t)
void ReadFstKaldi(std::istream &is, bool binary, VectorFst< Arc > *fst)
void WriteKaldiObject(const C &c, const std::string &filename, bool binary)
Definition: kaldi-io.h:257
std::string PrintableWxfilename(const std::string &wxfilename)
PrintableWxfilename turns the wxfilename into a more human-readable form for error reporting...
Definition: kaldi-io.cc:73
void CopyToVectorFst(GrammarFst *grammar_fst, VectorFst< StdArc > *vector_fst)
This function copies a GrammarFst to a VectorFst (intended mostly for testing and comparison purposes...
Definition: grammar-fst.cc:988
#define KALDI_LOG
Definition: kaldi-error.h:153