tiny_dnn  1.0.0
A header only, dependency-free deep learning framework in C++11
tiny_quantized_deconv2d_kernel.h
1 /*
2  Copyright (c) 2016, Taiga Nomi, Edgar Riba
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 the <organization> 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" AND ANY
17  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #pragma once
28 
29 #include "tiny_dnn/core/params/deconv_params.h"
30 #include "tiny_dnn/core/kernels/tiny_quantization_kernel.h"
31 
32 namespace tiny_dnn {
33 namespace core {
34 namespace kernels {
35 
36 inline void tiny_quantized_deconv2d_kernel(const deconv_params& params,
37  const vec_t& in,
38  const vec_t& W,
39  const vec_t& bias,
40  vec_t& a,
41  const bool layer_parallelize) {
42  // image quantization
43  float_t min_input(in[0]);
44  float_t max_input(in[0]);
45  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
46  for (serial_size_t ins = 0; ins < params.in.height_*params.in.height_; ins++) {
47  serial_size_t idx = params.in.get_index(0, 0, inc);
48  min_input = std::min(min_input, (&in[idx])[ins]);
49  max_input = std::max(max_input, (&in[idx])[ins]);
50  }
51  }
52  std::vector<uint8_t> in_quantized =
53  float_tensor_to_quantized<uint8_t>(in, min_input, max_input);
54  // filter quantization
55  float_t min_filter(W[0]);
56  float_t max_filter(W[0]);
57  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
58  for (serial_size_t ins = 0; ins < params.weight.height_*params.weight.height_; ins++) {
59  serial_size_t idx = params.in.get_index(0, 0, inc);
60  min_filter = std::min(min_filter, (&W[idx])[ins]);
61  max_filter = std::max(max_filter, (&W[idx])[ins]);
62  }
63  }
64  if (min_filter == max_filter) {
65  max_filter = W[0] + 1e-3f;
66  min_filter = W[0] - 1e-3f;
67  }
68  std::vector<uint8_t> W_quantized =
69  float_tensor_to_quantized<uint8_t>(W, min_filter, max_filter);
70  // bias quantization
71  float_t min_bias(0);
72  float_t max_bias(0);
73  std::vector<uint8_t> bias_quantized;
74  if (params.has_bias) {
75  for (serial_size_t inc = 0; inc < params.out.depth_; inc++) {
76  min_bias = std::min(min_bias, bias[inc]);
77  max_bias = std::max(max_bias, bias[inc]);
78  }
79  if (min_bias == max_bias) {
80  max_bias = bias[0] + 1e-3f;
81  min_bias = bias[0] - 1e-3f;
82  }
83  bias_quantized =
84  float_tensor_to_quantized<uint8_t>(bias, min_bias, max_bias);
85  }
86 
87  // output range
88  float_t min_output_value;
89  float_t max_output_value;
90  quantization_range_for_multiplication<uint8_t, uint8_t, int32_t>(
91  min_input, max_input, min_filter, max_filter, &min_output_value,
92  &max_output_value);
93 
94  std::vector<int32_t> a_quantized(a.size(), static_cast<int32_t>(0));
95 
96  // calculating offset
97  const int32_t offset_input =
98  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_input, max_input));
99  const int32_t offset_filter =
100  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_filter, max_filter));
101  const int32_t zero_in_total_space =
102  int64_to_int32(float_to_quantized<int32_t>(0.0f, min_output_value, max_output_value));
103 
104  for_i(layer_parallelize, params.out.depth_, [&](int o) {
105  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
106  if (!params.tbl.is_connected(o, inc)) continue;
107 
108  serial_size_t idx = 0;
109  idx = params.in.depth_ * o + inc;
110  idx = params.weight.get_index(0, 0, idx);
111  const uint8_t *pw = &W_quantized[idx];
112 
113  idx = params.in.get_index(0, 0, inc);
114  const uint8_t *pi = &in_quantized[idx];
115 
116  idx = params.out.get_index(0, 0, o);
117  int32_t *pa_quantized = &a_quantized[idx];
118 
119  for (serial_size_t y = 0; y < params.in.height_; y++) {
120  for (serial_size_t x = 0; x < params.in.width_; x++) {
121  const uint8_t * ppw = pw;
122  const uint8_t * ppi = pi + y * params.in.width_ + x;
123  // should be optimized for small kernel(3x3,5x5)
124  for (serial_size_t wy = 0; wy < params.weight.height_; wy++) {
125  for (serial_size_t wx = 0; wx < params.weight.width_; wx++) {
126  pa_quantized[(y * params.h_stride + wy) *
127  params.out.width_ + (x *
128  params.w_stride + wx)] += static_cast<int32_t>(ppw[wy *
129  params.weight.width_ + wx] - offset_filter) *
130  static_cast<int32_t>(*ppi - offset_input);
131  }
132  }
133  }
134  }
135  }
136  if (params.has_bias) {
137  int32_t * pa_quantized = &a_quantized[params.out.get_index(0, 0, o)];
138  int32_t * paa_quantized = pa_quantized + params.out.width_ * params.out.height_;
139  std::for_each(pa_quantized, paa_quantized, [&](int32_t& f) {
140  f += (bias_quantized[o] - zero_in_total_space);
141  });
142  }
143  });
144 
145  float_t min_output_requantized;
146  float_t max_output_requantized;
147  std::vector<uint8_t> a_requantized(a_quantized.size(), static_cast<uint8_t>(0));
148 
149  // Requantize from 32bits to 8 bits for next layer
150  quantize_down_and_shrink_range<int32_t, uint8_t>(a_quantized, min_output_value, max_output_value,
151  &min_output_requantized, &max_output_requantized, &a_requantized);
152 
153  // dequantize to flaot, this could be removed within concatenated quantized network
154  a = quantized_tensor_to_float<uint8_t>(a_requantized, min_output_requantized, max_output_requantized);
155 }
156 
157 inline void tiny_quantized_deconv2d_back_kernel(const deconv_params& params,
158  const vec_t& prev_out,
159  const vec_t& W,
160  vec_t& dW,
161  vec_t& db,
162  vec_t& curr_delta,
163  vec_t* prev_delta) {
164  // previous output quantization
165  float_t min_prev_out(prev_out[0]);
166  float_t max_prev_out(prev_out[0]);
167  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
168  for (serial_size_t ins = 0; ins < params.in.height_*params.in.height_; ins++) {
169  serial_size_t idx = params.in.get_index(0, 0, inc);
170  min_prev_out = std::min(min_prev_out, (&prev_out[idx])[ins]);
171  max_prev_out = std::max(min_prev_out, (&prev_out[idx])[ins]);
172  }
173  }
174  std::vector<uint8_t> prev_out_quantized =
175  float_tensor_to_quantized<uint8_t>(prev_out, min_prev_out, max_prev_out);
176 
177  // filter quantization
178  float_t min_filter(W[0]);
179  float_t max_filter(W[0]);
180  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
181  for (serial_size_t ins = 0; ins < params.weight.height_*params.weight.height_; ins++) {
182  serial_size_t idx = params.in.get_index(0, 0, inc);
183  min_filter = std::min(min_filter, (&W[idx])[ins]);
184  max_filter = std::max(max_filter, (&W[idx])[ins]);
185  }
186  }
187  if (min_filter == max_filter) {
188  max_filter = W[0] + 1e-3f;
189  min_filter = W[0] - 1e-3f;
190  }
191  std::vector<uint8_t> W_quantized =
192  float_tensor_to_quantized<uint8_t>(W, min_filter, max_filter);
193 
194  // current delta quantization
195  float_t min_curr_delta(curr_delta[0]);
196  float_t max_curr_delta(curr_delta[0]);
197  for (serial_size_t inc = 0; inc < params.out.depth_; inc++) {
198  for (serial_size_t ins = 0; ins < params.out.height_*params.out.height_; ins++) {
199  serial_size_t idx = params.out.get_index(0, 0, inc);
200  min_curr_delta = std::min(min_curr_delta, (&curr_delta[idx])[ins]);
201  max_curr_delta = std::max(max_curr_delta, (&curr_delta[idx])[ins]);
202  }
203  }
204  std::vector<uint8_t> curr_delta_quantized =
205  float_tensor_to_quantized<uint8_t>(curr_delta, min_curr_delta, max_curr_delta);
206 
207  // output range for previous delta
208  float_t min_prev_delta_value;
209  float_t max_prev_delta_value;
210  quantization_range_for_multiplication<uint8_t, uint8_t, int32_t>(
211  min_curr_delta, max_curr_delta, min_filter, max_filter, &min_prev_delta_value,
212  &max_prev_delta_value);
213 
214  std::vector<int32_t> prev_delta_quantized(prev_delta->size(), static_cast<int32_t>(0));
215 
216  // output range for dW
217  float_t min_dW_value;
218  float_t max_dW_value;
219  quantization_range_for_multiplication<uint8_t, uint8_t, int32_t>(
220  min_curr_delta, max_curr_delta, min_prev_out, max_prev_out, &min_dW_value,
221  &max_dW_value);
222 
223  std::vector<int32_t> dW_quantized(dW.size(), static_cast<int32_t>(0));
224 
225  // calculating offset
226  // TODO wangdiya: do we need to check overflows?
227  const int32_t offset_prev_out =
228  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_prev_out, max_prev_out));
229  const int32_t offset_filter =
230  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_filter, max_filter));
231  const int32_t offset_curr_delta =
232  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_curr_delta, max_curr_delta));
233  // const int32_t zero_in_prev_delta =
234  // float_to_quantized<int32_t>(0.0f, min_prev_delta_value, max_prev_delta_value);
235 
236  // propagate delta to previous layer
237  for_i(params.in.depth_, [&](int inc) {
238  for (serial_size_t outc = 0; outc < params.out.depth_; outc++) {
239  if (!params.tbl.is_connected(outc, inc)) continue;
240 
241  serial_size_t idx = 0;
242  idx = params.in.depth_ * outc + inc;
243  idx = params.weight.get_index(0, 0, idx);
244  const uint8_t *pw = &W_quantized[idx];
245 
246  idx = params.out_unpadded.get_index(0, 0, outc);
247  const uint8_t *pdelta_src = &curr_delta_quantized[idx];
248 
249  idx = params.in.get_index(0, 0, inc);
250  int32_t *pdelta_quantized_dst = &(prev_delta_quantized)[idx];
251 
252  for (serial_size_t y = 0; y < params.in.height_; y++) {
253  for (serial_size_t x = 0; x < params.in.width_; x++) {
254  const uint8_t * ppw = pw;
255  int32_t * ppdelta_quantized_dst = pdelta_quantized_dst + y * params.in.width_ + x;
256  int32_t sum = int32_t(0);
257 
258  for (serial_size_t wy = 0; wy < params.weight.height_; wy++) {
259  for (serial_size_t wx = 0; wx < params.weight.width_; wx++) {
260  sum += static_cast<int32_t>(ppw[wy * params.weight.width_ + wx] - offset_filter) *
261  static_cast<int32_t>(pdelta_src[(y * params.h_stride + wy) *
262  params.out.width_ + (x *
263  params.w_stride + wx)] -
264  offset_curr_delta);
265  }
266  }
267  *ppdelta_quantized_dst += sum;
268  }
269  }
270  }
271  });
272 
273  float_t min_prev_delta_requantized;
274  float_t max_prev_delta_requantized;
275  std::vector<uint8_t> prev_delta_requantized(prev_delta_quantized.size(), static_cast<uint8_t>(0));
276 
277  // Requantize from 32bits to 8 bits for next layer
278  quantize_down_and_shrink_range<int32_t, uint8_t>(prev_delta_quantized, min_prev_delta_value, max_prev_delta_value,
279  &min_prev_delta_requantized, &max_prev_delta_requantized, &prev_delta_requantized);
280 
281  // dequantize to flaot, this could be removed within concatenated quantized network
282  vec_t prev_delta_vec = quantized_tensor_to_float<uint8_t>(prev_delta_requantized, min_prev_delta_requantized, max_prev_delta_requantized);
283  prev_delta = &prev_delta_vec;
284 
285  // Accumulate dw
286  for_i(params.in.depth_, [&](int inc) {
287  for (serial_size_t outc = 0; outc < params.out.depth_; outc++) {
288  if (!params.tbl.is_connected(outc, inc)) continue;
289 
290  for (serial_size_t wy = 0; wy < params.weight.height_; wy++) {
291  for (serial_size_t wx = 0; wx < params.weight.width_; wx++) {
292  int32_t dst = int32_t(0);
293 
294  serial_size_t idx = 0;
295  idx = params.in.get_index(0, 0, inc);
296  const uint8_t * prevo = &prev_out_quantized[idx];
297 
298  idx = params.out.get_index(wx, wy, outc);
299  const uint8_t * delta = &curr_delta_quantized[idx];
300 
301  for (serial_size_t y = 0; y < params.in.height_; y++) {
302  for (serial_size_t x = 0; x < params.in.width_; x++) {
303  dst += (static_cast<int32_t>(*(prevo + y * params.in.width_ + x)) - offset_prev_out) *
304  (static_cast<int32_t>(*(delta + y * params.out.width_ + x)) - offset_curr_delta);
305  }
306  }
307 
308  idx = params.in.depth_ * outc + inc;
309  dW_quantized[params.weight.get_index(wx, wy, idx)] += dst;
310  }
311  }
312  }
313  });
314 
315  float_t min_dW_requantized;
316  float_t max_dW_requantized;
317  std::vector<uint8_t> dW_requantized(dW_quantized.size(), static_cast<uint8_t>(0));
318 
319  // requantize from 32bits to 8 bits for next layer
320  quantize_down_and_shrink_range<int32_t, uint8_t>(dW_quantized, min_dW_value, max_dW_value,
321  &min_dW_requantized, &max_dW_requantized, &dW_requantized);
322 
323  // dequantize to flaot, this could be removed within concatenated quantized network
324  dW = quantized_tensor_to_float<uint8_t>(dW_requantized, min_dW_requantized, max_dW_requantized);
325 
326  // Accumulate db
327  if (params.has_bias) {
328  //vec_t& db = *in_grad[2];
329 
330  for (serial_size_t outc = 0; outc < params.out.depth_; outc++) {
331  serial_size_t idx = params.out.get_index(0, 0, outc);
332  const float_t * delta = &curr_delta[idx];
333  const float_t * deltaa = delta + params.out.width_ *
334  params.out.height_;
335  db[outc] += std::accumulate(delta, deltaa, float_t(0));
336  }
337  }
338 }
339 
340 inline void tiny_quantized_deconv2d_kernel(const deconv_params& params,
341  const vec_t& in,
342  const vec_t& W,
343  const vec_t& bias,
344  const vec_t& in_r,
345  const vec_t& W_r,
346  const vec_t& b_r,
347  vec_t& a,
348  vec_t& a_r,
349  const bool layer_parallelize) {
350  // filter range
351  float_t min_filter(W_r[0]);
352  float_t max_filter(W_r[1]);
353  if (W_r[0] == W_r[1]) {
354  max_filter = W_r[1] + 1e-3f;
355  min_filter = W_r[0] - 1e-3f;
356  }
357  // bias range
358  float_t min_bias(b_r[0]);
359  float_t max_bias(b_r[1]);
360  if (params.has_bias) {
361  if (min_bias == max_bias) {
362  max_bias = b_r[1] + 1e-3f;
363  min_bias = b_r[0] - 1e-3f;
364  }
365  }
366  // output range
367  float_t min_output_value;
368  float_t max_output_value;
369  quantization_range_for_multiplication<uint8_t, uint8_t, int32_t>(
370  in_r[0], in_r[1], min_filter, max_filter, &min_output_value,
371  &max_output_value);
372  // data type restore
373  std::vector<uint8_t> in_quantized, W_quantized, bias_quantized;
374  for (size_t i = 0; i < in.size(); i++) {
375  in_quantized.push_back(static_cast<uint8_t>(in[i]));
376  }
377  for (size_t i = 0; i < W.size(); i++) {
378  W_quantized.push_back(static_cast<uint8_t>(W[i]));
379  }
380  for (size_t i = 0; i < bias.size(); i++) {
381  bias_quantized.push_back(static_cast<uint8_t>(bias[i]));
382  }
383 
384  std::vector<int32_t> a_quantized(a.size(), static_cast<int32_t>(0));
385 
386  // calculating offset
387  const int32_t offset_input =
388  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, in_r[0], in_r[1]));
389  const int32_t offset_filter =
390  int64_to_int32(float_to_quantized_unclamped<uint8_t>(0.0f, min_filter, max_filter));
391  const int32_t zero_in_total_space =
392  int64_to_int32(float_to_quantized<int32_t>(0.0f, min_output_value, max_output_value));
393 
394  for_i(layer_parallelize, params.out.depth_, [&](int o) {
395  for (serial_size_t inc = 0; inc < params.in.depth_; inc++) {
396  if (!params.tbl.is_connected(o, inc)) continue;
397 
398  serial_size_t idx = 0;
399  idx = params.in.depth_ * o + inc;
400  idx = params.weight.get_index(0, 0, idx);
401  const uint8_t *pw = &W_quantized[idx];
402 
403  idx = params.in.get_index(0, 0, inc);
404  const uint8_t *pi = &in_quantized[idx];
405 
406  idx = params.out.get_index(0, 0, o);
407  int32_t *pa_quantized = &a_quantized[idx];
408 
409  for (serial_size_t y = 0; y < params.in.height_; y++) {
410  for (serial_size_t x = 0; x < params.in.width_; x++) {
411  const uint8_t * ppw = pw;
412  const uint8_t * ppi = pi + y * params.in.width_ + x;
413  // should be optimized for small kernel(3x3,5x5)
414  for (serial_size_t wy = 0; wy < params.weight.height_; wy++) {
415  for (serial_size_t wx = 0; wx < params.weight.width_; wx++) {
416  pa_quantized[(y * params.h_stride + wy) *
417  params.out.width_ + (x *
418  params.w_stride + wx)] += static_cast<int32_t>(ppw[wy *
419  params.weight.width_ + wx] - offset_filter) *
420  static_cast<int32_t>(*ppi - offset_input);
421  }
422  }
423  }
424  }
425  }
426  if (params.has_bias) {
427  int32_t * pa_quantized = &a_quantized[params.out.get_index(0, 0, o)];
428  int32_t * paa_quantized = pa_quantized + params.out.width_ * params.out.height_;
429  std::for_each(pa_quantized, paa_quantized, [&](int32_t& f) {
430  f += static_cast<int32_t>((bias[o] - zero_in_total_space));
431  });
432  }
433  });
434 
435  float_t min_output_requantized;
436  float_t max_output_requantized;
437  std::vector<uint8_t> a_requantized(a_quantized.size(), static_cast<uint8_t>(0));
438 
439  // Requantize from 32bits to 8 bits for next layer
440  quantize_down_and_shrink_range<int32_t, uint8_t>(a_quantized, min_output_value, max_output_value,
441  &min_output_requantized, &max_output_requantized, &a_requantized);
442  // store directly in float datatype
443  for (size_t i = 0; i < a_requantized.size(); i++) {
444  a[i] = static_cast<float>(a_requantized[i]);
445  }
446  a_r[0] = min_output_requantized;
447  a_r[1] = max_output_requantized;
448 }
449 
450 } // namespace kernels
451 } // namespace core
452 } // namespace tiny_dnn