Reduce model initialization time for online speech recognition (#215)

* Reduce model initialization time for online speech recognition

* Fixed Styling

---------

Co-authored-by: w11wo <wilsowong961@gmail.com>
This commit is contained in:
Wilson Wongso
2023-07-14 20:20:10 +07:00
committed by GitHub
parent fe0630fe1f
commit 5a6b55c5a7
7 changed files with 69 additions and 8 deletions

View File

@@ -50,6 +50,8 @@ SherpaOnnxOnlineRecognizer *CreateOnlineRecognizer(
SHERPA_ONNX_OR(config->model_config.num_threads, 1); SHERPA_ONNX_OR(config->model_config.num_threads, 1);
recognizer_config.model_config.provider = recognizer_config.model_config.provider =
SHERPA_ONNX_OR(config->model_config.provider, "cpu"); SHERPA_ONNX_OR(config->model_config.provider, "cpu");
recognizer_config.model_config.model_type =
SHERPA_ONNX_OR(config->model_config.model_type, "");
recognizer_config.model_config.debug = recognizer_config.model_config.debug =
SHERPA_ONNX_OR(config->model_config.debug, 0); SHERPA_ONNX_OR(config->model_config.debug, 0);

View File

@@ -53,6 +53,7 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOnlineTransducerModelConfig {
const char *tokens; const char *tokens;
int32_t num_threads; int32_t num_threads;
const char *provider; const char *provider;
const char *model_type;
int32_t debug; // true to print debug information of the model int32_t debug; // true to print debug information of the model
} SherpaOnnxOnlineTransducerModelConfig; } SherpaOnnxOnlineTransducerModelConfig;

View File

@@ -22,26 +22,30 @@ void OnlineTransducerModelConfig::Register(ParseOptions *po) {
po->Register("debug", &debug, po->Register("debug", &debug,
"true to print model information while loading it."); "true to print model information while loading it.");
po->Register("model-type", &model_type,
"Specify it to reduce model initialization time. "
"Valid values are: conformer, lstm, zipformer, zipformer2. "
"All other values lead to loading the model twice.");
} }
bool OnlineTransducerModelConfig::Validate() const { bool OnlineTransducerModelConfig::Validate() const {
if (!FileExists(tokens)) { if (!FileExists(tokens)) {
SHERPA_ONNX_LOGE("%s does not exist", tokens.c_str()); SHERPA_ONNX_LOGE("tokens: %s does not exist", tokens.c_str());
return false; return false;
} }
if (!FileExists(encoder_filename)) { if (!FileExists(encoder_filename)) {
SHERPA_ONNX_LOGE("%s does not exist", encoder_filename.c_str()); SHERPA_ONNX_LOGE("encoder: %s does not exist", encoder_filename.c_str());
return false; return false;
} }
if (!FileExists(decoder_filename)) { if (!FileExists(decoder_filename)) {
SHERPA_ONNX_LOGE("%s does not exist", decoder_filename.c_str()); SHERPA_ONNX_LOGE("decoder: %s does not exist", decoder_filename.c_str());
return false; return false;
} }
if (!FileExists(joiner_filename)) { if (!FileExists(joiner_filename)) {
SHERPA_ONNX_LOGE("%s does not exist", joiner_filename.c_str()); SHERPA_ONNX_LOGE("joiner: %s does not exist", joiner_filename.c_str());
return false; return false;
} }
@@ -63,6 +67,7 @@ std::string OnlineTransducerModelConfig::ToString() const {
os << "tokens=\"" << tokens << "\", "; os << "tokens=\"" << tokens << "\", ";
os << "num_threads=" << num_threads << ", "; os << "num_threads=" << num_threads << ", ";
os << "provider=\"" << provider << "\", "; os << "provider=\"" << provider << "\", ";
os << "model_type=\"" << model_type << "\", ";
os << "debug=" << (debug ? "True" : "False") << ")"; os << "debug=" << (debug ? "True" : "False") << ")";
return os.str(); return os.str();

View File

@@ -19,19 +19,33 @@ struct OnlineTransducerModelConfig {
bool debug = false; bool debug = false;
std::string provider = "cpu"; std::string provider = "cpu";
// With the help of this field, we only need to load the model once
// instead of twice; and therefore it reduces initialization time.
//
// Valid values:
// - conformer
// - lstm
// - zipformer
// - zipformer2
//
// All other values are invalid and lead to loading the model twice.
std::string model_type;
OnlineTransducerModelConfig() = default; OnlineTransducerModelConfig() = default;
OnlineTransducerModelConfig(const std::string &encoder_filename, OnlineTransducerModelConfig(const std::string &encoder_filename,
const std::string &decoder_filename, const std::string &decoder_filename,
const std::string &joiner_filename, const std::string &joiner_filename,
const std::string &tokens, int32_t num_threads, const std::string &tokens, int32_t num_threads,
bool debug, const std::string &provider) bool debug, const std::string &provider,
const std::string &model_type)
: encoder_filename(encoder_filename), : encoder_filename(encoder_filename),
decoder_filename(decoder_filename), decoder_filename(decoder_filename),
joiner_filename(joiner_filename), joiner_filename(joiner_filename),
tokens(tokens), tokens(tokens),
num_threads(num_threads), num_threads(num_threads),
debug(debug), debug(debug),
provider(provider) {} provider(provider),
model_type(model_type) {}
void Register(ParseOptions *po); void Register(ParseOptions *po);
bool Validate() const; bool Validate() const;

View File

@@ -77,6 +77,22 @@ static ModelType GetModelType(char *model_data, size_t model_data_length,
std::unique_ptr<OnlineTransducerModel> OnlineTransducerModel::Create( std::unique_ptr<OnlineTransducerModel> OnlineTransducerModel::Create(
const OnlineTransducerModelConfig &config) { const OnlineTransducerModelConfig &config) {
if (!config.model_type.empty()) {
const auto &model_type = config.model_type;
if (model_type == "conformer") {
return std::make_unique<OnlineConformerTransducerModel>(config);
} else if (model_type == "lstm") {
return std::make_unique<OnlineLstmTransducerModel>(config);
} else if (model_type == "zipformer") {
return std::make_unique<OnlineZipformerTransducerModel>(config);
} else if (model_type == "zipformer2") {
return std::make_unique<OnlineZipformer2TransducerModel>(config);
} else {
SHERPA_ONNX_LOGE(
"Invalid model_type: %s. Trying to load the model to get its type",
model_type.c_str());
}
}
ModelType model_type = ModelType::kUnkown; ModelType model_type = ModelType::kUnkown;
{ {
@@ -140,6 +156,23 @@ Ort::Value OnlineTransducerModel::BuildDecoderInput(
#if __ANDROID_API__ >= 9 #if __ANDROID_API__ >= 9
std::unique_ptr<OnlineTransducerModel> OnlineTransducerModel::Create( std::unique_ptr<OnlineTransducerModel> OnlineTransducerModel::Create(
AAssetManager *mgr, const OnlineTransducerModelConfig &config) { AAssetManager *mgr, const OnlineTransducerModelConfig &config) {
if (!config.model_type.empty()) {
const auto &model_type = config.model_type;
if (model_type == "conformer") {
return std::make_unique<OnlineConformerTransducerModel>(mgr, config);
} else if (model_type == "lstm") {
return std::make_unique<OnlineLstmTransducerModel>(mgr, config);
} else if (model_type == "zipformer") {
return std::make_unique<OnlineZipformerTransducerModel>(mgr, config);
} else if (model_type == "zipformer2") {
return std::make_unique<OnlineZipformer2TransducerModel>(mgr, config);
} else {
SHERPA_ONNX_LOGE(
"Invalid model_type: %s. Trying to load the model to get its type",
model_type.c_str());
}
}
auto buffer = ReadFile(mgr, config.encoder_filename); auto buffer = ReadFile(mgr, config.encoder_filename);
auto model_type = GetModelType(buffer.data(), buffer.size(), config.debug); auto model_type = GetModelType(buffer.data(), buffer.size(), config.debug);

View File

@@ -15,11 +15,11 @@ void PybindOnlineTransducerModelConfig(py::module *m) {
py::class_<PyClass>(*m, "OnlineTransducerModelConfig") py::class_<PyClass>(*m, "OnlineTransducerModelConfig")
.def(py::init<const std::string &, const std::string &, .def(py::init<const std::string &, const std::string &,
const std::string &, const std::string &, int32_t, bool, const std::string &, const std::string &, int32_t, bool,
const std::string &>(), const std::string &, const std::string &>(),
py::arg("encoder_filename"), py::arg("decoder_filename"), py::arg("encoder_filename"), py::arg("decoder_filename"),
py::arg("joiner_filename"), py::arg("tokens"), py::arg("joiner_filename"), py::arg("tokens"),
py::arg("num_threads"), py::arg("debug") = false, py::arg("num_threads"), py::arg("debug") = false,
py::arg("provider") = "cpu") py::arg("provider") = "cpu", py::arg("model_type") = "")
.def_readwrite("encoder_filename", &PyClass::encoder_filename) .def_readwrite("encoder_filename", &PyClass::encoder_filename)
.def_readwrite("decoder_filename", &PyClass::decoder_filename) .def_readwrite("decoder_filename", &PyClass::decoder_filename)
.def_readwrite("joiner_filename", &PyClass::joiner_filename) .def_readwrite("joiner_filename", &PyClass::joiner_filename)
@@ -27,6 +27,7 @@ void PybindOnlineTransducerModelConfig(py::module *m) {
.def_readwrite("num_threads", &PyClass::num_threads) .def_readwrite("num_threads", &PyClass::num_threads)
.def_readwrite("debug", &PyClass::debug) .def_readwrite("debug", &PyClass::debug)
.def_readwrite("provider", &PyClass::provider) .def_readwrite("provider", &PyClass::provider)
.def_readwrite("model_type", &PyClass::model_type)
.def("__str__", &PyClass::ToString); .def("__str__", &PyClass::ToString);
} }

View File

@@ -41,6 +41,7 @@ class OnlineRecognizer(object):
max_active_paths: int = 4, max_active_paths: int = 4,
context_score: float = 1.5, context_score: float = 1.5,
provider: str = "cpu", provider: str = "cpu",
model_type: str = "",
): ):
""" """
Please refer to Please refer to
@@ -90,6 +91,9 @@ class OnlineRecognizer(object):
the maximum number of active paths during beam search. the maximum number of active paths during beam search.
provider: provider:
onnxruntime execution providers. Valid values are: cpu, cuda, coreml. onnxruntime execution providers. Valid values are: cpu, cuda, coreml.
model_type:
Online transducer model type. Valid values are: conformer, lstm,
zipformer, zipformer2. All other values lead to loading the model twice.
""" """
_assert_file_exists(tokens) _assert_file_exists(tokens)
_assert_file_exists(encoder) _assert_file_exists(encoder)
@@ -105,6 +109,7 @@ class OnlineRecognizer(object):
tokens=tokens, tokens=tokens,
num_threads=num_threads, num_threads=num_threads,
provider=provider, provider=provider,
model_type=model_type,
) )
feat_config = FeatureExtractorConfig( feat_config = FeatureExtractorConfig(