updated readme file due to moving CMake scripts to the root folder
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / tests / benchdnn / rnn / rnn.hpp
1 /*******************************************************************************
2  * Copyright 2018 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16
17 #ifndef _LSTM_HPP
18 #define _LSTM_HPP
19
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdint.h>
23
24 #include "common.hpp"
25 #include "dnn_types.hpp"
26 #include "mkldnn_common.hpp"
27 #include "mkldnn_debug.hpp"
28 #include "mkldnn_memory.hpp"
29
30 namespace rnn {
31
32 extern const char *perf_template;
33
34 enum alg_t { VANILLA_RNN, VANILLA_LSTM, VANILLA_GRU, LBR_GRU };
35 alg_t str2alg(const char *str);
36 const char *alg2str(alg_t alg);
37 mkldnn_alg_kind_t alg2kind(alg_t alg);
38
39 enum activation_t { RELU, LOGISTIC, TANH };
40 activation_t str2activation(const char *str);
41 const char *activation2str(activation_t alg);
42 mkldnn_alg_kind_t activation2kind(activation_t alg);
43
44 mkldnn_prop_kind_t str2prop(const char *str);
45 const char *prop2str(mkldnn_prop_kind_t prop);
46
47 mkldnn_rnn_direction_t str2direction(const char *str);
48 const char *direction2str(mkldnn_rnn_direction_t direction);
49
50 const int H = 0;
51 const int C = 1;
52
53 template <typename Telem>
54 struct array_offset_calculator {
55     template <typename... Targs>
56     array_offset_calculator(Telem *base, Targs... Fargs)
57         : _size(sizeof...(Fargs)) {
58         const int init_list[] = { Fargs... };
59         _dims = new int[_size];
60         for (int i = 0; i < _size; ++i)
61             _dims[i] = init_list[i];
62
63         _base_ptr = base;
64     }
65     ~array_offset_calculator() { delete[] _dims; }
66     template <typename... Targs>
67     inline Telem &operator()(Targs... Fargs) {
68         return *(_base_ptr + _offset(1, Fargs...));
69     }
70
71 private:
72     template <typename... Targs>
73     inline int _offset(int const dimension, int element) {
74         return element;
75     }
76
77     template <typename... Targs>
78     inline int _offset(int const dimension, int theta, int element) {
79         return element + (_dims[dimension] * theta);
80     }
81
82     template <typename... Targs>
83     inline int _offset(
84             int const dimension, int theta, int element, Targs... Fargs) {
85         int t_prime = element + (_dims[dimension] * theta);
86         return _offset(dimension + 1, t_prime, Fargs...);
87     }
88
89     Telem *_base_ptr;
90     int _size;
91     int *_dims;
92 };
93
94 struct rnn_desc_t {
95     int sic;
96     int slc;
97     int dic;
98     int dlc;
99     int mb;
100     int n_layer;
101     int n_iter;
102     const char *name;
103 };
104 int str2desc(rnn_desc_t *desc, const char *str);
105
106 enum rnn_data_kind_t {
107     input,
108     states,
109     weights_input,
110     weights_states,
111     bias,
112     dst_last_iteration,
113     dst_last_layer,
114     dst_diff_input,
115     dst_diff_states,
116     dst_diff_weights_input,
117     dst_diff_weights_states,
118     dst_diff_bias,
119     diff_last_iteration,
120     diff_last_layer,
121     data_kind_total // should be last to provide the total number of data kinds
122 };
123
124 inline const char *rnn_data_kind2str(rnn_data_kind_t kind) {
125     switch (kind) {
126     case input: return "INPUT";
127     case states: return "STATES";
128     case weights_input: return "WEIGHTS_INPUT";
129     case weights_states: return "WEIGHTS_STATES";
130     case bias: return "BIAS";
131     case dst_last_layer: return "DST_LAST_LAYER";
132     case dst_last_iteration: return "DST_LAST_ITERATION";
133     default:
134         assert(!"incorrect rnn data kind");
135         return "incorrect rnn data kind";
136     }
137 }
138
139 /** configuration structure, that controls initial data filling + error check
140 *
141 * dt defines precision
142 *
143 * for each lst data kind the values are filled as follows:
144 * if (rand() > f_sparsity) then:
145 *     v <-- f_base
146 * else:
147 *     v <-- f_min + rand() * f_step % (f_max - f_min)
148 *
149 * on final check the resulting values should be in [min .. max] range, the
150 * relative difference should not exceed eps
151 */
152
153 typedef struct dt_conf_t {
154     mkldnn_data_type_t dt;
155     int min, max; /* representative */
156     int f_min, f_max; /* fill range */
157     float f_mean, f_var; /* mean and variance of normally distributed data */
158     double eps; /* acceptable error */
159 } _dt_conf_t[data_kind_total];
160
161 extern const _dt_conf_t conf_f32;
162 extern const _dt_conf_t conf_u8u8u8u8;
163 extern const _dt_conf_t conf_u8u8u8f32;
164 extern const _dt_conf_t conf_f32u8f32f32;
165 extern const _dt_conf_t conf_f32u8f32u8;
166
167 const dt_conf_t *str2cfg(const char *str);
168 const char *cfg2str(const dt_conf_t *cfg);
169
170 enum policy_t { NONE = 0, COMMON, PER_OC };
171 policy_t str2policy(const char *str);
172 const char *policy2str(attr_t::scale_t::policy_t policy);
173
174 struct rnn_prb_t : public rnn_desc_t {
175     rnn_prb_t(const rnn_desc_t desc, const dt_conf_t *cfg,
176             mkldnn_prop_kind_t prop, alg_t alg,
177             mkldnn_rnn_direction_t direction, activation_t activation,
178             const attr_t &attr, policy_t scale_policy, int mb = 0)
179         : rnn_desc_t(desc)
180         , cfg(cfg)
181         , prop(prop)
182         , alg(alg)
183         , direction(direction)
184         , activation(activation)
185         , attr(attr)
186         , scale_policy(scale_policy)
187         , ops(0.0) {
188         count_ops();
189         if (mb) this->mb = mb;
190         wei_oc_scales = NULL;
191         if (scale_policy == PER_OC)
192             wei_oc_scales
193                     = (float *)zmalloc(sizeof(float) * dic * n_gates(), 64);
194         set_qparams(-1., 1.);
195     }
196     ~rnn_prb_t() {
197         if (wei_oc_scales)
198             zfree(wei_oc_scales);
199     }
200
201     void count_ops() {
202         // Here, we count only the ops in GEMM portion as there is no
203         // theoretical number of ops for the post-gemm operations
204         size_t num_cells = (size_t) n_directions() * n_layer * n_iter;
205         size_t cell_ops = (size_t) 2 * (n_gates() * dic) * mb * (sic + slc);
206         ops = num_cells * cell_ops;
207     }
208
209     int n_directions() const {
210         return (direction == mkldnn_bidirectional_concat
211                        || direction == mkldnn_bidirectional_sum) ?
212                 2 :
213                 1;
214     }
215     int n_weights() const { return 1; }
216     int n_states() const { return alg == VANILLA_LSTM ? 2 : 1; }
217     int n_gates() const {
218         return alg == VANILLA_LSTM ?
219                 4 :
220                 (alg == VANILLA_GRU || alg == LBR_GRU ? 3 : 1);
221     }
222     int n_bias() const {
223         return alg == LBR_GRU ? n_gates() + 1 : n_gates();
224     }
225
226     const dt_conf_t *cfg;
227     mkldnn_prop_kind_t prop;
228     alg_t alg;
229     mkldnn_rnn_direction_t direction;
230     activation_t activation;
231     attr_t attr;
232     policy_t scale_policy;
233
234     double ops;
235
236     float data_scale, data_shift;
237     float wei_scale;
238     float *wei_oc_scales;
239
240 private:
241     void set_qparams(float fp_min, float fp_max);
242     rnn_prb_t(const rnn_prb_t &) = delete;
243     rnn_prb_t &operator=(const rnn_prb_t &) = delete;
244 };
245
246 const size_t max_prb_len = 392;
247 void prb2str(const rnn_prb_t *p, const res_t *res, char *buffer);
248
249 void compute_ref_fwd(const rnn_prb_t *p, dnn_mem_t &input_m,
250         dnn_mem_t &states_m, dnn_mem_t &weights_input_m,
251         dnn_mem_t &weights_states_m, dnn_mem_t &bias_m,
252         dnn_mem_t &dst_last_layer_m, dnn_mem_t &dst_last_iteration_m,
253         mkldnn_rnn_direction_t direction);
254
255 void compute_ref_bwd(const rnn_prb_t *p, dnn_mem_t &input_m,
256         dnn_mem_t &states_m, dnn_mem_t &diff_last_layer_m,
257         dnn_mem_t &diff_last_iteration_m, dnn_mem_t &weights_input_m,
258         dnn_mem_t &weights_states_m, dnn_mem_t &bias_m,
259         dnn_mem_t &dst_last_layer_m, dnn_mem_t &dst_last_iteration_m,
260         dnn_mem_t &dst_diff_input_m, dnn_mem_t &dst_diff_states_m,
261         dnn_mem_t &dst_diff_weights_input_m,
262         dnn_mem_t &dst_diff_weights_states_m, dnn_mem_t &dst_diff_bias_m,
263         mkldnn_rnn_direction_t direction);
264
265 // mkldnn_ntc
266 inline size_t ntc_off_f(const rnn_prb_t *p, int n, int t, int c) {
267     return ((size_t)n * p->n_iter + t) * p->slc + c;
268 }
269
270 inline void inv_ntc_off_f(
271         const rnn_prb_t *p, size_t off, int &n, int &t, int &c) {
272     c = off % p->slc;
273     off /= p->slc;
274     t = off % p->n_iter;
275     off /= p->n_iter;
276     n = off % p->mb;
277     off /= p->mb;
278     assert(off == 0);
279 }
280
281 // mkldnn_ldsnc
282 inline size_t ldsnc_off_f(
283         const rnn_prb_t *p, int l, int d, int s, int n, int c) {
284     return ((((size_t)l * p->n_directions() + d) * p->n_states() + s) * p->mb
285                    + n)
286             * p->sic
287             + c;
288 }
289
290 inline void inv_ldsnc_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
291         int &s, int &n, int &c) {
292     c = off % p->sic;
293     off /= p->sic;
294     n = off % p->mb;
295     off /= p->mb;
296     s = off % p->n_states();
297     off /= p->n_states();
298     d = off % p->n_directions();
299     off /= p->n_directions();
300     l = off % p->n_layer;
301     off /= p->n_layer;
302     assert(off == 0);
303 }
304
305 // mkldnn_ldigo
306 inline size_t ldigo_off_f(
307         const rnn_prb_t *p, int l, int d, int w, int ic, int oc) {
308     return ((((size_t)l * p->n_directions() + d) * p->n_weights() + w)
309                            * (4 * p->slc)
310                    + ic)
311             * p->sic
312             + oc;
313 }
314
315 inline void inv_ldigo_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
316         int &w, int &ic, int &oc) {
317     oc = off % p->sic;
318     off /= p->sic;
319     ic = off % (4 * p->slc);
320     off /= (4 * p->slc);
321     w = off % p->n_weights();
322     off /= p->n_weights();
323     d = off % p->n_directions();
324     off /= p->n_directions();
325     l = off % p->n_layer;
326     off /= p->n_layer;
327     assert(off == 0);
328 }
329
330 // mkldnn_ldwOcIc
331 inline size_t ldwOcIc_off_f(
332         const rnn_prb_t *p, int l, int d, int w, int oc, int ic) {
333     return ((((size_t)l * p->n_directions() + d) * p->n_weights() + w)
334                            * (4 * p->sic)
335                    + oc)
336             * p->slc
337             + ic;
338 }
339
340 inline void inv_ldwOcIc_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
341         int &w, int &oc, int &ic) {
342     ic = off % p->slc;
343     off /= p->slc;
344     oc = off % (4 * p->sic);
345     off /= (4 * p->sic);
346     w = off % p->n_weights();
347     off /= p->n_weights();
348     d = off % p->n_directions();
349     off /= p->n_directions();
350     l = off % p->n_layer;
351     off /= p->n_layer;
352     assert(off == 0);
353 }
354
355 // bias: mkldnn_ldgo
356 inline size_t ldgo_off_f(const rnn_prb_t *p, int l, int d, int b, int c) {
357     return (((size_t)l * p->n_directions() + d) * p->n_bias() + b) * p->sic
358             + c;
359 }
360
361 inline void inv_ldgo_off_f(
362         const rnn_prb_t *p, size_t off, int &l, int &d, int &b, int &c) {
363     c = off % p->sic;
364     off /= p->sic;
365     b = off % p->n_bias();
366     off /= p->n_bias();
367     d = off % p->n_directions();
368     off /= p->n_directions();
369     l = off % p->n_layer;
370     off /= p->n_layer;
371     assert(off == 0);
372 }
373
374 // dst_last_layer: mkldnn_tnc
375 inline size_t tnc_off_f(const rnn_prb_t *p, int s, int t, int n, int c) {
376     return (((size_t)s * p->n_iter + t) * p->mb + n) * p->sic + c;
377 }
378
379 inline void inv_tnc_off_f(
380         const rnn_prb_t *p, size_t off, int &s, int &t, int &n, int &c) {
381     c = off % p->sic;
382     off /= p->sic;
383     n = off % p->mb;
384     off /= p->mb;
385     t = off % p->n_iter;
386     off /= p->n_iter;
387     s = off % p->n_states();
388     off /= p->n_states();
389     assert(off == 0);
390 }
391
392 void perf_report(const rnn_prb_t *p, const res_t *r, const char *pstr);
393
394 int doit(const rnn_prb_t *p, res_t *res);
395 void check(rnn_desc_t *p);
396 int bench(int argc, char **argv, bool main_bench = true);
397 } // namespace rnn
398
399 #endif