From: Yuan Zhao Date: Tue, 29 Oct 2019 07:14:54 +0000 (-0500) Subject: Subgraph data conversion at boundaries X-Git-Tag: v01.04.00^2~10 X-Git-Url: https://git.ti.com/gitweb?p=tidl%2Ftidl-api.git;a=commitdiff_plain;h=e0b7c38d199674f34ea1fb2c182744851785dd79 Subgraph data conversion at boundaries - Data layout: NCHW <-> NHWC - Data type: 8-bit quantized <-> float - MCT-1222 --- diff --git a/tidl_api/Makefile b/tidl_api/Makefile index 988cdc9..4dc298b 100644 --- a/tidl_api/Makefile +++ b/tidl_api/Makefile @@ -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 diff --git a/tidl_api/src/subgraph_data_conv.h b/tidl_api/inc/subgraph_data_conv.h similarity index 94% rename from tidl_api/src/subgraph_data_conv.h rename to tidl_api/inc/subgraph_data_conv.h index 24920fc..49b4315 100644 --- a/tidl_api/src/subgraph_data_conv.h +++ b/tidl_api/inc/subgraph_data_conv.h @@ -26,6 +26,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#include +#include + namespace tidl { /* @class SubgraphDataConv @@ -73,10 +76,10 @@ class SubgraphDataConv //! @param None SubgraphDataConv() {} - SubgraphDataConv(const vector& is_signed, - const vector& scaleQ, - const vector& is_NCHW, - const vector& dims + SubgraphDataConv(const std::vector& is_signed, + const std::vector& scaleQ, + const std::vector& is_NCHW, + const std::vector& 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& in, uint8_t* out); + void ScaleQuant(const std::vector& 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& out); + void ScaleDequant(const uint8_t *in, std::vector& 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 dims_m; -} +}; } // namespace tidl diff --git a/tidl_api/inc/subgraph_runtime.h b/tidl_api/inc/subgraph_runtime.h index 09cf970..a38973e 100644 --- a/tidl_api/inc/subgraph_runtime.h +++ b/tidl_api/inc/subgraph_runtime.h @@ -33,6 +33,7 @@ #include #include #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 es_m; std::vector e2s_m; std::vector *eops_m; + std::vector in_conv_m; + std::vector 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 index 0000000..d8cc11f --- /dev/null +++ b/tidl_api/src/subgraph_data_conv.cpp @@ -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& in) +{ + // TODO +} + +void SubgraphDataConv::EstScaleDequant(const std::vector& out) +{ + // TODO +} + + +void +SubgraphDataConv::ScaleQuant(const std::vector& 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& 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; + } +} + diff --git a/tidl_api/src/subgraph_runtime.cpp b/tidl_api/src/subgraph_runtime.cpp index 5445b9b..9f68c62 100644 --- a/tidl_api/src/subgraph_runtime.cpp +++ b/tidl_api/src/subgraph_runtime.cpp @@ -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(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]; +}