From 1f89bef5f0f58c1d348b3fa534694481623b6be7 Mon Sep 17 00:00:00 2001 From: godeffroy Date: Mon, 31 Aug 2020 19:01:47 +0200 Subject: [PATCH] PR #3279 - avoid unnecessary copies of timesteps vectors --- .../ctcdecode/ctc_beam_search_decoder.cpp | 15 ++++++++------- native_client/ctcdecode/path_trie.cpp | 15 ++++++++++----- native_client/ctcdecode/path_trie.h | 8 +++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/native_client/ctcdecode/ctc_beam_search_decoder.cpp b/native_client/ctcdecode/ctc_beam_search_decoder.cpp index c28dacd2..0fe7784c 100644 --- a/native_client/ctcdecode/ctc_beam_search_decoder.cpp +++ b/native_client/ctcdecode/ctc_beam_search_decoder.cpp @@ -106,7 +106,8 @@ DecoderState::next(const double *probs, // combine current path with previous ones with the same prefix // the blank label comes last, so we can compare log_prob_nb_cur with log_p if (prefix->log_prob_nb_cur < log_p) { - prefix->timesteps_cur = prefix->timesteps; + // keep current timesteps + prefix->previous_timesteps = nullptr; } prefix->log_prob_b_cur = log_sum_exp(prefix->log_prob_b_cur, log_p); @@ -120,7 +121,8 @@ DecoderState::next(const double *probs, // combine current path with previous ones with the same prefix if (prefix->log_prob_nb_cur < log_p) { - prefix->timesteps_cur = prefix->timesteps; + // keep current timesteps + prefix->previous_timesteps = nullptr; } prefix->log_prob_nb_cur = log_sum_exp( prefix->log_prob_nb_cur, log_p); @@ -130,10 +132,6 @@ DecoderState::next(const double *probs, auto prefix_new = prefix->get_path_trie(c, log_prob_c); if (prefix_new != nullptr) { - // compute timesteps of current path - std::vector timesteps_new=prefix->timesteps; - timesteps_new.push_back(abs_time_step_); - // compute probability of current path float log_p = -NUM_FLT_INF; @@ -167,7 +165,10 @@ DecoderState::next(const double *probs, // combine current path with previous ones with the same prefix if (prefix_new->log_prob_nb_cur < log_p) { - prefix_new->timesteps_cur = timesteps_new; + // record data needed to update timesteps + // the actual update will be done if nothing better is found + prefix_new->previous_timesteps = &prefix->timesteps; + prefix_new->new_timestep = abs_time_step_; } prefix_new->log_prob_nb_cur = log_sum_exp(prefix_new->log_prob_nb_cur, log_p); diff --git a/native_client/ctcdecode/path_trie.cpp b/native_client/ctcdecode/path_trie.cpp index ebb4d924..cca89a93 100644 --- a/native_client/ctcdecode/path_trie.cpp +++ b/native_client/ctcdecode/path_trie.cpp @@ -157,6 +157,11 @@ PathTrie* PathTrie::get_prev_word(std::vector& output, } void PathTrie::iterate_to_vec(std::vector& output) { + // previous_timesteps might point to ancestors' timesteps + // therefore, children must be uptaded first + for (auto child : children_) { + child.second->iterate_to_vec(output); + } if (exists_) { log_prob_b_prev = log_prob_b_cur; log_prob_nb_prev = log_prob_nb_cur; @@ -166,14 +171,14 @@ void PathTrie::iterate_to_vec(std::vector& output) { score = log_sum_exp(log_prob_b_prev, log_prob_nb_prev); - timesteps = std::move(timesteps_cur); - timesteps_cur.clear(); + if (previous_timesteps != nullptr) { + timesteps = *previous_timesteps; + timesteps.push_back(new_timestep); + } + previous_timesteps=nullptr; output.push_back(this); } - for (auto child : children_) { - child.second->iterate_to_vec(output); - } } void PathTrie::remove() { diff --git a/native_client/ctcdecode/path_trie.h b/native_client/ctcdecode/path_trie.h index a3ef7bdb..00e0c3bf 100644 --- a/native_client/ctcdecode/path_trie.h +++ b/native_client/ctcdecode/path_trie.h @@ -64,9 +64,11 @@ public: float approx_ctc; unsigned int character; std::vector timesteps; - // `timesteps_cur` is a temporary storage for each decoding step. - // At the end of a decoding step, it is moved to `timesteps`. - std::vector timesteps_cur; + + // timestep temporary storage for each decoding step. + std::vector* previous_timesteps=nullptr; + unsigned int new_timestep; + PathTrie* parent; private: