From: Rafal Walczyna Date: Mon, 1 Feb 2021 14:55:36 +0000 (+0100) Subject: [ML][Common] Add TensorsData.getTensorRawData location/size support X-Git-Tag: submit/tizen/20210217.032056~6^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dc6075789fef30db5b8c78227ae9e418fdcd95e0;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [ML][Common] Add TensorsData.getTensorRawData location/size support ACR: TWDAPI-273 Test code: var ti = new tizen.ml.TensorsInfo(); ti.addTensorInfo("tensor", "INT16", [3, 3]) var td = ti.getTensorsData(); td.setTensorRawData(0, [1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 0], [3, 3]) var data = td.getTensorRawData(0, [1, 1], []) console.log(data) console.log(data.data) // Int16Array(4) [5, 6, 8, 9] // 5, 6 // 8, 9 data = td.getTensorRawData(0, [0, 0], [3, 1]) console.log(data) console.log(data.data) // Int16Array(3) [1, 2, 3] // 1, 2, 3 data = td.getTensorRawData(0, [2, 0], [1, 2]) console.log(data) console.log(data.data) // Int16Array(2) [3, 6] // 3 // 6 data = td.getTensorRawData(0, [], [1, 1]) console.log(data) console.log(data.data) // Int16Array(1) [1] data = td.getTensorRawData(0, [0, 1], [-1,1]) console.log(data) console.log(data.data) // Int16Array(1) [3] (4, 5, 6) [Verification] Built successful. Tested in Chrome Dev console. Change-Id: Ife781390e8806309bc72963f43a5d001bcd2f5c2 Signed-off-by: Rafal Walczyna --- diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index d86fe9fc..20c6ec82 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -583,11 +583,32 @@ void MlInstance::MLTensorsDataGetTensorRawData(const picojson::value& args, pico ("Could not find TensorsData handle with given id: %d", tensor_data_id)); return; } - // TODO: validate location and size - will be done in future commit - unsigned int location[ML_TENSOR_RANK_LIMIT]; - unsigned int size[ML_TENSOR_RANK_LIMIT]; + + unsigned int location[ML_TENSOR_RANK_LIMIT] = {}; + PlatformResult result = + util::GetLocationFromJsonArray(args.get(kLocation).get(), location); + if (!result) { + LogAndReportError(result, &out); + return; + } + + unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {}; + result = tensors_data->GetTensorsInfo()->NativeGetTensorDimensions(index, dimensions); + if (!result) { + LogAndReportError(result, &out); + return; + } + + unsigned int size[ML_TENSOR_RANK_LIMIT] = {}; + result = util::GetSizeFromJsonArray(args.get(kSize).get(), location, dimensions, + size); + if (!result) { + LogAndReportError(result, &out); + return; + } + TensorRawData raw_data; - PlatformResult result = tensors_data->GetTensorRawData(index, location, size, &raw_data); + result = tensors_data->GetTensorRawData(index, location, size, &raw_data); if (!result) { LogAndReportError(result, &out); return; @@ -684,8 +705,8 @@ void MlInstance::MLTensorsDataSetTensorRawData(const picojson::value& args, pico std::vector buffer; common::decode_binary_from_string(str_buffer, buffer); - TensorRawData rawData{.data = buffer.data(), .size_in_bytes = buffer.size()}; - result = tensors_data->SetTensorRawData(index, location, size, rawData); + TensorRawData raw_data{buffer.data(), buffer.size()}; + result = tensors_data->SetTensorRawData(index, location, size, raw_data); if (!result) { LogAndReportError(result, &out); return; diff --git a/src/ml/ml_tensors_data_manager.cc b/src/ml/ml_tensors_data_manager.cc index aa944643..77711b9d 100644 --- a/src/ml/ml_tensors_data_manager.cc +++ b/src/ml/ml_tensors_data_manager.cc @@ -66,27 +66,97 @@ PlatformResult TensorsData::GetTensorRawData(int index, unsigned int location[ML unsigned int size[ML_TENSOR_RANK_LIMIT], TensorRawData* tensor_raw_data) { ScopeLogger("id_: %d, index: %d", id_, index); + if (nullptr == tensor_raw_data) { LoggerE("Invalid tensor_raw_data"); return PlatformResult(ErrorCode::ABORT_ERR); } - void* data; + + void* void_data; size_t data_size; - PlatformResult result = NativeGetTensorData(index, &data, &data_size); + PlatformResult result = NativeGetTensorData(index, &void_data, &data_size); if (!result) { return result; } - // TODO: add support for location and size - will be done in future commit + uint8_t* data = static_cast(void_data); // Dimensions of whole tensor unsigned int dim[ML_TENSOR_RANK_LIMIT]; + // Dimensions of expected tensors relative to location coordiantes + unsigned int size_rel[ML_TENSOR_RANK_LIMIT]; + result = tensors_info_->NativeGetTensorDimensions(index, dim); if (!result) { return result; } + // Check if update is partial due to location change + bool partial = false; for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { - tensor_raw_data->shape[i] = dim[i]; + if (location[i] >= dim[i]) { + // Input data starts outside of current data + LoggerE("Requested data location is invalid on [%d]: %u", i, location[i]); + return PlatformResult{ErrorCode::INVALID_VALUES_ERR, "Requested data location is invalid"}; + } else if (location[i] != 0) { + partial = true; + } + } + + uint8_t bytes_per_element = tensors_info_->GetBytesPerElement(index); + size_t data_to_be_returned_size = bytes_per_element; + + // Check if data will fit in TensorData and calculate dimensions + // of returned part, also check if update is partial due to size change + for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { + size_rel[i] = location[i] + size[i]; + if (size_rel[i] < dim[i]) { + partial = true; + } else { + size_rel[i] = dim[i]; + } + data_to_be_returned_size *= (size_rel[i] - location[i]); + } + + if (partial) { + LoggerD("Partial get of tensor data"); + // Allocate data, it will be freed on TensorRawData destruction + auto new_data = std::make_unique(data_to_be_returned_size); + size_t position_in_new_data = 0; + + size_t delta2 = dim[1] * dim[0] * bytes_per_element; + size_t delta1 = dim[0] * bytes_per_element; + + size_t position = location[3] * dim[2] * delta2; + for (unsigned int i = location[3]; i < size_rel[3]; i++) { + position += (location[2]) * delta2; + for (unsigned int j = location[2]; j < size_rel[2]; j++) { + position += (location[1]) * delta1; + for (unsigned int k = location[1]; k < size_rel[1]; k++) { + position += location[0] * bytes_per_element; + size_t length = (size_rel[0] - location[0]) * bytes_per_element; + mempcpy(&new_data[position_in_new_data], &data[position], length); + position_in_new_data += length; + position += (dim[0] - location[0]) * bytes_per_element; + } + position += (dim[1] - size_rel[1]) * delta1; + } + position += (dim[2] - size_rel[2]) * delta2; + } + if (position_in_new_data != data_to_be_returned_size) { + LoggerE("Error while copying data, expected: %zu, got: %zu", data_to_be_returned_size, + position_in_new_data); + return PlatformResult{ErrorCode::ABORT_ERR, "Internal error while fetching the data"}; + } + tensor_raw_data->data = new_data.release(); + tensor_raw_data->size_in_bytes = position_in_new_data; + tensor_raw_data->SetOwnership(true); + } else { + tensor_raw_data->data = data; + tensor_raw_data->size_in_bytes = data_size; + } + + for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) { + tensor_raw_data->shape[i] = size_rel[i] - location[i]; } result = types::TensorTypeEnum.getName(this->GetTensorType(index), &tensor_raw_data->type_str); @@ -94,9 +164,6 @@ PlatformResult TensorsData::GetTensorRawData(int index, unsigned int location[ML return result; } - tensor_raw_data->data = static_cast(data); - tensor_raw_data->size_in_bytes = data_size; - return PlatformResult(ErrorCode::NO_ERROR); } diff --git a/src/ml/ml_tensors_data_manager.h b/src/ml/ml_tensors_data_manager.h index f07a7396..2ebc82e3 100644 --- a/src/ml/ml_tensors_data_manager.h +++ b/src/ml/ml_tensors_data_manager.h @@ -32,11 +32,34 @@ namespace ml { class TensorsInfo; struct TensorRawData { - // TensorRawData does not take ownership of data, remember to handle it outside - uint8_t* data; + // use SetOwnership() to automatically free data* on object destruction + TensorRawData() { + } + + TensorRawData(uint8_t* d, size_t s) : data(d), size_in_bytes(s) { + } + + ~TensorRawData() { + ScopeLogger(); + if (has_ownership_) { + LoggerD("Freeing data"); + delete[] data; + data = nullptr; + } + } + + void SetOwnership(bool v) { + ScopeLogger("v: %s", v ? "true" : "false"); + has_ownership_ = v; + } + + uint8_t* data = nullptr; size_t size_in_bytes; std::string type_str; unsigned int shape[ML_TENSOR_RANK_LIMIT]; + + private: + bool has_ownership_ = false; }; class TensorsData { diff --git a/src/ml/ut/tensor_raw_data.cc b/src/ml/ut/tensor_raw_data.cc index ae980113..6f2f7956 100644 --- a/src/ml/ut/tensor_raw_data.cc +++ b/src/ml/ut/tensor_raw_data.cc @@ -82,12 +82,13 @@ TEST_F(MlTensorRawDataTest, SetTensorRawDataFull) { unsigned int location[] = {0, 0, 0, 0}; unsigned int size[] = {3, 2, 2, 1}; uint8_t arr_in[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 12}; + TensorRawData raw_data_set{arr_in, 12}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 1}; @@ -119,12 +120,13 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData1) { unsigned int location[] = {0, 0, 0, 0}; unsigned int size[] = {3, 2, 1, 1}; uint8_t arr_in[] = {1, 2, 3, 4, 5, 6}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 6}; + TensorRawData raw_data_set{arr_in, 6}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 1}; @@ -157,12 +159,14 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData2) { unsigned int location[] = {0, 0, 1, 0}; unsigned int size[] = {3, 2, 1, 1}; uint8_t arr_in[] = {1, 2, 3, 4, 5, 6}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 6}; + TensorRawData raw_data_set{arr_in, 6}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 1}; @@ -195,12 +199,15 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData3) { unsigned int location[] = {1, 1, 0, 0}; unsigned int size[] = {2, 1, 1, 1}; uint8_t arr_in[] = {1, 2}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 2}; + TensorRawData raw_data_set{arr_in, 2}; + raw_data_set.data = arr_in; + raw_data_set.size_in_bytes = 2; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 1}; @@ -239,12 +246,13 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData4) { unsigned int location[] = {1, 0, 1, 1}; unsigned int size[] = {1, 2, 1, 1}; uint8_t arr_in[] = {1, 2}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 2}; + TensorRawData raw_data_set{arr_in, 2}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 2}; @@ -283,12 +291,13 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData5) { unsigned int location[] = {2, 1, 1, 1}; unsigned int size[] = {1, 1, 1, 1}; int arr_in[] = {-34}; - TensorRawData raw_data_set = {.data = (uint8_t*)arr_in, .size_in_bytes = 4}; + TensorRawData raw_data_set{(uint8_t*)arr_in, 4}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_TRUE(res) << "SetTensorRawData failed"; TensorRawData raw_data_get; - res = tensors_data->GetTensorRawData(0, location, dim, &raw_data_get); + unsigned int location_get[] = {0, 0, 0, 0}; + res = tensors_data->GetTensorRawData(0, location_get, dim, &raw_data_get); ASSERT_TRUE(res) << "GetTensorRawData failed"; unsigned int expected_dim[] = {3, 2, 2, 2}; @@ -317,7 +326,7 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData6) { unsigned int location[] = {4, 0, 0, 0}; unsigned int size[] = {1, 1, 1, 1}; uint8_t arr_in[1] = {}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 1}; + TensorRawData raw_data_set{arr_in, 1}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_FALSE(res) << "SetTensorRawData should fail"; ASSERT_EQ(res.error_code(), ErrorCode::INVALID_VALUES_ERR) << "Invalid error code"; @@ -334,7 +343,7 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData7) { unsigned int location[] = {0, 0, 0, 0}; unsigned int size[] = {2, 1, 1, 1}; uint8_t arr_in[1] = {}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 1}; + TensorRawData raw_data_set{arr_in, 1}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_FALSE(res) << "SetTensorRawData should fail"; ASSERT_EQ(res.error_code(), ErrorCode::INVALID_VALUES_ERR) << "Invalid error code"; @@ -351,7 +360,7 @@ TEST_F(MlTensorRawDataTest, SetTensorRawData8) { unsigned int location[] = {0, 0, 0, 0}; unsigned int size[] = {1, 1, 1, 1}; uint8_t arr_in[400] = {}; - TensorRawData raw_data_set = {.data = arr_in, .size_in_bytes = 400}; + TensorRawData raw_data_set{arr_in, 400}; PlatformResult res = tensors_data->SetTensorRawData(0, location, size, raw_data_set); ASSERT_FALSE(res) << "SetTensorRawData should fail"; ASSERT_EQ(res.error_code(), ErrorCode::INVALID_VALUES_ERR) << "Invalid error code";