From 7d6ab90716a327983e3618b0da86776ada25c397 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Thu, 25 Feb 2021 13:38:46 +0100 Subject: [PATCH] [ML][single] SingleShot.invoke implementation added ACR: TWDAPI-273 Test code: var ti1 = new tizen.ml.TensorsInfo() ti1.addTensorInfo("three", "FLOAT32", [1, 1, 1, 1]) var td1 = ti1.getTensorsData(0); td1.setTensorRawData(0, [1]); var ti3 = new tizen.ml.TensorsInfo() ti3.addTensorInfo("three", "FLOAT32", [3, 1, 1, 1]) var td3 = ti3.getTensorsData(0); td3.setTensorRawData(0, [1, 2, 3]); var ti5 = new tizen.ml.TensorsInfo() ti5.addTensorInfo("three", "FLOAT32", [5, 1, 1, 1]) var td5 = ti5.getTensorsData(0); td5.setTensorRawData(0, [1, 2, 3, 4, 5]); // using model from nnstreamer API var m = tizen.ml.single.openModel('documents/add.tflite', null, null, "ANY", "ANY") m.invoke(td1) // ok m.invoke(td3) // error m.invoke(td5) // error var m_dynamic = tizen.ml.single.openModel('documents/add.tflite', null, null, "ANY", "ANY", true) m_dynamic.invoke(td1) // ok m_dynamic.invoke(td3) // ok m_dynamic.invoke(td5) // ok [Verification] Built successful. Tested in Chrome Dev console. Change-Id: I25218c122c57d6cb781181388f94a27ee0605ee8 Signed-off-by: Rafal Walczyna --- src/ml/js/ml_single.js | 34 ++++++++- src/ml/ml_instance.cc | 29 +++++++- src/ml/ml_instance.h | 2 +- src/ml/ml_single_manager.cc | 40 +++++++++- src/ml/ml_single_manager.h | 2 +- src/ml/ml_singleshot.cc | 118 +++++++++++++++++++++++++++++- src/ml/ml_singleshot.h | 14 +++- src/ml/ml_tensors_data_manager.cc | 16 ++++ src/ml/ml_tensors_data_manager.h | 1 + src/ml/ml_tensors_info_manager.cc | 9 +++ src/ml/ml_tensors_info_manager.h | 2 + 11 files changed, 254 insertions(+), 13 deletions(-) diff --git a/src/ml/js/ml_single.js b/src/ml/js/ml_single.js index d516997b..57fae3e6 100755 --- a/src/ml/js/ml_single.js +++ b/src/ml/js/ml_single.js @@ -270,7 +270,39 @@ var SingleShot = function(id) { }); }; -// SingleShot::invoke() +var ValidInvokeExceptions = [ + 'TimeoutError', + 'TypeMismatchError', + 'NotSupportedError', + 'AbortError' +]; + +SingleShot.prototype.invoke = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'inTensorsData', + type: types_.PLATFORM_OBJECT, + values: TensorsData + } + ]); + + var nativeArgs = { + id: this._id, + tensorsDataId: args.inTensorsData._id + }; + + var result = native_.callSync('MLSingleShotInvoke', nativeArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidInvokeExceptions, + AbortError + ); + } + + return new TensorsData(result.tensorsDataId, result.tensorsInfoId); +}; var GetSetValueValidExceptions = [ 'AbortError', diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 9eb99b64..1e188e11 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -125,7 +125,7 @@ MlInstance::MlInstance() REGISTER_METHOD(MLSingleManagerOpenModel); REGISTER_METHOD(MLSingleShotGetTensorsInfo); REGISTER_METHOD(MLSingleShotSetInputInfo); - // SingleShot::invoke() + REGISTER_METHOD(MLSingleShotInvoke); REGISTER_METHOD(MLSingleShotGetValue); REGISTER_METHOD(MLSingleShotSetValue); // SingleShot::setTimeout() @@ -888,7 +888,32 @@ void MlInstance::MLSingleShotSetInputInfo(const picojson::value& args, picojson: ReportSuccess(out); } -// SingleShot::invoke() +void MlInstance::MLSingleShotInvoke(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kId, double, out); + CHECK_ARGS(args, kTensorsDataId, double, out); + + int id = static_cast(args.get(kId).get()); + int tensors_data_id = static_cast(args.get(kTensorsDataId).get()); + + TensorsData* in_tensors_data = GetTensorsDataManager().GetTensorsData(tensors_data_id); + if (nullptr == in_tensors_data) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsData error"), &out, + ("Could not find TensorsData handle with given id: %d", tensors_data_id)); + return; + } + + TensorsData* out_tensors_data = nullptr; + auto ret = single_manager_.Invoke(id, in_tensors_data, &out_tensors_data); + if (!ret) { + ReportError(ret, &out); + return; + } + + out[kTensorsDataId] = picojson::value(static_cast(out_tensors_data->Id())); + out[kTensorsInfoId] = picojson::value(static_cast(out_tensors_data->TensorsInfoId())); + ReportSuccess(out); +} void MlInstance::MLSingleShotGetValue(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 88b71af3..3366b3e5 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -75,7 +75,7 @@ class MlInstance : public common::ParsedInstance { void MLSingleManagerOpenModel(const picojson::value& args, picojson::object& out); void MLSingleShotGetTensorsInfo(const picojson::value& args, picojson::object& out); void MLSingleShotSetInputInfo(const picojson::value& args, picojson::object& out); - // SingleShot::invoke() + void MLSingleShotInvoke(const picojson::value& args, picojson::object& out); void MLSingleShotGetValue(const picojson::value& args, picojson::object& out); void MLSingleShotSetValue(const picojson::value& args, picojson::object& out); // SingleShot::setTimeout() diff --git a/src/ml/ml_single_manager.cc b/src/ml/ml_single_manager.cc index 68c262b4..a460a14f 100644 --- a/src/ml/ml_single_manager.cc +++ b/src/ml/ml_single_manager.cc @@ -50,7 +50,7 @@ PlatformResult SingleManager::OpenModel(const std::string& modelPath, TensorsInf std::lock_guard singles_lock(singles_mutex_); int id = nextId_++; - singles_[id] = std::make_unique(id, handle); + singles_[id] = std::make_unique(id, handle, isDynamicMode); *res_id = id; return PlatformResult{}; } @@ -106,7 +106,43 @@ PlatformResult SingleManager::SetNativeInputInfo(int id, TensorsInfo* inTensorsI return PlatformResult{}; } -// SingleShot::invoke() +PlatformResult SingleManager::Invoke(int id, TensorsData* in_tensors_data, + TensorsData** out_tensors_data) { + ScopeLogger(); + + SingleShot* single = GetSingleShot(id); + if (!single) { + LoggerE("Could not find SingleShot handle"); + return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error"); + } + + ml_tensors_info_h out_tensors_info_h = nullptr; + ml_tensors_data_h out_tensors_data_h = nullptr; + bool should_copy_data = false; + PlatformResult result = + single->Invoke(in_tensors_data->Handle(), in_tensors_data->GetTensorsInfo()->Handle(), + &out_tensors_data_h, &out_tensors_info_h, &should_copy_data); + if (!result) { + return result; + } + if (should_copy_data) { + *out_tensors_data = tim_->CloneNativeTensorWithData(out_tensors_info_h, out_tensors_data_h); + } else { + *out_tensors_data = tim_->CreateTensorsData(out_tensors_info_h, out_tensors_data_h); + } + + if (*out_tensors_data == nullptr) { + LoggerE("out_tensors_data creation failed"); + result = single->CleanUpAfterInvoke(); + if (!result) { + LoggerE("CleanUpAfterInvoke failed"); + } + return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error"); + } + + return PlatformResult{}; +} + PlatformResult SingleManager::GetValue(int id, const std::string& name, std::string& value) { ScopeLogger(); diff --git a/src/ml/ml_single_manager.h b/src/ml/ml_single_manager.h index ad232aa9..18d5aa02 100644 --- a/src/ml/ml_single_manager.h +++ b/src/ml/ml_single_manager.h @@ -47,7 +47,7 @@ class SingleManager { // OpenModelSuccessCallback PlatformResult GetNativeTensorsInfo(int id, bool get_input_mode, int* res_id); PlatformResult SetNativeInputInfo(int id, TensorsInfo* inTensorsInfo); - // SingleShot::invoke() + PlatformResult Invoke(int id, TensorsData* in_tensors_data, TensorsData** out_tensors_data); PlatformResult GetValue(int id, const std::string& name, std::string& value); PlatformResult SetValue(int id, const std::string& name, const std::string& value); // SingleShot::setTimeout() diff --git a/src/ml/ml_singleshot.cc b/src/ml/ml_singleshot.cc index 7459242c..d7cc4d15 100644 --- a/src/ml/ml_singleshot.cc +++ b/src/ml/ml_singleshot.cc @@ -26,18 +26,41 @@ using common::ErrorCode; namespace extension { namespace ml { -SingleShot::SingleShot(int id, ml_single_h handle) : id_{id}, handle_{handle} { +SingleShot::SingleShot(int id, ml_single_h handle, bool dynamic_mode) + : id_{id}, + handle_{handle}, + dynamic_mode_{dynamic_mode}, + tensor_data_out_handle_{nullptr}, + tensor_info_out_handle_{nullptr} { ScopeLogger("id: %d", id_); } // 'this' owns a handle_, and invalidates 'o' -SingleShot::SingleShot(SingleShot&& o) : id_(o.id_), handle_(o.handle_) { +SingleShot::SingleShot(SingleShot&& o) + : id_(o.id_), handle_(o.handle_), dynamic_mode_(o.dynamic_mode_) { ScopeLogger("id: %d", id_); o.handle_ = nullptr; } SingleShot::~SingleShot() { ScopeLogger("id: %d", id_); + // not dynamic mode uses ml_single_invoke_fast, which reuses handles, so they need to be freed + if (!dynamic_mode_) { + if (nullptr != tensor_data_out_handle_) { + int ret = ml_tensors_data_destroy(tensor_data_out_handle_); + if (ML_ERROR_NONE != ret) { + LoggerW("ml_tensors_data_destroy failed: %d (%s)", ret, get_error_message(ret)); + } + } + + if (nullptr != tensor_info_out_handle_) { + int ret = ml_tensors_info_destroy(tensor_info_out_handle_); + if (ML_ERROR_NONE != ret) { + LoggerW("ml_tensors_info_destroy failed: %d (%s)", ret, get_error_message(ret)); + } + } + } + int ret = ml_single_close(handle_); if (ML_ERROR_NONE != ret) { LoggerW("ml_single_close failed: %d (%s)", ret, get_error_message(ret)); @@ -75,7 +98,96 @@ PlatformResult SingleShot::SetInputInfo(ml_tensors_info_h in_info) { return PlatformResult{}; } -// SingleShot::invoke() +PlatformResult SingleShot::Invoke(ml_tensors_data_h in_data, ml_tensors_info_h in_info, + ml_tensors_data_h* out_data, ml_tensors_info_h* out_info, + bool* should_copy_data) { + ScopeLogger(); + PlatformResult result; + if (dynamic_mode_) { + result = InvokeDynamicInternal(in_data, in_info); + } else { + result = InvokeInternal(in_data, in_info); + } + if (!result) { + return result; + } + + *out_data = tensor_data_out_handle_; + *out_info = tensor_info_out_handle_; + *should_copy_data = !dynamic_mode_; + + return PlatformResult{}; +} + +PlatformResult SingleShot::InvokeInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info) { + ScopeLogger(); + if (nullptr == tensor_info_out_handle_) { + PlatformResult result = GetTensorsInfo(false, &tensor_info_out_handle_); + if (!result) { + LoggerE("GetTensorsInfo failed"); + return result; + } + } + + if (nullptr == tensor_data_out_handle_) { + int ret = ml_tensors_data_create(tensor_info_out_handle_, &tensor_data_out_handle_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_tensors_data_create failed: %d (%s)", ret, get_error_message(ret)); + return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error"); + } + } + + int ret = ml_single_invoke_fast(handle_, in_data, tensor_data_out_handle_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_single_invoke failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to invoke"); + } + return PlatformResult{}; +} + +PlatformResult SingleShot::InvokeDynamicInternal(ml_tensors_data_h in_data, + ml_tensors_info_h in_info) { + ScopeLogger(); + int ret = ml_single_invoke_dynamic(handle_, in_data, in_info, &tensor_data_out_handle_, + &tensor_info_out_handle_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_single_invoke_dynamic failed: %d (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Failed to invoke"); + } + + return PlatformResult{}; +} + +PlatformResult SingleShot::CleanUpAfterInvoke() { + ScopeLogger(); + if (dynamic_mode_) { + bool is_ok = true; + if (nullptr != tensor_data_out_handle_) { + int ret = ml_tensors_data_destroy(tensor_data_out_handle_); + if (ML_ERROR_NONE != ret) { + is_ok = false; + LoggerE("ml_tensors_data_destroy failed: %d (%s)", ret, get_error_message(ret)); + } else { + tensor_data_out_handle_ = nullptr; + } + } + + if (nullptr != tensor_info_out_handle_) { + int ret = ml_tensors_info_destroy(tensor_info_out_handle_); + if (ML_ERROR_NONE != ret) { + is_ok = false; + LoggerE("ml_tensors_info_destroy failed: %d (%s)", ret, get_error_message(ret)); + } else { + tensor_info_out_handle_ = nullptr; + } + } + if (!is_ok) { + return PlatformResult(ErrorCode::ABORT_ERR, "Internal SingleShot error"); + } + } + + return PlatformResult{}; +} PlatformResult SingleShot::GetValue(const std::string& name, std::string& value) { ScopeLogger(); diff --git a/src/ml/ml_singleshot.h b/src/ml/ml_singleshot.h index e456baf8..32a831e0 100644 --- a/src/ml/ml_singleshot.h +++ b/src/ml/ml_singleshot.h @@ -31,7 +31,7 @@ namespace ml { class SingleShot { public: - SingleShot(int id, ml_single_h handle); + SingleShot(int id, ml_single_h handle, bool dynamic_mode); SingleShot() = delete; // copy semantics SingleShot(const SingleShot&) = delete; @@ -43,8 +43,10 @@ class SingleShot { PlatformResult GetTensorsInfo(bool get_input_mode, ml_tensors_info_h* result); PlatformResult SetInputInfo(ml_tensors_info_h in_info); - // SingleShot::invoke() - + PlatformResult Invoke(ml_tensors_data_h in_data, ml_tensors_info_h in_info, + ml_tensors_data_h* out_data, ml_tensors_info_h* out_info, + bool* should_copy_data); + PlatformResult CleanUpAfterInvoke(); PlatformResult GetValue(const std::string& name, std::string& value); PlatformResult SetValue(const std::string& name, const std::string& value); @@ -53,8 +55,14 @@ class SingleShot { // SingleShot::close() private: + PlatformResult InvokeInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info); + PlatformResult InvokeDynamicInternal(ml_tensors_data_h in_data, ml_tensors_info_h in_info); const int id_; ml_single_h handle_; + const bool dynamic_mode_; + // below handles are reused by ml_single_invoke_fast when dynamic mode is off + ml_tensors_data_h tensor_data_out_handle_; + ml_tensors_info_h tensor_info_out_handle_; }; } // namespace ml diff --git a/src/ml/ml_tensors_data_manager.cc b/src/ml/ml_tensors_data_manager.cc index dd7d7747..949a390d 100644 --- a/src/ml/ml_tensors_data_manager.cc +++ b/src/ml/ml_tensors_data_manager.cc @@ -325,6 +325,22 @@ TensorsDataManager::~TensorsDataManager() { map_.clear(); }; +TensorsData* TensorsDataManager::CreateTensorsData(TensorsInfo* tensors_info, + ml_tensors_data_h tensors_data_handle) { + ScopeLogger(); + if (nullptr == tensors_info) { + LoggerE("Could not find tensor"); + return nullptr; + } + + std::lock_guard lock{map_and_next_id_mutex_}; + int id = nextId_++; + auto t = std::make_unique(tensors_data_handle, id, tensors_info); + map_[id] = std::move(t); + + return map_[id].get(); +} + TensorsData* TensorsDataManager::CreateTensorsData(TensorsInfo* tensors_info) { ScopeLogger(); if (nullptr == tensors_info) { diff --git a/src/ml/ml_tensors_data_manager.h b/src/ml/ml_tensors_data_manager.h index af1067cf..12f5da0e 100644 --- a/src/ml/ml_tensors_data_manager.h +++ b/src/ml/ml_tensors_data_manager.h @@ -100,6 +100,7 @@ class TensorsDataManager { ~TensorsDataManager(); TensorsData* CreateTensorsData(TensorsInfo* tensors_info); + TensorsData* CreateTensorsData(TensorsInfo* tensors_info, ml_tensors_data_h tensors_data_handle); TensorsData* GetTensorsData(int id); PlatformResult DisposeTensorsData(int id); diff --git a/src/ml/ml_tensors_info_manager.cc b/src/ml/ml_tensors_info_manager.cc index 0557ff89..46623df0 100644 --- a/src/ml/ml_tensors_info_manager.cc +++ b/src/ml/ml_tensors_info_manager.cc @@ -440,6 +440,15 @@ TensorsData* TensorsInfoManager::CreateTensorsData(TensorsInfo* tensors_info) { return tensors_data_manager_->CreateTensorsData(t_info); }; +TensorsData* TensorsInfoManager::CreateTensorsData(ml_tensors_info_h tensors_info_src, + ml_tensors_data_h tensors_data_src) { + ScopeLogger("tensors_info_src: [%p], tensors_data_src: [%p]", tensors_info_src, tensors_data_src); + + TensorsInfo* t_info = CreateTensorsInfo(tensors_info_src); + + return tensors_data_manager_->CreateTensorsData(t_info, tensors_data_src); +}; + TensorsData* TensorsInfoManager::CloneNativeTensorWithData(ml_tensors_info_h tensors_info_src, ml_tensors_data_h tensors_data_src) { ScopeLogger("tensors_info_src: [%p], tensors_data_src: [%p]", tensors_info_src, tensors_data_src); diff --git a/src/ml/ml_tensors_info_manager.h b/src/ml/ml_tensors_info_manager.h index 2a36d05a..38a03b17 100644 --- a/src/ml/ml_tensors_info_manager.h +++ b/src/ml/ml_tensors_info_manager.h @@ -84,6 +84,8 @@ class TensorsInfoManager { PlatformResult DisposeTensorsInfo(TensorsInfo* t); TensorsData* CreateTensorsData(TensorsInfo* tensors_info); + TensorsData* CreateTensorsData(ml_tensors_info_h tensors_info_src, + ml_tensors_data_h tensors_data_src); TensorsData* CloneNativeTensorWithData(ml_tensors_info_h tensors_info_src, ml_tensors_data_h tensors_data_src); -- 2.34.1