From: Rafal Walczyna Date: Wed, 13 Jan 2021 12:52:21 +0000 (+0100) Subject: [ML][Common] Add TensorsInfo getters / setters X-Git-Tag: submit/tizen/20210128.113801~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eb678fb6aa9112a689c1414dd079de1af9ee546c;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [ML][Common] Add TensorsInfo getters / setters ACR: TWDAPI-273 Methods added: TensorsInfo.getTensorName TensorsInfo.setTensorName TensorsInfo.getTensorType TensorsInfo.setTensorType TensorsInfo.getDimensions TensorsInfo.setDimensions Test code: var ti = new tizen.ml.TensorsInfo(); ti.addTensorInfo("tensor1", "UINT8", [1, 1]) console.log(ti.getTensorName(0)); ti.setTensorName(0, "changedName"); console.log(ti.getTensorName(0)); console.log(ti.getTensorType(0)); ti.setTensorType(0, "INT8"); console.log(ti.getTensorType(0)); console.log(ti.getDimensions(0)); ti.setDimensions(0, [2,4]); console.log(ti.getDimensions(0)); [Verification] Built successful, tested in Chrome Dev console. Change-Id: I197072bfbc48812fd44a00cfaceb09ee8928f1a1 Signed-off-by: Rafal Walczyna --- diff --git a/src/ml/js/ml_common.js b/src/ml/js/ml_common.js index 77c30eba..ad509401 100755 --- a/src/ml/js/ml_common.js +++ b/src/ml/js/ml_common.js @@ -156,7 +156,7 @@ TensorsInfo.prototype.addTensorInfo = function() { args.dimensions.forEach(function(d) { if (Number.isInteger(d) == false) { throw new WebAPIException( - WebAPIException.INVALID_VALUES_ERR, + WebAPIException.TYPE_MISMATCH_ERR, 'dimensions array has to contain only integers' ); } @@ -179,6 +179,12 @@ TensorsInfo.prototype.addTensorInfo = function() { } }; +var TensorsInfoGettersSettersValidExceptions = [ + 'AbortError', + 'InvalidValuesError', + 'NotSupportedError' +]; + TensorsInfo.prototype.clone = function() { throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); }; @@ -188,27 +194,224 @@ TensorsInfo.prototype.equals = function() { }; TensorsInfo.prototype.getDimensions = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + } + ]); + + if (!args.has.index) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: index is undefined' + ); + } + + var callArgs = { + index: args.index, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoGetDimensions', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGettersSettersValidExceptions, + AbortError + ); + } + return native_.getResultObject(result); }; +var TensorsInfoSetDimensionsExceptions = [ + 'InvalidValuesError', + 'TypeMismatchError', + 'NotSupportedError', + 'AbortError' +]; + TensorsInfo.prototype.setDimensions = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + }, + { + name: 'dimensions', + type: types_.ARRAY + } + ]); + + args.dimensions.forEach(function(d) { + if (Number.isInteger(d) == false) { + throw new WebAPIException( + WebAPIException.TYPE_MISMATCH_ERR, + 'dimensions array has to contain only integers' + ); + } + }); + + var callArgs = { + index: args.index, + dimensions: args.dimensions, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoSetDimensions', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoSetDimensionsExceptions, + AbortError + ); + } }; TensorsInfo.prototype.getTensorName = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + } + ]); + + if (!args.has.index) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: index is undefined' + ); + } + + var callArgs = { + index: args.index, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoGetTensorName', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGettersSettersValidExceptions, + AbortError + ); + } + return native_.getResultObject(result); }; TensorsInfo.prototype.setTensorName = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + }, + { + name: 'name', + type: types_.STRING + } + ]); + + if (!args.has.index) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: index is undefined' + ); + } + + if (!args.has.name) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: name is undefined' + ); + } + + var callArgs = { + index: args.index, + name: args.name, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoSetTensorName', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGettersSettersValidExceptions, + AbortError + ); + } }; TensorsInfo.prototype.getTensorType = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + } + ]); + + if (!args.has.index) { + throw new WebAPIException( + WebAPIException.INVALID_VALUES_ERR, + 'Invalid parameter: index is undefined' + ); + } + + var callArgs = { + index: args.index, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoGetTensorType', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoGettersSettersValidExceptions, + AbortError + ); + } + return native_.getResultObject(result); }; +var TensorsInfoSetTensorTypeValidExceptions = [ + 'AbortError', + 'InvalidValuesError', + 'NotSupportedError', + 'TypeMismatchError' +]; + TensorsInfo.prototype.setTensorType = function() { - throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented'); + var args = validator_.validateArgs(arguments, [ + { + name: 'index', + type: types_.LONG + }, + { + name: 'type', + type: types_.ENUM, + values: Object.values(TensorType) + } + ]); + + var callArgs = { + index: args.index, + type: args.type, + tensorsInfoId: this._id + }; + + var result = native_.callSync('MLTensorsInfoSetTensorType', callArgs); + + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + TensorsInfoSetTensorTypeValidExceptions, + AbortError + ); + } }; TensorsInfo.prototype.getTensorSize = function() { diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index 301333e7..4250a13b 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -77,6 +77,13 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLTensorsInfoCountGetter); REGISTER_METHOD(MLTensorsInfoAddTensorInfo); REGISTER_METHOD(MLTensorsInfoCreate); + REGISTER_METHOD(MLTensorsInfoGetDimensions); + REGISTER_METHOD(MLTensorsInfoSetDimensions); + REGISTER_METHOD(MLTensorsInfoGetTensorName); + REGISTER_METHOD(MLTensorsInfoSetTensorName); + REGISTER_METHOD(MLTensorsInfoGetTensorType); + REGISTER_METHOD(MLTensorsInfoSetTensorType); + // Common ML API end // Single API begin @@ -152,6 +159,57 @@ void MlInstance::MLTensorsInfoCountGetter(const picojson::value& args, picojson: ReportSuccess(val, out); } +PlatformResult GetDimensionsFromJsonArray(picojson::array& dim, + unsigned int dimensions[ML_TENSOR_RANK_LIMIT]) { + ScopeLogger(); + bool foundValidValue = false; + unsigned int validDimensions[ML_TENSOR_RANK_LIMIT]; + for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { + validDimensions[i] = 1; + } + int dimSize = ML_TENSOR_RANK_LIMIT; + if (dim.size() <= ML_TENSOR_RANK_LIMIT) { + dimSize = dim.size(); + } else { + LoggerD("Provided dimensions array is bigger than supported"); + } + + for (int i = dimSize - 1; i >= 0; i--) { + auto& d = dim[i]; + if (!d.is()) { + LoggerE("dimensions array contains an invalid value: %s", d.serialize().c_str()); + return PlatformResult(ErrorCode::INVALID_VALUES_ERR, + "dimensions array contains an invalid value"); + } + + int v = static_cast(d.get()); + if (v <= 0) { + // dimensions with zeros at the end are valid + // 0 after valid value is not accepted + if (foundValidValue || (v < 0)) { + LoggerE("dimensions array contains non-positive value: %d", v); + return PlatformResult(ErrorCode::INVALID_VALUES_ERR, + "dimensions array contains non-positive value"); + } + continue; + } + + foundValidValue = true; + validDimensions[i] = static_cast(v); + } + + if (!foundValidValue) { + LoggerE("No valid values found in dimensions array"); + return PlatformResult(ErrorCode::INVALID_VALUES_ERR, + "dimensions array contains invalid values"); + } + + for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { + dimensions[i] = validDimensions[i]; + } + return PlatformResult(ErrorCode::NO_ERROR); +} + void MlInstance::MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out) { ScopeLogger("args: %s", args.serialize().c_str()); CHECK_ARGS(args, kTensorsInfoId, double, out); @@ -184,35 +242,194 @@ void MlInstance::MLTensorsInfoAddTensorInfo(const picojson::value& args, picojso LoggerD("name: %s", name.c_str()); } - unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {1, 1, 1, 1}; - - // CHECK_ARGS has already validated type of kDimensions + unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {}; auto dim = args.get(kDimensions).get(); - int i = 0; - for (const auto& d : dim) { - if (i >= ML_TENSOR_RANK_LIMIT) { - LoggerD("Provided dimensions array is bigger than supported"); + result = GetDimensionsFromJsonArray(dim, dimensions); + if (!result) { + LogAndReportError(result, &out); + return; + } + + result = tensorsInfo->AddTensorInfo(name, tensorTypeEnum, dimensions); + if (!result) { + LogAndReportError(result, &out); + return; + } + + ReportSuccess(out); +} + +void MlInstance::MLTensorsInfoGetDimensions(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + int index = static_cast(args.get(kIndex).get()); + unsigned int dim[ML_TENSOR_RANK_LIMIT]; + PlatformResult result = tensorsInfo->NativeGetTensorDimensions(index, dim); + if (!result) { + LogAndReportError(result, &out); + return; + } + picojson::array array = picojson::array{}; + for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { + if (0 == dim[i]) { break; } + array.push_back(picojson::value{static_cast(dim[i])}); + } + picojson::value val = picojson::value{array}; + ReportSuccess(val, out); +} - if (!d.is()) { - LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, - "dimensions array contains an invalid value"), - &out, - ("dimensions array contains an invalid value: %s", d.serialize().c_str())); - return; - } +void MlInstance::MLTensorsInfoSetDimensions(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + CHECK_ARGS(args, kDimensions, picojson::array, out); - dimensions[i] = static_cast(d.get()); - i++; + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; } - result = tensorsInfo->AddTensorInfo(name, tensorTypeEnum, dimensions); + unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {}; + auto dim = args.get(kDimensions).get(); + PlatformResult result = GetDimensionsFromJsonArray(dim, dimensions); + if (!result) { + LogAndReportError(result, &out); + return; + } + + int index = static_cast(args.get(kIndex).get()); + result = tensorsInfo->NativeSetTensorDimensions(index, dimensions); if (!result) { LogAndReportError(result, &out); return; } + ReportSuccess(out); +} +void MlInstance::MLTensorsInfoGetTensorName(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + int index = static_cast(args.get(kIndex).get()); + std::string name; + PlatformResult result = tensorsInfo->NativeGetTensorName(index, &name); + if (!result) { + LogAndReportError(result, &out); + return; + } + picojson::value val = picojson::value{name}; + ReportSuccess(val, out); +} + +void MlInstance::MLTensorsInfoSetTensorName(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + CHECK_ARGS(args, kName, std::string, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + + int index = static_cast(args.get(kIndex).get()); + const std::string& name = args.get(kName).get(); + PlatformResult result = tensorsInfo->NativeSetTensorName(index, name); + if (!result) { + LogAndReportError(result, &out); + return; + } + ReportSuccess(out); +} + +void MlInstance::MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + + int index = static_cast(args.get(kIndex).get()); + ml_tensor_type_e tensorTypeEnum = ML_TENSOR_TYPE_UNKNOWN; + PlatformResult result = tensorsInfo->NativeGetTensorType(index, &tensorTypeEnum); + if (!result) { + LogAndReportError(result, &out); + return; + } + std::string tensorTypeString; + result = types::TensorTypeEnum.getName(tensorTypeEnum, &tensorTypeString); + if (!result) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Error getting name of TensorType"), + &out, + ("TensorTypeEnum.getName() failed, error: %s", result.message().c_str())); + return; + } + + picojson::value val = picojson::value{tensorTypeString}; + ReportSuccess(val, out); +} + +void MlInstance::MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + CHECK_ARGS(args, kTensorsInfoId, double, out); + CHECK_ARGS(args, kIndex, double, out); + CHECK_ARGS(args, kType, std::string, out); + + int tensorsInfoId = static_cast(args.get(kTensorsInfoId).get()); + TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId); + if (nullptr == tensorsInfo) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out, + ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId)); + return; + } + + const std::string& tensorType = args.get(kType).get(); + ml_tensor_type_e tensorTypeEnum = ML_TENSOR_TYPE_UNKNOWN; + PlatformResult result = types::TensorTypeEnum.getValue(tensorType, &tensorTypeEnum); + if (!result) { + LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Error getting value of TensorType"), + &out, + ("TensorTypeEnum.getValue() failed, error: %s", result.message().c_str())); + return; + } + + int index = static_cast(args.get(kIndex).get()); + result = tensorsInfo->NativeSetTensorType(index, tensorTypeEnum); + if (!result) { + LogAndReportError(result, &out); + return; + } ReportSuccess(out); } // Common ML API end diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index f8141a91..a461becb 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -40,6 +40,12 @@ class MlInstance : public common::ParsedInstance { void MLTensorsInfoCountGetter(const picojson::value& args, picojson::object& out); void MLTensorsInfoCreate(const picojson::value& args, picojson::object& out); void MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out); + void MLTensorsInfoGetDimensions(const picojson::value& args, picojson::object& out); + void MLTensorsInfoSetDimensions(const picojson::value& args, picojson::object& out); + void MLTensorsInfoGetTensorName(const picojson::value& args, picojson::object& out); + void MLTensorsInfoSetTensorName(const picojson::value& args, picojson::object& out); + void MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out); + void MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out); TensorsInfoManager tensors_info_manager_; // Common ML API end