Subgraph data conversion at boundaries
authorYuan Zhao <yuanzhao@ti.com>
Tue, 29 Oct 2019 07:14:54 +0000 (02:14 -0500)
committerYuan Zhao <yuanzhao@ti.com>
Thu, 31 Oct 2019 02:54:46 +0000 (21:54 -0500)
- Data layout: NCHW <-> NHWC
- Data type: 8-bit quantized <-> float
- MCT-1222

tidl_api/Makefile
tidl_api/inc/subgraph_data_conv.h [moved from tidl_api/src/subgraph_data_conv.h with 94% similarity]
tidl_api/inc/subgraph_runtime.h
tidl_api/src/subgraph_data_conv.cpp [new file with mode: 0644]
tidl_api/src/subgraph_runtime.cpp

index 988cdc94f7c6706a1057612a3c1e5edb20c61f2b..4dc298b74f345a7cfddd458fb961dc530ceb1335 100644 (file)
@@ -41,7 +41,7 @@ AR = ar
 SRCS = ocl_device.cpp configuration_parser.cpp configuration.cpp\
           executor.cpp execution_object.cpp trace.cpp util.cpp \
        execution_object_pipeline.cpp \
-       subgraph_runtime.cpp
+       subgraph_runtime.cpp subgraph_data_conv.cpp
 SRCS_IMGUTIL = imgutil.cpp
 SRCS_PYBIND  = pybind_eo.cpp pybind_eop.cpp pybind_executor.cpp \
                           pybind_configuration.cpp pybind_helpers.cpp
similarity index 94%
rename from tidl_api/src/subgraph_data_conv.h
rename to tidl_api/inc/subgraph_data_conv.h
index 24920fc9b76bfac6ec7e3299a7e3a76aefe03f48..49b4315ef58a156a9cc75452870dae7009266dd0 100644 (file)
@@ -26,6 +26,9 @@
  *  THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
+#include <stdint.h>
+#include <vector>
+
 namespace tidl {
 
 /* @class SubgraphDataConv
@@ -73,10 +76,10 @@ class SubgraphDataConv
         //! @param None
         SubgraphDataConv() {}
 
-        SubgraphDataConv(const vector<bool>& is_signed,
-                         const vector<float>& scaleQ,
-                         const vector<bool>& is_NCHW,
-                         const vector<int>& dims
+        SubgraphDataConv(const std::vector<bool>& is_signed,
+                         const std::vector<float>& scaleQ,
+                         const std::vector<bool>& is_NCHW,
+                         const std::vector<int>& dims
                         ) : is_signed_m(is_signed), scaleQ_m(scaleQ),
                             is_NCHW_m(is_NCHW), dims_m(dims)
                         {}
@@ -99,7 +102,7 @@ class SubgraphDataConv
         //!        by TIDL
         //! @param in floating point vector input to quantize
         //! @param out 8-bit Quantized output (quantized from in)
-        void ScaleQuant(const std::vector<float*>& in, uint8_t* out);
+        void ScaleQuant(const std::vector<float*>& in, uint8_t* out) const;
 
         //! @brief De-Quantizes 8-bit Quantized {in} to floating point {out}
         //!        and transposes buffer from NCHW to NHWC format (if needed),
@@ -107,7 +110,7 @@ class SubgraphDataConv
         //!        tensor, as expected by external tensors
         //! @param in 8-bit Quantized input to De-Quantize
         //! @param out floating point output (De-Quantized from in)
-        void ScaleDequant(const uint8_t *in, std::vector<float*>& out);
+        void ScaleDequant(const uint8_t *in, std::vector<float*>& out) const;
 
     private:
         //! if tensor needs to be evaluated as signed char
@@ -123,6 +126,6 @@ class SubgraphDataConv
 
         //! flattened 4d dims of external tensors
         std::vector<int> dims_m;
-}
+};
 
 }  // namespace tidl
index 09cf970779195274db496c9b0617f1b7ab3ba1a7..a38973eee8a7a2aa4785c2d9a7be8963ec8e1e88 100644 (file)
@@ -33,6 +33,7 @@
 #include <mutex>
 #include <condition_variable>
 #include "execution_object_pipeline.h"
+#include "subgraph_data_conv.h"
 
 
 namespace tidl {
@@ -106,8 +107,8 @@ class ResM {
     void                     FreeEOP(uint32_t subgraph_id,
                                      ExecutionObjectPipeline* eop);
     Configuration&           GetConfiguration(uint32_t subgraph_id);
-    //const SubgraphDataConv&        GetInConv(uint32_t subgraph_id);
-    //const SubgraphDataConv&        GetOutConv(uint32_t subgraph_id);
+    const SubgraphDataConv&  GetInConv(uint32_t subgraph_id);
+    const SubgraphDataConv&  GetOutConv(uint32_t subgraph_id);
 
 
   private:
@@ -135,6 +136,8 @@ class ResM {
     std::vector<Executor*> es_m;
     std::vector<Executor*> e2s_m;
     std::vector<ResEOP> *eops_m;
+    std::vector<SubgraphDataConv*> in_conv_m;
+    std::vector<SubgraphDataConv*> out_conv_m;
 };
 
 } // namespace tidl
diff --git a/tidl_api/src/subgraph_data_conv.cpp b/tidl_api/src/subgraph_data_conv.cpp
new file mode 100644 (file)
index 0000000..d8cc11f
--- /dev/null
@@ -0,0 +1,142 @@
+/******************************************************************************
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *      * Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ *      * Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ *      * Neither the name of Texas Instruments Incorporated nor the
+ *        names of its contributors may be used to endorse or promote products
+ *        derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "subgraph_data_conv.h"
+
+using namespace tidl;
+
+
+static inline uint8_t QuantizeValue(float v, float Q, int vmin, int vmax)
+{
+  // scale
+  int32_t qv = (int32_t) (v * Q);
+  // saturate
+  qv = qv < vmin ? vmin : qv;
+  qv = qv > vmax ? vmax : qv;
+  return (uint8_t) qv;
+}
+
+static inline float DequantizeValue(uint8_t v, float Q_inv, bool S)
+{
+  // interpret sign
+  int32_t sv = S ? ((int32_t)(int8_t) v) : ((int32_t) v);
+  // scale
+  return sv * Q_inv;
+}
+
+// Gets 1-d index for 4-d buffer[d][c][b][a]
+static inline int GetIndex(int d, int c, int b, int a,
+                           int D, int C, int B, int A)
+{
+    return a + A*(b + B*(c + C*d));
+}
+
+
+void SubgraphDataConv::EstScaleQuant(const std::vector<float*>& in)
+{
+  // TODO
+}
+
+void SubgraphDataConv::EstScaleDequant(const std::vector<float*>& out)
+{
+  // TODO
+}
+
+
+void
+SubgraphDataConv::ScaleQuant(const std::vector<float*>& in, uint8_t* out)
+const
+{
+  int offset = 0;
+  for (uint32_t d = 0; d < is_NCHW_m.size(); d++)
+  {
+    float Q     = scaleQ_m[d];
+    int   N     = dims_m[4 * d + 0];
+    int   C     = dims_m[4 * d + 1];
+    int   H     = dims_m[4 * d + 2];
+    int   W     = dims_m[4 * d + 3];
+    int   vmin  = is_signed_m[d] ? -128 : 0;
+    int   vmax  = is_signed_m[d] ?  127 : 255;
+    float *in_d = in[d];
+    if (is_NCHW_m[d])  // no need to transpose external tensor
+    {
+      for (int i = 0; i < N * C * H * W; i++)
+        out[offset + i] = QuantizeValue(in_d[i], Q, vmin, vmax);
+    }
+    else  // need to transpose external tensor
+    {
+      for (int n = 0; n < N; n++)
+        for (int c = 0; c < C; c++)
+          for (int h = 0; h < H; h++)
+            for (int w = 0; w < W; w++)
+            {
+              int nchw = GetIndex(n, c, h, w, N, C, H, W);
+              int nhwc = GetIndex(n, h, w, c, N, H, W, C);
+              out[offset + nchw] = QuantizeValue(in_d[nhwc], Q, vmin, vmax);
+            }
+    }
+    offset += N * C * H * W;
+  }
+}
+
+void
+SubgraphDataConv::ScaleDequant(const uint8_t *in, std::vector<float*>& out)
+const
+{
+  int offset = 0;
+  for (uint32_t d = 0; d < is_NCHW_m.size(); d++)
+  {
+    float Q      = scaleQ_m[d];
+    float Q_inv  = 1.0f / Q;
+    int   N      = dims_m[4 * d + 0];
+    int   C      = dims_m[4 * d + 1];
+    int   H      = dims_m[4 * d + 2];
+    int   W      = dims_m[4 * d + 3];
+    bool  S      = is_signed_m[d];
+    float *out_d = out[d];
+    if (is_NCHW_m[d])  // no need to transpose external tensor
+    {
+      for (int i = 0; i < N * C * H * W; i++)
+        out_d[i] = DequantizeValue(in[offset + i], Q_inv, S);
+    }
+    else  // need to transpose external tensor
+    {
+      for (int n = 0; n < N; n++)
+        for (int c = 0; c < C; c++)
+          for (int h = 0; h < H; h++)
+            for (int w = 0; w < W; w++)
+            {
+              int nchw = GetIndex(n, c, h, w, N, C, H, W);
+              int nhwc = GetIndex(n, h, w, c, N, H, W, C);
+              out_d[nhwc] = DequantizeValue(in[offset + nchw], Q_inv, S);
+            }
+    }
+    offset += N * C * H * W;
+  }
+}
+
index 5445b9b7cc70caa8a9ec071769b10957b99a7a2e..9f68c62157da3ab45eefb912648ea0ee54371ada 100644 (file)
@@ -121,6 +121,10 @@ ResM::~ResM()
     if (e != nullptr) delete e;
   for (const Executor* e : e2s_m)
     if (e != nullptr) delete e;
+  for (SubgraphDataConv *dc : in_conv_m)
+    if (dc != nullptr) delete dc;
+  for (SubgraphDataConv *dc : out_conv_m)
+    if (dc != nullptr) delete dc;
 }
 
 ResM& ResM::Instance(uint32_t total_num_subgraphs)
@@ -155,6 +159,15 @@ void ResM::Init(uint32_t num_subgraphs)
     es_m.resize(num_subgraphs_m, nullptr);
     e2s_m.resize(num_subgraphs_m, nullptr);
     eops_m = new std::vector<ResEOP>(num_subgraphs_m);
+
+    // TODO: this should come from parsing config file
+    for (uint32_t i = 0; i < num_subgraphs_m; i++)
+    {
+      in_conv_m.push_back(new SubgraphDataConv(
+                                    {true}, {128.0f}, {false}, {1,3,224,224}));
+      out_conv_m.push_back(new SubgraphDataConv(
+                                    {false}, {255.0f}, {true}, {1,1,1,1001}));
+    }
   }
 }
 
@@ -318,4 +331,15 @@ Configuration& ResM::GetConfiguration(uint32_t subgraph_id)
   return cs_m[subgraph_id];
 }
 
+const SubgraphDataConv& ResM::GetInConv(uint32_t subgraph_id)
+{
+  assert(in_conv_m[subgraph_id] != nullptr);
+  return *in_conv_m[subgraph_id];
+}
+
+const SubgraphDataConv& ResM::GetOutConv(uint32_t subgraph_id)
+{
+  assert(out_conv_m[subgraph_id] != nullptr);
+  return *out_conv_m[subgraph_id];
+}