SimpleDecoder Class Reference

Simplest possible decoder, included largely for didactic purposes and as a means to debug more highly optimized decoders. More...

#include <simple-decoder.h>

Collaboration diagram for SimpleDecoder:

Classes

class  Token
 

Public Types

typedef fst::StdArc StdArc
 
typedef StdArc::Weight StdWeight
 
typedef StdArc::Label Label
 
typedef StdArc::StateId StateId
 

Public Member Functions

 SimpleDecoder (const fst::Fst< fst::StdArc > &fst, BaseFloat beam)
 
 ~SimpleDecoder ()
 
bool Decode (DecodableInterface *decodable)
 Decode this utterance. More...
 
bool ReachedFinal () const
 
bool GetBestPath (Lattice *fst_out, bool use_final_probs=true) const
 
BaseFloat FinalRelativeCost () const
 *** The next functions are from the "new interface". *** More...
 
void InitDecoding ()
 InitDecoding initializes the decoding, and should only be used if you intend to call AdvanceDecoding(). More...
 
void AdvanceDecoding (DecodableInterface *decodable, int32 max_num_frames=-1)
 This will decode until there are no more frames ready in the decodable object, but if max_num_frames is >= 0 it will decode no more than that many frames. More...
 
int32 NumFramesDecoded () const
 Returns the number of frames already decoded. More...
 

Private Member Functions

void ProcessEmitting (DecodableInterface *decodable)
 
void ProcessNonemitting ()
 
 KALDI_DISALLOW_COPY_AND_ASSIGN (SimpleDecoder)
 

Static Private Member Functions

static void ClearToks (unordered_map< StateId, Token *> &toks)
 
static void PruneToks (BaseFloat beam, unordered_map< StateId, Token *> *toks)
 

Private Attributes

unordered_map< StateId, Token * > cur_toks_
 
unordered_map< StateId, Token * > prev_toks_
 
const fst::Fst< fst::StdArc > & fst_
 
BaseFloat beam_
 
int32 num_frames_decoded_
 

Detailed Description

Simplest possible decoder, included largely for didactic purposes and as a means to debug more highly optimized decoders.

See SimpleDecoder: the simplest possible decoder for more information.

Definition at line 37 of file simple-decoder.h.

Member Typedef Documentation

◆ Label

typedef StdArc::Label Label

Definition at line 41 of file simple-decoder.h.

◆ StateId

typedef StdArc::StateId StateId

Definition at line 42 of file simple-decoder.h.

◆ StdArc

Definition at line 39 of file simple-decoder.h.

◆ StdWeight

typedef StdArc::Weight StdWeight

Definition at line 40 of file simple-decoder.h.

Constructor & Destructor Documentation

◆ SimpleDecoder()

SimpleDecoder ( const fst::Fst< fst::StdArc > &  fst,
BaseFloat  beam 
)
inline

Definition at line 44 of file simple-decoder.h.

References SimpleDecoder::AdvanceDecoding(), SimpleDecoder::Decode(), SimpleDecoder::FinalRelativeCost(), SimpleDecoder::GetBestPath(), SimpleDecoder::InitDecoding(), SimpleDecoder::ReachedFinal(), and SimpleDecoder::~SimpleDecoder().

44 : fst_(fst), beam_(beam) { }
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
const fst::Fst< fst::StdArc > & fst_

◆ ~SimpleDecoder()

Definition at line 27 of file simple-decoder.cc.

References SimpleDecoder::ClearToks(), SimpleDecoder::cur_toks_, and SimpleDecoder::prev_toks_.

Referenced by SimpleDecoder::SimpleDecoder().

27  {
30 }
unordered_map< StateId, Token * > cur_toks_
unordered_map< StateId, Token * > prev_toks_
static void ClearToks(unordered_map< StateId, Token *> &toks)

Member Function Documentation

◆ AdvanceDecoding()

void AdvanceDecoding ( DecodableInterface decodable,
int32  max_num_frames = -1 
)

This will decode until there are no more frames ready in the decodable object, but if max_num_frames is >= 0 it will decode no more than that many frames.

If it returns false, then no tokens are alive, which is a kind of error state.

Definition at line 52 of file simple-decoder.cc.

References SimpleDecoder::beam_, SimpleDecoder::ClearToks(), SimpleDecoder::cur_toks_, KALDI_ASSERT, SimpleDecoder::num_frames_decoded_, DecodableInterface::NumFramesReady(), SimpleDecoder::prev_toks_, SimpleDecoder::ProcessEmitting(), SimpleDecoder::ProcessNonemitting(), and SimpleDecoder::PruneToks().

Referenced by SimpleDecoder::Decode(), and SimpleDecoder::SimpleDecoder().

53  {
55  "You must call InitDecoding() before AdvanceDecoding()");
56  int32 num_frames_ready = decodable->NumFramesReady();
57  // num_frames_ready must be >= num_frames_decoded, or else
58  // the number of frames ready must have decreased (which doesn't
59  // make sense) or the decodable object changed between calls
60  // (which isn't allowed).
61  KALDI_ASSERT(num_frames_ready >= num_frames_decoded_);
62  int32 target_frames_decoded = num_frames_ready;
63  if (max_num_frames >= 0)
64  target_frames_decoded = std::min(target_frames_decoded,
65  num_frames_decoded_ + max_num_frames);
66  while (num_frames_decoded_ < target_frames_decoded) {
67  // note: ProcessEmitting() increments num_frames_decoded_
69  cur_toks_.swap(prev_toks_);
70  ProcessEmitting(decodable);
73  }
74 }
void ProcessEmitting(DecodableInterface *decodable)
unordered_map< StateId, Token * > cur_toks_
unordered_map< StateId, Token * > prev_toks_
static void ClearToks(unordered_map< StateId, Token *> &toks)
kaldi::int32 int32
static void PruneToks(BaseFloat beam, unordered_map< StateId, Token *> *toks)
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ClearToks()

void ClearToks ( unordered_map< StateId, Token *> &  toks)
staticprivate

Definition at line 258 of file simple-decoder.cc.

References SimpleDecoder::Token::TokenDelete().

Referenced by SimpleDecoder::AdvanceDecoding(), SimpleDecoder::InitDecoding(), and SimpleDecoder::~SimpleDecoder().

258  {
259  for (unordered_map<StateId, Token*>::iterator iter = toks.begin();
260  iter != toks.end(); ++iter) {
261  Token::TokenDelete(iter->second);
262  }
263  toks.clear();
264 }
static void TokenDelete(Token *tok)

◆ Decode()

bool Decode ( DecodableInterface decodable)

Decode this utterance.

Returns true if any tokens reached the end of the file (regardless of whether they are in a final state); query ReachedFinal() after Decode() to see whether we reached a final state.

Definition at line 33 of file simple-decoder.cc.

References SimpleDecoder::AdvanceDecoding(), SimpleDecoder::cur_toks_, and SimpleDecoder::InitDecoding().

Referenced by main(), and SimpleDecoder::SimpleDecoder().

33  {
34  InitDecoding();
35  AdvanceDecoding(decodable);
36  return (!cur_toks_.empty());
37 }
unordered_map< StateId, Token * > cur_toks_
void AdvanceDecoding(DecodableInterface *decodable, int32 max_num_frames=-1)
This will decode until there are no more frames ready in the decodable object, but if max_num_frames ...
void InitDecoding()
InitDecoding initializes the decoding, and should only be used if you intend to call AdvanceDecoding(...

◆ FinalRelativeCost()

BaseFloat FinalRelativeCost ( ) const

*** The next functions are from the "new interface". ***

FinalRelativeCost() serves the same function as ReachedFinal(), but gives more information. It returns the difference between the best (final-cost plus cost) of any token on the final frame, and the best cost of any token on the final frame. If it is infinity it means no final-states were present on the final frame. It will usually be nonnegative.

Definition at line 87 of file simple-decoder.cc.

References SimpleDecoder::cur_toks_, SimpleDecoder::fst_, and KALDI_WARN.

Referenced by SimpleDecoder::SimpleDecoder().

87  {
88  // as a special case, if there are no active tokens at all (e.g. some kind of
89  // pruning failure), return infinity.
90  double infinity = std::numeric_limits<double>::infinity();
91  if (cur_toks_.empty())
92  return infinity;
93  double best_cost = infinity,
94  best_cost_with_final = infinity;
95  for (unordered_map<StateId, Token*>::const_iterator iter = cur_toks_.begin();
96  iter != cur_toks_.end();
97  ++iter) {
98  // Note: Plus is taking the minimum cost, since we're in the tropical
99  // semiring.
100  best_cost = std::min(best_cost, iter->second->cost_);
101  best_cost_with_final = std::min(best_cost_with_final,
102  iter->second->cost_ +
103  fst_.Final(iter->first).Value());
104  }
105  BaseFloat extra_cost = best_cost_with_final - best_cost;
106  if (extra_cost != extra_cost) { // NaN. This shouldn't happen; it indicates some
107  // kind of error, most likely.
108  KALDI_WARN << "Found NaN (likely search failure in decoding)";
109  return infinity;
110  }
111  // Note: extra_cost will be infinity if no states were final.
112  return extra_cost;
113 }
unordered_map< StateId, Token * > cur_toks_
float BaseFloat
Definition: kaldi-types.h:29
const fst::Fst< fst::StdArc > & fst_
#define KALDI_WARN
Definition: kaldi-error.h:150

◆ GetBestPath()

bool GetBestPath ( Lattice fst_out,
bool  use_final_probs = true 
) const

Definition at line 117 of file simple-decoder.cc.

References SimpleDecoder::Token::arc_, SimpleDecoder::Token::cost_, SimpleDecoder::cur_toks_, SimpleDecoder::fst_, rnnlm::i, KALDI_ASSERT, LatticeWeightTpl< BaseFloat >::One(), SimpleDecoder::Token::prev_, SimpleDecoder::ReachedFinal(), and fst::RemoveEpsLocal().

Referenced by main(), and SimpleDecoder::SimpleDecoder().

117  {
118  fst_out->DeleteStates();
119  Token *best_tok = NULL;
120  bool is_final = ReachedFinal();
121  if (!is_final) {
122  for (unordered_map<StateId, Token*>::const_iterator iter = cur_toks_.begin();
123  iter != cur_toks_.end();
124  ++iter)
125  if (best_tok == NULL || *best_tok < *(iter->second) )
126  best_tok = iter->second;
127  } else {
128  double infinity =std::numeric_limits<double>::infinity(),
129  best_cost = infinity;
130  for (unordered_map<StateId, Token*>::const_iterator iter = cur_toks_.begin();
131  iter != cur_toks_.end();
132  ++iter) {
133  double this_cost = iter->second->cost_ + fst_.Final(iter->first).Value();
134  if (this_cost != infinity && this_cost < best_cost) {
135  best_cost = this_cost;
136  best_tok = iter->second;
137  }
138  }
139  }
140  if (best_tok == NULL) return false; // No output.
141 
142  std::vector<LatticeArc> arcs_reverse; // arcs in reverse order.
143  for (Token *tok = best_tok; tok != NULL; tok = tok->prev_)
144  arcs_reverse.push_back(tok->arc_);
145  KALDI_ASSERT(arcs_reverse.back().nextstate == fst_.Start());
146  arcs_reverse.pop_back(); // that was a "fake" token... gives no info.
147 
148  StateId cur_state = fst_out->AddState();
149  fst_out->SetStart(cur_state);
150  for (ssize_t i = static_cast<ssize_t>(arcs_reverse.size())-1; i >= 0; i--) {
151  LatticeArc arc = arcs_reverse[i];
152  arc.nextstate = fst_out->AddState();
153  fst_out->AddArc(cur_state, arc);
154  cur_state = arc.nextstate;
155  }
156  if (is_final && use_final_probs)
157  fst_out->SetFinal(cur_state,
158  LatticeWeight(fst_.Final(best_tok->arc_.nextstate).Value(),
159  0.0));
160  else
161  fst_out->SetFinal(cur_state, LatticeWeight::One());
162  fst::RemoveEpsLocal(fst_out);
163  return true;
164 }
fst::ArcTpl< LatticeWeight > LatticeArc
Definition: kaldi-lattice.h:40
unordered_map< StateId, Token * > cur_toks_
StdArc::StateId StateId
static const LatticeWeightTpl One()
void RemoveEpsLocal(MutableFst< Arc > *fst)
RemoveEpsLocal remove some (but not necessarily all) epsilons in an FST, using an algorithm that is g...
bool ReachedFinal() const
fst::LatticeWeightTpl< BaseFloat > LatticeWeight
Definition: kaldi-lattice.h:32
const fst::Fst< fst::StdArc > & fst_
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ InitDecoding()

void InitDecoding ( )

InitDecoding initializes the decoding, and should only be used if you intend to call AdvanceDecoding().

If you call Decode(), you don't need to call this. You can call InitDecoding if you have already decoded an utterance and want to start with a new utterance.

Definition at line 39 of file simple-decoder.cc.

References SimpleDecoder::ClearToks(), SimpleDecoder::cur_toks_, SimpleDecoder::fst_, KALDI_ASSERT, SimpleDecoder::num_frames_decoded_, SimpleDecoder::prev_toks_, and SimpleDecoder::ProcessNonemitting().

Referenced by SimpleDecoder::Decode(), and SimpleDecoder::SimpleDecoder().

39  {
40  // clean up from last time:
43  // initialize decoding:
44  StateId start_state = fst_.Start();
45  KALDI_ASSERT(start_state != fst::kNoStateId);
46  StdArc dummy_arc(0, 0, StdWeight::One(), start_state);
47  cur_toks_[start_state] = new Token(dummy_arc, 0.0, NULL);
50 }
unordered_map< StateId, Token * > cur_toks_
StdArc::StateId StateId
unordered_map< StateId, Token * > prev_toks_
static void ClearToks(unordered_map< StateId, Token *> &toks)
const fst::Fst< fst::StdArc > & fst_
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ KALDI_DISALLOW_COPY_AND_ASSIGN()

KALDI_DISALLOW_COPY_AND_ASSIGN ( SimpleDecoder  )
private

◆ NumFramesDecoded()

int32 NumFramesDecoded ( ) const
inline

Returns the number of frames already decoded.

Definition at line 89 of file simple-decoder.h.

References SimpleDecoder::num_frames_decoded_.

89 { return num_frames_decoded_; }

◆ ProcessEmitting()

void ProcessEmitting ( DecodableInterface decodable)
private

Definition at line 167 of file simple-decoder.cc.

References SimpleDecoder::Token::arc_, SimpleDecoder::beam_, SimpleDecoder::Token::cost_, SimpleDecoder::cur_toks_, SimpleDecoder::fst_, KALDI_ASSERT, DecodableInterface::LogLikelihood(), SimpleDecoder::num_frames_decoded_, SimpleDecoder::prev_toks_, and SimpleDecoder::Token::TokenDelete().

Referenced by SimpleDecoder::AdvanceDecoding(), and SimpleDecoder::Token::TokenDelete().

167  {
168  int32 frame = num_frames_decoded_;
169  // Processes emitting arcs for one frame. Propagates from
170  // prev_toks_ to cur_toks_.
171  double cutoff = std::numeric_limits<BaseFloat>::infinity();
172  for (unordered_map<StateId, Token*>::iterator iter = prev_toks_.begin();
173  iter != prev_toks_.end();
174  ++iter) {
175  StateId state = iter->first;
176  Token *tok = iter->second;
177  KALDI_ASSERT(state == tok->arc_.nextstate);
178  for (fst::ArcIterator<fst::Fst<StdArc> > aiter(fst_, state);
179  !aiter.Done();
180  aiter.Next()) {
181  const StdArc &arc = aiter.Value();
182  if (arc.ilabel != 0) { // propagate..
183  BaseFloat acoustic_cost = -decodable->LogLikelihood(frame, arc.ilabel);
184  double total_cost = tok->cost_ + arc.weight.Value() + acoustic_cost;
185 
186  if (total_cost >= cutoff) continue;
187  if (total_cost + beam_ < cutoff)
188  cutoff = total_cost + beam_;
189  Token *new_tok = new Token(arc, acoustic_cost, tok);
190  unordered_map<StateId, Token*>::iterator find_iter
191  = cur_toks_.find(arc.nextstate);
192  if (find_iter == cur_toks_.end()) {
193  cur_toks_[arc.nextstate] = new_tok;
194  } else {
195  if ( *(find_iter->second) < *new_tok ) {
196  Token::TokenDelete(find_iter->second);
197  find_iter->second = new_tok;
198  } else {
199  Token::TokenDelete(new_tok);
200  }
201  }
202  }
203  }
204  }
206 }
unordered_map< StateId, Token * > cur_toks_
StdArc::StateId StateId
unordered_map< StateId, Token * > prev_toks_
kaldi::int32 int32
float BaseFloat
Definition: kaldi-types.h:29
const fst::Fst< fst::StdArc > & fst_
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
static void TokenDelete(Token *tok)

◆ ProcessNonemitting()

void ProcessNonemitting ( )
private

Definition at line 208 of file simple-decoder.cc.

References SimpleDecoder::Token::arc_, SimpleDecoder::beam_, SimpleDecoder::Token::cost_, SimpleDecoder::cur_toks_, SimpleDecoder::fst_, KALDI_ASSERT, and SimpleDecoder::Token::TokenDelete().

Referenced by SimpleDecoder::AdvanceDecoding(), SimpleDecoder::InitDecoding(), and SimpleDecoder::Token::TokenDelete().

208  {
209  // Processes nonemitting arcs for one frame. Propagates within
210  // cur_toks_.
211  std::vector<StateId> queue;
212  double infinity = std::numeric_limits<double>::infinity();
213  double best_cost = infinity;
214  for (unordered_map<StateId, Token*>::iterator iter = cur_toks_.begin();
215  iter != cur_toks_.end();
216  ++iter) {
217  queue.push_back(iter->first);
218  best_cost = std::min(best_cost, iter->second->cost_);
219  }
220  double cutoff = best_cost + beam_;
221 
222  while (!queue.empty()) {
223  StateId state = queue.back();
224  queue.pop_back();
225  Token *tok = cur_toks_[state];
226  KALDI_ASSERT(tok != NULL && state == tok->arc_.nextstate);
227  for (fst::ArcIterator<fst::Fst<StdArc> > aiter(fst_, state);
228  !aiter.Done();
229  aiter.Next()) {
230  const StdArc &arc = aiter.Value();
231  if (arc.ilabel == 0) { // propagate nonemitting only...
232  const BaseFloat acoustic_cost = 0.0;
233  Token *new_tok = new Token(arc, acoustic_cost, tok);
234  if (new_tok->cost_ > cutoff) {
235  Token::TokenDelete(new_tok);
236  } else {
237  unordered_map<StateId, Token*>::iterator find_iter
238  = cur_toks_.find(arc.nextstate);
239  if (find_iter == cur_toks_.end()) {
240  cur_toks_[arc.nextstate] = new_tok;
241  queue.push_back(arc.nextstate);
242  } else {
243  if ( *(find_iter->second) < *new_tok ) {
244  Token::TokenDelete(find_iter->second);
245  find_iter->second = new_tok;
246  queue.push_back(arc.nextstate);
247  } else {
248  Token::TokenDelete(new_tok);
249  }
250  }
251  }
252  }
253  }
254  }
255 }
unordered_map< StateId, Token * > cur_toks_
StdArc::StateId StateId
float BaseFloat
Definition: kaldi-types.h:29
const fst::Fst< fst::StdArc > & fst_
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
static void TokenDelete(Token *tok)

◆ PruneToks()

void PruneToks ( BaseFloat  beam,
unordered_map< StateId, Token *> *  toks 
)
staticprivate

Definition at line 267 of file simple-decoder.cc.

References rnnlm::i, KALDI_VLOG, and SimpleDecoder::Token::TokenDelete().

Referenced by SimpleDecoder::AdvanceDecoding().

267  {
268  if (toks->empty()) {
269  KALDI_VLOG(2) << "No tokens to prune.\n";
270  return;
271  }
272  double best_cost = std::numeric_limits<double>::infinity();
273  for (unordered_map<StateId, Token*>::iterator iter = toks->begin();
274  iter != toks->end(); ++iter)
275  best_cost = std::min(best_cost, iter->second->cost_);
276  std::vector<StateId> retained;
277  double cutoff = best_cost + beam;
278  for (unordered_map<StateId, Token*>::iterator iter = toks->begin();
279  iter != toks->end(); ++iter) {
280  if (iter->second->cost_ < cutoff)
281  retained.push_back(iter->first);
282  else
283  Token::TokenDelete(iter->second);
284  }
285  unordered_map<StateId, Token*> tmp;
286  for (size_t i = 0; i < retained.size(); i++) {
287  tmp[retained[i]] = (*toks)[retained[i]];
288  }
289  KALDI_VLOG(2) << "Pruned to " << (retained.size()) << " toks.\n";
290  tmp.swap(*toks);
291 }
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
static void TokenDelete(Token *tok)

◆ ReachedFinal()

bool ReachedFinal ( ) const

Definition at line 76 of file simple-decoder.cc.

References SimpleDecoder::cur_toks_, and SimpleDecoder::fst_.

Referenced by SimpleDecoder::GetBestPath(), main(), and SimpleDecoder::SimpleDecoder().

76  {
77  for (unordered_map<StateId, Token*>::const_iterator iter = cur_toks_.begin();
78  iter != cur_toks_.end();
79  ++iter) {
80  if (iter->second->cost_ != std::numeric_limits<BaseFloat>::infinity() &&
81  fst_.Final(iter->first) != StdWeight::Zero())
82  return true;
83  }
84  return false;
85 }
unordered_map< StateId, Token * > cur_toks_
const fst::Fst< fst::StdArc > & fst_

Member Data Documentation

◆ beam_

◆ cur_toks_

◆ fst_

◆ num_frames_decoded_

◆ prev_toks_


The documentation for this class was generated from the following files: