diff --git a/speechx/examples/ds2_ol/decoder/ctc-prefix-beam-search-decoder-ol.cc b/speechx/examples/ds2_ol/decoder/ctc-prefix-beam-search-decoder-ol.cc index 46a78ef9..eaec41b7 100644 --- a/speechx/examples/ds2_ol/decoder/ctc-prefix-beam-search-decoder-ol.cc +++ b/speechx/examples/ds2_ol/decoder/ctc-prefix-beam-search-decoder-ol.cc @@ -98,6 +98,7 @@ int main(int argc, char* argv[]) { LOG(INFO) << "receptive field (frame): " << receptive_field_length; decoder.InitDecoder(); + kaldi::Timer timer; for (; !feature_reader.Done(); feature_reader.Next()) { string utt = feature_reader.Key(); kaldi::Matrix feature = feature_reader.Value(); @@ -160,5 +161,7 @@ int main(int argc, char* argv[]) { KALDI_LOG << "Done " << num_done << " utterances, " << num_err << " with errors."; + double elapsed = timer.Elapsed(); + KALDI_LOG << " cost:" << elapsed << " s"; return (num_done != 0 ? 0 : 1); } diff --git a/speechx/examples/ds2_ol/decoder/recognizer_test_main.cc b/speechx/examples/ds2_ol/decoder/recognizer_test_main.cc index e6fed0ed..00764f53 100644 --- a/speechx/examples/ds2_ol/decoder/recognizer_test_main.cc +++ b/speechx/examples/ds2_ol/decoder/recognizer_test_main.cc @@ -38,6 +38,9 @@ int main(int argc, char* argv[]) { LOG(INFO) << "chunk size (sample): " << chunk_sample_size; int32 num_done = 0, num_err = 0; + double tot_wav_duration = 0.0; + + kaldi::Timer timer; for (; !wav_reader.Done(); wav_reader.Next()) { std::string utt = wav_reader.Key(); @@ -47,6 +50,7 @@ int main(int argc, char* argv[]) { kaldi::SubVector waveform(wave_data.Data(), this_channel); int tot_samples = waveform.Dim(); + tot_wav_duration += tot_samples * 1.0 / sample_rate; LOG(INFO) << "wav len (sample): " << tot_samples; int sample_offset = 0; @@ -85,4 +89,9 @@ int main(int argc, char* argv[]) { result_writer.Write(utt, result); ++num_done; } + double elapsed = timer.Elapsed(); + KALDI_LOG << "Done " << num_done << " out of " << (num_err + num_done); + KALDI_LOG << " cost:" << elapsed << " s"; + KALDI_LOG << "total wav duration is: " << tot_wav_duration << " s"; + KALDI_LOG << "the RTF is: " << elapsed / tot_wav_duration; } \ No newline at end of file diff --git a/speechx/examples/ds2_ol/decoder/wfst-decoder-ol.cc b/speechx/examples/ds2_ol/decoder/wfst-decoder-ol.cc index cb68a5a2..fefc16d2 100644 --- a/speechx/examples/ds2_ol/decoder/wfst-decoder-ol.cc +++ b/speechx/examples/ds2_ol/decoder/wfst-decoder-ol.cc @@ -100,7 +100,7 @@ int main(int argc, char* argv[]) { LOG(INFO) << "chunk stride (frame): " << chunk_stride; LOG(INFO) << "receptive field (frame): " << receptive_field_length; decoder.InitDecoder(); - + kaldi::Timer timer; for (; !feature_reader.Done(); feature_reader.Next()) { string utt = feature_reader.Key(); kaldi::Matrix feature = feature_reader.Value(); @@ -160,6 +160,9 @@ int main(int argc, char* argv[]) { ++num_done; } + double elapsed = timer.Elapsed(); + KALDI_LOG << " cost:" << elapsed << " s"; + KALDI_LOG << "Done " << num_done << " utterances, " << num_err << " with errors."; return (num_done != 0 ? 0 : 1); diff --git a/speechx/examples/ds2_ol/feat/CMakeLists.txt b/speechx/examples/ds2_ol/feat/CMakeLists.txt index db59fc8e..84cb4cc7 100644 --- a/speechx/examples/ds2_ol/feat/CMakeLists.txt +++ b/speechx/examples/ds2_ol/feat/CMakeLists.txt @@ -5,8 +5,12 @@ add_executable(${bin_name} ${CMAKE_CURRENT_SOURCE_DIR}/${bin_name}.cc) target_include_directories(${bin_name} PRIVATE ${SPEECHX_ROOT} ${SPEECHX_ROOT}/kaldi) target_link_libraries(${bin_name} frontend kaldi-util kaldi-feat-common gflags glog) +set(bin_name compute_fbank_main) +add_executable(${bin_name} ${CMAKE_CURRENT_SOURCE_DIR}/${bin_name}.cc) +target_include_directories(${bin_name} PRIVATE ${SPEECHX_ROOT} ${SPEECHX_ROOT}/kaldi) +target_link_libraries(${bin_name} frontend kaldi-util kaldi-feat-common kaldi-fbank gflags glog) set(bin_name cmvn-json2kaldi) add_executable(${bin_name} ${CMAKE_CURRENT_SOURCE_DIR}/${bin_name}.cc) target_include_directories(${bin_name} PRIVATE ${SPEECHX_ROOT} ${SPEECHX_ROOT}/kaldi) -target_link_libraries(${bin_name} utils kaldi-util kaldi-matrix gflags glog ${DEPS}) \ No newline at end of file +target_link_libraries(${bin_name} utils kaldi-util kaldi-matrix gflags glog ${DEPS}) diff --git a/speechx/examples/ds2_ol/feat/compute_fbank_main.cc b/speechx/examples/ds2_ol/feat/compute_fbank_main.cc new file mode 100644 index 00000000..8db0f3b5 --- /dev/null +++ b/speechx/examples/ds2_ol/feat/compute_fbank_main.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// 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 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// todo refactor, repalce with gtest + +#include "base/flags.h" +#include "base/log.h" +#include "kaldi/feat/wave-reader.h" +#include "kaldi/util/kaldi-io.h" +#include "kaldi/util/table-types.h" + +#include "frontend/audio/audio_cache.h" +#include "frontend/audio/data_cache.h" +#include "frontend/audio/fbank.h" +#include "frontend/audio/feature_cache.h" +#include "frontend/audio/frontend_itf.h" +#include "frontend/audio/normalizer.h" + +DEFINE_string(wav_rspecifier, "", "test wav scp path"); +DEFINE_string(feature_wspecifier, "", "output feats wspecifier"); +DEFINE_string(cmvn_file, "", "read cmvn"); +DEFINE_double(streaming_chunk, 0.36, "streaming feature chunk size"); +DEFINE_int32(num_bins, 161, "fbank num bins"); + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, false); + google::InitGoogleLogging(argv[0]); + + kaldi::SequentialTableReader wav_reader( + FLAGS_wav_rspecifier); + kaldi::BaseFloatMatrixWriter feat_writer(FLAGS_feature_wspecifier); + + int32 num_done = 0, num_err = 0; + + // feature pipeline: wave cache --> hanning window + // -->fbank --> global cmvn -> feat cache + + std::unique_ptr data_source( + new ppspeech::AudioCache(3600 * 1600, false)); + + ppspeech::FbankOptions opt; + opt.fbank_opts.frame_opts.frame_length_ms = 25; + opt.fbank_opts.frame_opts.frame_shift_ms = 10; + opt.streaming_chunk = FLAGS_streaming_chunk; + opt.fbank_opts.mel_opts.num_bins = FLAGS_num_bins; + opt.fbank_opts.frame_opts.dither = 0.0; + + std::unique_ptr fbank( + new ppspeech::Fbank(opt, std::move(data_source))); + + std::unique_ptr cmvn( + new ppspeech::CMVN(FLAGS_cmvn_file, std::move(fbank))); + + ppspeech::FeatureCacheOptions feat_cache_opts; + // the feature cache output feature chunk by chunk. + // frame_chunk_size : num frame of a chunk. + // frame_chunk_stride: chunk sliding window stride. + feat_cache_opts.frame_chunk_stride = 1; + feat_cache_opts.frame_chunk_size = 1; + ppspeech::FeatureCache feature_cache(feat_cache_opts, std::move(cmvn)); + LOG(INFO) << "feat dim: " << feature_cache.Dim(); + + int sample_rate = 16000; + float streaming_chunk = FLAGS_streaming_chunk; + int chunk_sample_size = streaming_chunk * sample_rate; + LOG(INFO) << "sr: " << sample_rate; + LOG(INFO) << "chunk size (s): " << streaming_chunk; + LOG(INFO) << "chunk size (sample): " << chunk_sample_size; + + + for (; !wav_reader.Done(); wav_reader.Next()) { + std::string utt = wav_reader.Key(); + const kaldi::WaveData& wave_data = wav_reader.Value(); + LOG(INFO) << "process utt: " << utt; + + int32 this_channel = 0; + kaldi::SubVector waveform(wave_data.Data(), + this_channel); + int tot_samples = waveform.Dim(); + LOG(INFO) << "wav len (sample): " << tot_samples; + + int sample_offset = 0; + std::vector> feats; + int feature_rows = 0; + while (sample_offset < tot_samples) { + int cur_chunk_size = + std::min(chunk_sample_size, tot_samples - sample_offset); + + kaldi::Vector wav_chunk(cur_chunk_size); + for (int i = 0; i < cur_chunk_size; ++i) { + wav_chunk(i) = waveform(sample_offset + i); + } + + kaldi::Vector features; + feature_cache.Accept(wav_chunk); + if (cur_chunk_size < chunk_sample_size) { + feature_cache.SetFinished(); + } + bool flag = true; + do { + flag = feature_cache.Read(&features); + feats.push_back(features); + feature_rows += features.Dim() / feature_cache.Dim(); + } while (flag == true && features.Dim() != 0); + sample_offset += cur_chunk_size; + } + + int cur_idx = 0; + kaldi::Matrix features(feature_rows, + feature_cache.Dim()); + for (auto feat : feats) { + int num_rows = feat.Dim() / feature_cache.Dim(); + for (int row_idx = 0; row_idx < num_rows; ++row_idx) { + for (size_t col_idx = 0; col_idx < feature_cache.Dim(); + ++col_idx) { + features(cur_idx, col_idx) = + feat(row_idx * feature_cache.Dim() + col_idx); + } + ++cur_idx; + } + } + feat_writer.Write(utt, features); + feature_cache.Reset(); + + if (num_done % 50 == 0 && num_done != 0) + KALDI_VLOG(2) << "Processed " << num_done << " utterances"; + num_done++; + } + KALDI_LOG << "Done " << num_done << " utterances, " << num_err + << " with errors."; + return (num_done != 0 ? 0 : 1); +} diff --git a/speechx/speechx/frontend/audio/CMakeLists.txt b/speechx/speechx/frontend/audio/CMakeLists.txt index 2d20edf7..028da6c9 100644 --- a/speechx/speechx/frontend/audio/CMakeLists.txt +++ b/speechx/speechx/frontend/audio/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(frontend STATIC audio_cache.cc feature_cache.cc feature_pipeline.cc + fbank.cc ) target_link_libraries(frontend PUBLIC kaldi-matrix kaldi-feat-common) diff --git a/speechx/speechx/frontend/audio/fbank.cc b/speechx/speechx/frontend/audio/fbank.cc index 8273beec..a3105b39 100644 --- a/speechx/speechx/frontend/audio/fbank.cc +++ b/speechx/speechx/frontend/audio/fbank.cc @@ -33,10 +33,10 @@ Fbank::Fbank(const FbankOptions& opts, std::unique_ptr base_extractor) : opts_(opts), computer_(opts.fbank_opts), - window_function_(computer_.GetFrameOptions()) { + window_function_(opts.fbank_opts.frame_opts) { base_extractor_ = std::move(base_extractor); - chunk_sample_size_ = - static_cast(opts.streaming_chunk * opts.frame_opts.samp_freq); + chunk_sample_size_ = static_cast( + opts.streaming_chunk * opts.fbank_opts.frame_opts.samp_freq); } void Fbank::Accept(const VectorBase& inputs) { @@ -71,7 +71,8 @@ bool Fbank::Read(Vector* feats) { // Compute spectrogram feat bool Fbank::Compute(const Vector& waves, Vector* feats) { - const FrameExtractionOptions& frame_opts = computer_.GetFrameOptions(); + const kaldi::FrameExtractionOptions& frame_opts = + computer_.GetFrameOptions(); int32 num_samples = waves.Dim(); int32 frame_length = frame_opts.WindowSize(); int32 sample_rate = frame_opts.samp_freq; @@ -80,7 +81,7 @@ bool Fbank::Compute(const Vector& waves, Vector* feats) { } int32 num_frames = kaldi::NumFrames(num_samples, frame_opts); - feats->Rsize(num_frames * Dim()); + feats->Resize(num_frames * Dim()); Vector window; bool need_raw_log_energy = computer_.NeedRawLogEnergy(); @@ -95,7 +96,7 @@ bool Fbank::Compute(const Vector& waves, Vector* feats) { need_raw_log_energy ? &raw_log_energy : NULL); - Vector this_feature(computer_.Dim(), kUndefined); + Vector this_feature(computer_.Dim(), kaldi::kUndefined); // note: this online feature-extraction code does not support VTLN. BaseFloat vtln_warp = 1.0; computer_.Compute(raw_log_energy, vtln_warp, &window, &this_feature); diff --git a/speechx/speechx/frontend/audio/fbank.h b/speechx/speechx/frontend/audio/fbank.h index 3b71ff84..720e17c7 100644 --- a/speechx/speechx/frontend/audio/fbank.h +++ b/speechx/speechx/frontend/audio/fbank.h @@ -14,6 +14,8 @@ #pragma once +#include "base/common.h" +#include "frontend/audio/frontend_itf.h" #include "kaldi/feat/feature-fbank.h" #include "kaldi/feat/feature-mfcc.h" #include "kaldi/matrix/kaldi-vector.h" @@ -38,7 +40,7 @@ struct FbankOptions { class Fbank : public FrontendInterface { public: explicit Fbank(const FbankOptions& opts, - unique_ptr base_extractor); + std::unique_ptr base_extractor); virtual void Accept(const kaldi::VectorBase& inputs); virtual bool Read(kaldi::Vector* feats); @@ -61,13 +63,13 @@ class Fbank : public FrontendInterface { FbankOptions opts_; std::unique_ptr base_extractor_; - - FeatureWindowFunction window_function_; + kaldi::FeatureWindowFunction window_function_; kaldi::FbankComputer computer_; // features_ is the Mfcc or Plp or Fbank features that we have already // computed. kaldi::Vector features_; kaldi::Vector remained_wav_; + kaldi::int32 chunk_sample_size_; DISALLOW_COPY_AND_ASSIGN(Fbank); }; diff --git a/speechx/speechx/kaldi/feat/CMakeLists.txt b/speechx/speechx/kaldi/feat/CMakeLists.txt index c3a996ff..cfbf2025 100644 --- a/speechx/speechx/kaldi/feat/CMakeLists.txt +++ b/speechx/speechx/kaldi/feat/CMakeLists.txt @@ -3,10 +3,10 @@ add_library(kaldi-mfcc ) target_link_libraries(kaldi-mfcc PUBLIC kaldi-feat-common) -add_library(fbank +add_library(kaldi-fbank feature-fbank.cc ) -target_link_libraries(fbank PUBLIC kaldi-feat-common) +target_link_libraries(kaldi-fbank PUBLIC kaldi-feat-common) add_library(kaldi-feat-common wave-reader.cc diff --git a/speechx/speechx/kaldi/feat/feature-fbank.cc b/speechx/speechx/kaldi/feat/feature-fbank.cc index d9ac03e5..8f3fcd52 100644 --- a/speechx/speechx/kaldi/feat/feature-fbank.cc +++ b/speechx/speechx/kaldi/feat/feature-fbank.cc @@ -84,10 +84,11 @@ void FbankComputer::Compute(BaseFloat signal_raw_log_energy, if (opts_.use_energy && !opts_.raw_energy) signal_raw_log_energy = Log(std::max(VecVec(*signal_frame, *signal_frame), std::numeric_limits::epsilon())); - - if (srfft_ != NULL) // Compute FFT using split-radix algorithm. - srfft_->Compute(signal_frame->Data(), true); - else // An alternative algorithm that works for non-powers-of-two. + + // todo : remove later; as align fbank feature in paddleaudio + //if (srfft_ != NULL) // Compute FFT using split-radix algorithm. + // srfft_->Compute(signal_frame->Data(), true); + //else // An alternative algorithm that works for non-powers-of-two. RealFft(signal_frame, true); // Convert the FFT into a power spectrum. diff --git a/speechx/speechx/kaldi/feat/mel-computations.cc b/speechx/speechx/kaldi/feat/mel-computations.cc index bb5e9f9a..626cb677 100644 --- a/speechx/speechx/kaldi/feat/mel-computations.cc +++ b/speechx/speechx/kaldi/feat/mel-computations.cc @@ -120,8 +120,8 @@ MelBanks::MelBanks(const MelBanksOptions &opts, last_index = i; } } - KALDI_ASSERT(first_index != -1 && last_index >= first_index - && "You may have set --num-mel-bins too large."); + //KALDI_ASSERT(first_index != -1 && last_index >= first_index + // && "You may have set --num-mel-bins too large."); bins_[bin].first = first_index; int32 size = last_index + 1 - first_index;