1 /******************************************************************************
2 * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Texas Instruments Incorporated nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
29 #include <cassert>
30 #include <cstring>
31 #include "subgraph_data_conv.h"
33 using namespace tidl;
36 static inline uint8_t QuantizeValue(float v, float Q, int vmin, int vmax)
37 {
38 // scale
39 int32_t qv = (int32_t) (v * Q);
40 // saturate
41 qv = qv < vmin ? vmin : qv;
42 qv = qv > vmax ? vmax : qv;
43 return (uint8_t) qv;
44 }
46 static inline float DequantizeValue(uint8_t v, float Q_inv, bool S)
47 {
48 // interpret sign
49 int32_t sv = S ? ((int32_t)(int8_t) v) : ((int32_t) v);
50 // scale
51 return sv * Q_inv;
52 }
54 // Gets 1-d index for 4-d buffer[d][c][b][a]
55 static inline int GetIndex(int d, int c, int b, int a,
56 int D, int C, int B, int A)
57 {
58 return a + A*(b + B*(c + C*d));
59 }
62 void SubgraphDataConv::EstScaleQuant(const std::vector<float*>& in)
63 {
64 // TODO
65 }
67 void SubgraphDataConv::EstScaleDequant(const std::vector<float*>& out)
68 {
69 // TODO
70 }
73 void
74 SubgraphDataConv::ScaleQuant(const std::vector<float*>& in, uint8_t* out)
75 const
76 {
77 int offset = 0;
78 for (uint32_t d = 0; d < is_NCHW_m.size(); d++)
79 {
80 int N = dims_m[4 * d + 0];
81 int C = dims_m[4 * d + 1];
82 int H = dims_m[4 * d + 2];
83 int W = dims_m[4 * d + 3];
85 if (conv_type_m[d] == ConvType::FLOAT_Q)
86 {
87 float Q = scaleQ_m[d];
88 int vmin = is_signed_m[d] ? -128 : 0;
89 int vmax = is_signed_m[d] ? 127 : 255;
90 float *in_d = in[d];
91 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
92 {
93 // no need to transpose external tensor
94 for (int i = 0; i < N * C * H * W; i++)
95 out[offset + i] = QuantizeValue(in_d[i], Q, vmin, vmax);
96 }
97 else
98 {
99 // need to transpose external tensor
100 for (int n = 0; n < N; n++)
101 for (int c = 0; c < C; c++)
102 for (int h = 0; h < H; h++)
103 for (int w = 0; w < W; w++)
104 {
105 int nchw = GetIndex(n, c, h, w, N, C, H, W);
106 int nhwc = GetIndex(n, h, w, c, N, H, W, C);
107 out[offset + nchw] = QuantizeValue(in_d[nhwc], Q, vmin, vmax);
108 }
109 }
110 }
111 else if (conv_type_m[d] == ConvType::FLOAT_FLOAT)
112 {
113 assert((W & 0x3) == 0); // last dimension is bytes
114 int f_W = W / 4; // number of elements
115 float *in_d = in[d];
116 float *out_d = (float *) (out + offset);
117 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
118 {
119 // no need to transpose external tensor
120 memcpy(out_d, in_d, N * C * H * W); // W is bytes
121 }
122 else
123 {
124 // need to transpose external tensor
125 for (int n = 0; n < N; n++)
126 for (int c = 0; c < C; c++)
127 for (int h = 0; h < H; h++)
128 for (int w = 0; w < f_W; w++)
129 {
130 int nchw = GetIndex(n, c, h, w, N, C, H, f_W);
131 int nhwc = GetIndex(n, h, w, c, N, H, f_W, C);
132 out_d[nchw] = in_d[nhwc];
133 }
134 }
135 }
136 else if (conv_type_m[d] == ConvType::Q_Q)
137 {
138 uint8_t *in_d = (uint8_t *) &in[d];
139 uint8_t *out_d = (out + offset);
140 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
141 {
142 // no need to transpose external tensor
143 memcpy(out_d, in_d, N * C * H * W);
144 }
145 else
146 {
147 // need to transpose external tensor
148 for (int n = 0; n < N; n++)
149 for (int c = 0; c < C; c++)
150 for (int h = 0; h < H; h++)
151 for (int w = 0; w < W; w++)
152 {
153 int nchw = GetIndex(n, c, h, w, N, C, H, W);
154 int nhwc = GetIndex(n, h, w, c, N, H, W, C);
155 out_d[nchw] = in_d[nhwc];
156 }
157 }
158 }
159 else
160 {
161 assert(false);
162 }
164 offset += N * C * H * W; // accumulate in bytes
165 }
166 }
168 void
169 SubgraphDataConv::ScaleDequant(const uint8_t *in, std::vector<float*>& out)
170 const
171 {
172 int offset = 0;
173 for (uint32_t d = 0; d < is_NCHW_m.size(); d++)
174 {
175 int N = dims_m[4 * d + 0];
176 int C = dims_m[4 * d + 1];
177 int H = dims_m[4 * d + 2];
178 int W = dims_m[4 * d + 3];
180 if (conv_type_m[d] == ConvType::FLOAT_Q)
181 {
182 float Q = scaleQ_m[d];
183 float Q_inv = 1.0f / Q;
184 bool S = is_signed_m[d];
185 float *out_d = out[d];
186 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
187 {
188 // no need to transpose external tensor
189 for (int i = 0; i < N * C * H * W; i++)
190 out_d[i] = DequantizeValue(in[offset + i], Q_inv, S);
191 }
192 else
193 {
194 // need to transpose external tensor
195 for (int n = 0; n < N; n++)
196 for (int c = 0; c < C; c++)
197 for (int h = 0; h < H; h++)
198 for (int w = 0; w < W; w++)
199 {
200 int nchw = GetIndex(n, c, h, w, N, C, H, W);
201 int nhwc = GetIndex(n, h, w, c, N, H, W, C);
202 out_d[nhwc] = DequantizeValue(in[offset + nchw], Q_inv, S);
203 }
204 }
205 }
206 else if (conv_type_m[d] == ConvType::FLOAT_FLOAT)
207 {
208 assert((W & 0x3) == 0); // last dimension is bytes
209 int f_W = W / 4; // number of elements
210 float *in_d = (float *) (in + offset);
211 float *out_d = out[d];
212 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
213 {
214 // no need to transpose external tensor
215 memcpy(out_d, in_d, N * C * H * W); // W is bytes
216 }
217 else
218 {
219 // need to transpose external tensor
220 for (int n = 0; n < N; n++)
221 for (int c = 0; c < C; c++)
222 for (int h = 0; h < H; h++)
223 for (int w = 0; w < f_W; w++)
224 {
225 int nchw = GetIndex(n, c, h, w, N, C, H, f_W);
226 int nhwc = GetIndex(n, h, w, c, N, H, f_W, C);
227 out_d[nhwc] = in_d[nchw];
228 }
229 }
230 }
231 else if (conv_type_m[d] == ConvType::Q_Q)
232 {
233 uint8_t *in_d = (uint8_t *) (in + offset);
234 uint8_t *out_d = (uint8_t * ) &out[d];
235 if (is_NCHW_m[d] || (C == 1) || (H*W == 1))
236 {
237 // no need to transpose external tensor
238 memcpy(out_d, in_d, N * C * H * W);
239 }
240 else
241 {
242 // need to transpose external tensor
243 for (int n = 0; n < N; n++)
244 for (int c = 0; c < C; c++)
245 for (int h = 0; h < H; h++)
246 for (int w = 0; w < W; w++)
247 {
248 int nchw = GetIndex(n, c, h, w, N, C, H, W);
249 int nhwc = GetIndex(n, h, w, c, N, H, W, C);
250 out_d[nhwc] = in_d[nchw];
251 }
252 }
253 }
254 else
255 {
256 assert(false);
257 }
259 offset += N * C * H * W;
260 }
261 }