[neurun] Define operand usage enum and check exception (#2213)
author오형석/동작제어Lab(SR)/Staff Engineer/삼성전자 <hseok82.oh@samsung.com>
Wed, 8 Aug 2018 22:18:15 +0000 (07:18 +0900)
committer박세희/동작제어Lab(SR)/Principal Engineer/삼성전자 <saehie.park@samsung.com>
Wed, 8 Aug 2018 22:18:15 +0000 (07:18 +0900)
Define operand usage: model input, constant, operation output
Check exception: operand usage conflict

Signed-off-by: Hyeongseok Oh <hseok82.oh@samsung.com>
runtimes/neurun/src/frontend/model.cc
runtimes/neurun/src/internal/Model.cc
runtimes/neurun/src/internal/Model.h

index ea51559..446b977 100644 (file)
@@ -110,6 +110,10 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in
 
   using internal::tflite::operand::CachedData;
 
+  if (!obj.setAsConstant())
+  {
+    return ANEURALNETWORKS_BAD_DATA;
+  }
   obj.data<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length);
 
   return ANEURALNETWORKS_NO_ERROR;
@@ -134,6 +138,10 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model,
 
   using internal::tflite::operand::ExternalData;
 
+  if (!obj.setAsConstant())
+  {
+    return ANEURALNETWORKS_BAD_DATA;
+  }
   obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(memory->base() + offset), length);
 
   return ANEURALNETWORKS_NO_ERROR;
@@ -155,6 +163,26 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
     return ANEURALNETWORKS_BAD_STATE;
   }
 
+  for (uint32_t i = 0; i < outputCount; i++)
+  {
+    // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI
+    //      functions such as ANeuralNetworksModel_setOperandValue use int to represent operand
+    //      index
+    //
+    //      ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent
+    //      operand
+    //      index.
+    //
+    //      Below, static_cast<int>(...) is introduced to eliminate compiler warning.
+    const internal::tflite::operand::Index ind{static_cast<int>(outputs[i])};
+    auto &obj = model->deref().operands().at(ind);
+
+    if (!obj.setAsOperationOutput())
+    {
+      return ANEURALNETWORKS_BAD_DATA;
+    }
+  }
+
   switch (type)
   {
     case ANEURALNETWORKS_CONV_2D:
@@ -303,6 +331,26 @@ int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
     return ANEURALNETWORKS_BAD_STATE;
   }
 
+  for (uint32_t i = 0; i < outputCount; i++)
+  {
+    // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI
+    //      functions such as ANeuralNetworksModel_setOperandValue use int to represent operand
+    //      index
+    //
+    //      ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent
+    //      operand
+    //      index.
+    //
+    //      Below, static_cast<int>(...) is introduced to eliminate compiler warning.
+    const internal::tflite::operand::Index ind{static_cast<int>(outputs[i])};
+    auto &obj = model->deref().operands().at(ind);
+
+    if (!obj.setAsOperationOutput())
+    {
+      return ANEURALNETWORKS_BAD_DATA;
+    }
+  }
+
   switch (type)
   {
     default:
@@ -335,12 +383,25 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u
   {
     const ::internal::tflite::operand::Index ind{static_cast<int>(inputs[n])};
     model->deref().inputs.emplace_back(ind);
+
+    auto &obj = model->deref().operands().at(ind);
+    if (!obj.setAsModelInput())
+    {
+      return ANEURALNETWORKS_BAD_DATA;
+    }
   }
 
   for (uint32_t n = 0; n < outputCount; ++n)
   {
     const ::internal::tflite::operand::Index ind{static_cast<int>(outputs[n])};
     model->deref().outputs.emplace_back(ind);
+
+    auto &obj = model->deref().operands().at(ind);
+    // Model output cannot become model input
+    if (obj.isModelInput())
+    {
+      return ANEURALNETWORKS_BAD_DATA;
+    }
   }
 
   return ANEURALNETWORKS_NO_ERROR;
index cd0e06d..93fc365 100644 (file)
@@ -64,6 +64,30 @@ namespace tflite
 namespace operand
 {
 
+bool Object::setUsage(const OperandUsage usage)
+{
+  if (usageIsDefined() && (_usage != usage))
+  {
+    // Already set as different type
+    return false;
+  }
+
+  _usage = usage;
+
+  return true;
+}
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
 Index Set::append(const Shape &shape)
 {
   int32_t index = _objects.size();
index b8fbf0b..60a695e 100644 (file)
@@ -147,19 +147,34 @@ namespace tflite
 namespace operand
 {
 
+// Operand usage should be exact one of these
+enum class OperandUsage
+{
+  NOT_DEFINED,
+  MODEL_INPUT,
+  CONSTANT,
+  OPERATION_OUTPUT,
+};
+
 class Object
 {
 public:
-  explicit Object(const Shape &shape) : _shape{shape}
+  explicit Object(const Shape &shape) : _shape{shape}, _usage{OperandUsage::NOT_DEFINED}
   {
     // DO NOTHING
   }
 
 public:
   const Shape &shape(void) const { return _shape; }
+  bool setAsConstant() { return setUsage(OperandUsage::CONSTANT); }
+  bool setAsModelInput() { return setUsage(OperandUsage::MODEL_INPUT); }
+  bool setAsOperationOutput() { return setUsage(OperandUsage::OPERATION_OUTPUT); }
+  bool usageIsDefined(void) const { return _usage != OperandUsage::NOT_DEFINED; }
+  bool isModelInput(void) const { return _usage == OperandUsage::MODEL_INPUT; }
 
 private:
   void data(std::unique_ptr<Data> &&data) { _data = std::move(data); }
+  bool setUsage(OperandUsage usage);
 
 public:
   const Data &data(void) const { return *_data; }
@@ -183,6 +198,7 @@ public:
 private:
   const Shape _shape;
   std::unique_ptr<Data> _data;
+  OperandUsage _usage;
 };
 
 } // namespace operand