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