Publishing R3
[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 enum alg_t { VANILLA_RNN, VANILLA_LSTM, VANILLA_GRU, GRU_LINEAR_BEFORE_RESET };
33 alg_t str2alg(const char *str);
34 const char *alg2str(alg_t alg);
35 mkldnn_alg_kind_t alg2kind(alg_t alg);
36
37 enum activation_t { RELU, LOGISTIC, TANH };
38 activation_t str2activation(const char *str);
39 const char *activation2str(activation_t alg);
40 mkldnn_alg_kind_t activation2kind(activation_t alg);
41
42 const int H = 0;
43 const int C = 1;
44
45 template <typename Telem>
46 struct array_offset_calculator {
47     template <typename... Targs>
48     array_offset_calculator(Telem *base, Targs... Fargs)
49         : _size(sizeof...(Fargs)) {
50         const int init_list[] = { Fargs... };
51         _dims = new int[_size];
52         for (int i = 0; i < _size; ++i)
53             _dims[i] = init_list[i];
54
55         _base_ptr = base;
56     }
57     ~array_offset_calculator() { delete[] _dims; }
58     template <typename... Targs>
59     inline Telem &operator()(Targs... Fargs) {
60         return *(_base_ptr + _offset(1, Fargs...));
61     }
62
63 private:
64     template <typename... Targs>
65     inline int _offset(int const dimension, int element) {
66         return element;
67     }
68
69     template <typename... Targs>
70     inline int _offset(int const dimension, int theta, int element) {
71         return element + (_dims[dimension] * theta);
72     }
73
74     template <typename... Targs>
75     inline int _offset(
76             int const dimension, int theta, int element, Targs... Fargs) {
77         int t_prime = element + (_dims[dimension] * theta);
78         return _offset(dimension + 1, t_prime, Fargs...);
79     }
80
81     Telem *_base_ptr;
82     int _size;
83     int *_dims;
84 };
85
86 struct rnn_desc_t {
87     alg_t alg;
88     activation_t activation;
89     mkldnn_rnn_direction_t direction;
90     int sic;
91     int slc;
92     int dic;
93     int dlc;
94     int mb;
95     int n_layer;
96     int n_iter;
97     const char *name;
98 };
99
100 enum rnn_data_kind_t {
101     input,
102     states,
103     weights_input,
104     weights_states,
105     bias,
106     dst_last_layer,
107     dst_last_iteration,
108     dst_diff_input,
109     dst_diff_states,
110     dst_diff_weights_input,
111     dst_diff_weights_states,
112     dst_diff_bias,
113     diff_last_layer,
114     diff_last_iteration,
115     data_kind_total // should be last to provide the total number of data kinds
116 };
117
118 inline const char *rnn_data_kind2str(rnn_data_kind_t kind) {
119     switch (kind) {
120     case input: return "INPUT";
121     case states: return "STATES";
122     case weights_input: return "WEIGHTS_INPUT";
123     case weights_states: return "WEIGHTS_STATES";
124     case bias: return "BIAS";
125     case dst_last_layer: return "DST_LAST_LAYER";
126     case dst_last_iteration: return "DST_LAST_ITERATION";
127     default:
128         assert(!"incorrect rnn data kind");
129         return "incorrect rnn data kind";
130     }
131 }
132
133 /** configuration structure, that controls initial data filling + error check
134 *
135 * dt defines precision
136 *
137 * for each lst data kind the values are filled as follows:
138 * if (rand() > f_sparsity) then:
139 *     v <-- f_base
140 * else:
141 *     v <-- f_min + rand() * f_step % (f_max - f_min)
142 *
143 * on final check the resulting values should be in [min .. max] range, the
144 * relative difference should not exceed eps
145 */
146
147 typedef struct dt_conf_t {
148     mkldnn_data_type_t dt;
149     int min, max; /* representative */
150     int f_min, f_max; /* fill range */
151     int f_base; /* fill base, use 0 */
152     int f_step; /* fill step, use 1 */
153     double f_sparsity; /* amount of non-zeros, default 0.25 */
154     double eps; /* acceptable error */
155 } _dt_conf_t[data_kind_total];
156
157 extern const _dt_conf_t conf_f32;
158
159 struct rnn_prb_t : public rnn_desc_t {
160     rnn_prb_t(const rnn_desc_t desc, const dt_conf_t *cfg,
161             mkldnn_prop_kind_t prop)
162         : rnn_desc_t(desc), cfg_(cfg), prop_(prop) {
163         switch (alg) {
164         case VANILLA_LSTM:
165             n_weights = 1;
166             n_states = 2;
167             n_gates = 4;
168             break;
169         case VANILLA_GRU:
170             n_weights = 1;
171             n_states = 1;
172             n_gates = 3;
173             break;
174         case GRU_LINEAR_BEFORE_RESET:
175             n_weights = 1;
176             n_states = 1;
177             n_gates = 3;
178             break;
179         default:
180             n_weights = 1;
181             n_states = 1;
182             n_gates = 1;
183             break;
184         }
185
186         // TODO: recheck below condition
187         if (direction == mkldnn_bidirectional_concat
188                 || direction == mkldnn_bidirectional_sum)
189             n_direction = 2;
190         else
191             n_direction = 1;
192     }
193
194     const dt_conf_t *cfg_;
195     mkldnn_prop_kind_t prop_;
196     int n_direction; // 1 for unidirectional, 2 for bidirectional
197
198     int n_weights, n_states, n_gates;
199
200 private:
201     rnn_prb_t(const rnn_prb_t &) = delete;
202     rnn_prb_t &operator=(const rnn_prb_t &) = delete;
203 };
204
205 const size_t max_prb_len = 392;
206 void prb2str(const rnn_prb_t *p, const res_t *res, char *buffer);
207
208 void compute_ref_fwd(const rnn_prb_t *p, dnn_mem_t &input_m,
209         dnn_mem_t &states_m, dnn_mem_t &weights_input_m,
210         dnn_mem_t &weights_states_m, dnn_mem_t &bias_m,
211         dnn_mem_t &dst_last_layer_m, dnn_mem_t &dst_last_iteration_m,
212         mkldnn_rnn_direction_t direction);
213
214 void compute_ref_bwd(const rnn_prb_t *p, dnn_mem_t &input_m,
215         dnn_mem_t &states_m, dnn_mem_t &diff_last_layer_m,
216         dnn_mem_t &diff_last_iteration_m, dnn_mem_t &weights_input_m,
217         dnn_mem_t &weights_states_m, dnn_mem_t &bias_m,
218         dnn_mem_t &dst_last_layer_m, dnn_mem_t &dst_last_iteration_m,
219         dnn_mem_t &dst_diff_input_m, dnn_mem_t &dst_diff_states_m,
220         dnn_mem_t &dst_diff_weights_input_m,
221         dnn_mem_t &dst_diff_weights_states_m, dnn_mem_t &dst_diff_bias_m,
222         mkldnn_rnn_direction_t direction);
223
224 // mkldnn_ntc
225 inline size_t ntc_off_f(const rnn_prb_t *p, int n, int t, int c) {
226     return ((size_t)n * p->n_iter + t) * p->slc + c;
227 }
228
229 inline void inv_ntc_off_f(
230         const rnn_prb_t *p, size_t off, int &n, int &t, int &c) {
231     c = off % p->slc;
232     off /= p->slc;
233     t = off % p->n_iter;
234     off /= p->n_iter;
235     n = off % p->mb;
236     off /= p->mb;
237     assert(off == 0);
238 }
239
240 // mkldnn_ldsnc
241 inline size_t ldsnc_off_f(
242         const rnn_prb_t *p, int l, int d, int s, int n, int c) {
243     return ((((size_t)l * p->n_direction + d) * p->n_states + s) * p->mb + n)
244             * p->sic
245             + c;
246 }
247
248 inline void inv_ldsnc_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
249         int &s, int &n, int &c) {
250     c = off % p->sic;
251     off /= p->sic;
252     n = off % p->mb;
253     off /= p->mb;
254     s = off % p->n_states;
255     off /= p->n_states;
256     d = off % p->n_direction;
257     off /= p->n_direction;
258     l = off % p->n_layer;
259     off /= p->n_layer;
260     assert(off == 0);
261 }
262
263 // mkldnn_ldigo
264 inline size_t ldigo_off_f(
265         const rnn_prb_t *p, int l, int d, int w, int ic, int oc) {
266     return ((((size_t)l * p->n_direction + d) * p->n_weights + w) * (4 * p->slc)
267                    + ic)
268             * p->sic
269             + oc;
270 }
271
272 inline void inv_ldigo_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
273         int &w, int &ic, int &oc) {
274     oc = off % p->sic;
275     off /= p->sic;
276     ic = off % (4 * p->slc);
277     off /= (4 * p->slc);
278     w = off % p->n_weights;
279     off /= p->n_weights;
280     d = off % p->n_direction;
281     off /= p->n_direction;
282     l = off % p->n_layer;
283     off /= p->n_layer;
284     assert(off == 0);
285 }
286
287 // mkldnn_ldwOcIc
288 inline size_t ldwOcIc_off_f(
289         const rnn_prb_t *p, int l, int d, int w, int oc, int ic) {
290     return ((((size_t)l * p->n_direction + d) * p->n_weights + w) * (4 * p->sic)
291                    + oc)
292             * p->slc
293             + ic;
294 }
295
296 inline void inv_ldwOcIc_off_f(const rnn_prb_t *p, size_t off, int &l, int &d,
297         int &w, int &oc, int &ic) {
298     ic = off % p->slc;
299     off /= p->slc;
300     oc = off % (4 * p->sic);
301     off /= (4 * p->sic);
302     w = off % p->n_weights;
303     off /= p->n_weights;
304     d = off % p->n_direction;
305     off /= p->n_direction;
306     l = off % p->n_layer;
307     off /= p->n_layer;
308     assert(off == 0);
309 }
310
311 // bias: mkldnn_ldgo
312 inline size_t ldgo_off_f(const rnn_prb_t *p, int l, int d, int b, int c) {
313     return (((size_t)l * p->n_direction + d) * p->n_gates + b) * p->sic + c;
314 }
315
316 inline void inv_ldgo_off_f(
317         const rnn_prb_t *p, size_t off, int &l, int &d, int &b, int &c) {
318     c = off % p->sic;
319     off /= p->sic;
320     b = off % p->n_gates;
321     off /= p->n_gates;
322     d = off % p->n_direction;
323     off /= p->n_direction;
324     l = off % p->n_layer;
325     off /= p->n_layer;
326     assert(off == 0);
327 }
328
329 // dst_last_layer: mkldnn_tnc
330 inline size_t tnc_off_f(const rnn_prb_t *p, int s, int t, int n, int c) {
331     return (((size_t)s * p->n_iter + t) * p->mb + n) * p->sic + c;
332 }
333
334 inline void inv_tnc_off_f(
335         const rnn_prb_t *p, size_t off, int &s, int &t, int &n, int &c) {
336     c = off % p->sic;
337     off /= p->sic;
338     n = off % p->mb;
339     off /= p->mb;
340     t = off % p->n_iter;
341     off /= p->n_iter;
342     s = off % p->n_states;
343     off /= p->n_states;
344     assert(off == 0);
345 }
346
347 void perf_report(const rnn_prb_t *p, const res_t *r, const char *pstr);
348
349 int doit(const rnn_prb_t *p, res_t *res);
350 void check(const rnn_prb_t *p);
351 int bench(int argc, char **argv);
352 } // namespace rnn
353
354 #endif