[ML][Common] Add TensorsData.getTensorRawData location/size support 02/252702/5
authorRafal Walczyna <r.walczyna@samsung.com>
Mon, 1 Feb 2021 14:55:36 +0000 (15:55 +0100)
committerRafal Walczyna <r.walczyna@samsung.com>
Wed, 10 Feb 2021 14:22:04 +0000 (15:22 +0100)
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 <r.walczyna@samsung.com>
src/ml/ml_instance.cc
src/ml/ml_tensors_data_manager.cc
src/ml/ml_tensors_data_manager.h
src/ml/ut/tensor_raw_data.cc

index d86fe9fc61439b769c6a0b10a5ee90da45bcf1ca..20c6ec8235153af6ac1ed7fa375718f293e7f154 100644 (file)
@@ -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<picojson::array>(), 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<picojson::array>(), 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<std::uint8_t> 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;
index aa944643dd34db6b214e72738e22e2ea85f5aee5..77711b9d0805e31c2374b5b70f90cc61242d69dc 100644 (file)
@@ -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<uint8_t*>(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<uint8_t[]>(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<uint8_t*>(data);
-  tensor_raw_data->size_in_bytes = data_size;
-
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
index f07a739687505bf23346063efab161ac6045c3f6..2ebc82e39dfb0c3fcbf3af09b437d396315c64ef 100644 (file)
@@ -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 {
index ae980113b6dea038cd609020302fc9dc5b26e158..6f2f795636c694e131417ab9bc23eee05f5d8c9f 100644 (file)
@@ -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";