Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / tests / unit / engines / gna / gna_matcher.hpp
1 //
2 // Copyright 2016-2018 Intel Corporation.
3 //
4 // This software and the related documents are Intel copyrighted materials,
5 // and your use of them is governed by the express license under which they
6 // were provided to you (End User License Agreement for the Intel(R) Software
7 // Development Products (Version May 2017)). Unless the License provides
8 // otherwise, you may not use, modify, copy, publish, distribute, disclose or
9 // transmit this software or the related documents without Intel's prior
10 // written permission.
11 //
12 // This software and the related documents are provided as is, with no
13 // express or implied warranties, other than those that are expressly
14 // stated in the License.
15 //
16
17 #pragma once
18 #include <limits>
19 #include <inference_engine/graph_tools.hpp>
20 #include "gtest/gtest.h"
21 #include "inference_engine.hpp"
22 #include "gna/gna_config.hpp"
23 #include "gna_plugin.hpp"
24 #include "gna-api.h"
25 #include "test_irs.hpp"
26 #include "dnn.h"
27
28
29 #define withConfig(key, value) withGNAConfig(GNA_CONFIG_KEY(key), value)
30 #define ASSERT_NO_THROW_IE_EXCEPTION(expr) \
31 try {\
32 expr;\
33 }catch(std::exception & e) {\
34     FAIL() << e.what();\
35 }\
36 catch(...) {\
37     FAIL() << "unknown exception";\
38 }
39
40 /**
41  * GNA unit tests environment
42  */
43 class GnaPluginTestEnvironment {
44  public:
45     struct NnetPrecision {
46         InferenceEngine::Precision input_precision;
47         InferenceEngine::Precision output_precision;
48         InferenceEngine::Precision weights_precision;
49         InferenceEngine::Precision biases_precision;
50     };
51     enum MatchWhat {
52         exactNNetStructure,
53         matchNone,
54         matchProcType,
55         matchPrecision,
56         matchPwlInserted,
57         matchConvInserted,
58         matchMaxPoolingInserted,
59         matchPwlQuantizeMetrics,
60         matchCopyInserted,
61         matchDiagonalInserted,
62         saveArgs,
63         matchInputData,
64         fillOutputValues,
65         matchAffineWeightsTranspose,
66         matchAffineWeights,
67         saveAffineWeights
68     };
69     std::vector<MatchWhat> whatToMatch;
70     enum {
71         kUnset = -1,
72         kAnyNotNull= -2
73     };
74     InferenceEngine::TargetDevice target_device =
75                             InferenceEngine::TargetDevice::eGNA;
76     int matchQuantity = kUnset;
77     int numberOfStates = kUnset;
78     bool matchInserted = true;
79     NnetPrecision nnet_precision;
80     float quantization_presicion_threshold = 1.0f;
81     uint16_t quantization_segments_threshold = UINT16_MAX;
82     uint32_t type = 0;
83     std::string model;
84     std::string exportedModelFileName;
85     bool exportNetworkOnly = false;
86     std::function<void (InferenceEngine::CNNNetwork &)> cb;
87     std::map<std::string, std::string> config;
88     GNAPluginNS::Policy policy;
89     bool matchThrows = false;
90     uint32_t proc_type = static_cast<intel_gna_proc_t>(GNA_SOFTWARE & GNA_HARDWARE);
91     std::string importedModelFileName;
92     bool is_profiling_enabled = false;
93     bool matchOutput = false;
94     bool is_setup_of_omp_theads_expected = false;
95     std::vector<int16_t> input_processed;
96     InferenceEngine::Precision input_precision = InferenceEngine::Precision::FP32;
97     std::map<std::string, std::vector<float>> input_init;
98     std::vector<float> expected_output;
99     int16_t fillValue = 0;
100     std::vector<float> weightsFillPattern;
101     std::pair<int, int> transposeArgs;
102     std::pair<int, int> transposedArgsForSaving;
103     std::vector<uint16_t>* transposedData;
104 };
105
106 class GNATestBase {
107  public:
108     virtual ~GNATestBase() = default;
109 };
110
111 template <class T>
112 class GNATestConfigurability : public GNATestBase{
113  protected:
114     bool needNextMatcher = true;
115     GnaPluginTestEnvironment _env;
116     GnaPluginTestEnvironment::MatchWhat & getMatcher() {
117         if (needNextMatcher) {
118             needNextMatcher = false;
119             _env.whatToMatch.push_back({});
120         }
121         return _env.whatToMatch.back();
122     }
123  public:
124     GNATestConfigurability(GnaPluginTestEnvironment env) : _env(env) {
125     }
126     T & And() {
127         needNextMatcher = true;
128         return *dynamic_cast<T*>(this);
129     }
130     template <class VType>
131     T & withGNAConfig(const std::string &keyName, const VType &value) {
132         std::stringstream ss;
133         ss << value;
134         _env.config[keyName] = ss.str();
135         return *dynamic_cast<T*>(this);
136     }
137     T & withGNADeviceMode(std::string value) {
138         _env.config[GNA_CONFIG_KEY(DEVICE_MODE)] = value;
139         return *dynamic_cast<T*>(this);
140     }
141     T & withAcceleratorThreadsNumber(std::string value) {
142         _env.config[GNA_CONFIG_KEY(LIB_N_THREADS)] = value;
143         return *dynamic_cast<T*>(this);
144     }
145     T & throws() {
146         _env.matchThrows = true;
147         return *dynamic_cast<T*>(this);
148     }
149     T & profiling_counters() {
150         _env.is_profiling_enabled = true;
151         _env.config[CONFIG_KEY(PERF_COUNT)] = InferenceEngine::PluginConfigParams::YES;
152         return *dynamic_cast<T*>(this);
153     }
154
155     T & enable_omp_multithreading() {
156         _env.is_setup_of_omp_theads_expected = true;
157         _env.config[CONFIG_KEY(SINGLE_THREAD)] = InferenceEngine::PluginConfigParams::NO;
158         return *dynamic_cast<T*>(this);
159     }
160 };
161
162 /**
163  * @brief matches loadnetwork + infer + call to gna_api propagate
164  */
165 class GNAPropagateMatcher : public GNATestConfigurability<GNAPropagateMatcher> {
166  public:
167     using base = GNATestConfigurability<GNAPropagateMatcher>;
168     using base::base;
169     using base::getMatcher;
170
171     ~GNAPropagateMatcher() {
172         match();
173     }
174
175     GNAPropagateMatcher & called() {
176         // inserting default matcher that matches any propagate_forward call
177         getMatcher();
178         return *this;
179     }
180
181     GNAPropagateMatcher & returns() {
182         return *this;
183     }
184
185     GNAPropagateMatcher & And() {
186         return *this;
187     }
188
189     GNAPropagateMatcher & that() {
190         return *this;
191     }
192
193     GNAPropagateMatcher & result() {
194         return *this;
195     }
196
197     GNAPropagateMatcher & called_with() {
198         return *this;
199     }
200
201     GNAPropagateMatcher & called_without() {
202         _env.matchInserted = false;
203         return *this;
204     }
205     /**
206      * @brief gna_propagate_forward will fill all output pointers of 16 bits with this value
207      */
208     GNAPropagateMatcher & filledWith(int16_t valueToFill) {
209         _env.fillValue = valueToFill;
210         getMatcher() = GnaPluginTestEnvironment::fillOutputValues;
211         return *this;
212     }
213
214     GNAPropagateMatcher & equal_to(const std::vector<float>& expect) {
215         _env.matchOutput = true;
216         _env.expected_output = expect;
217         return *this;
218     }
219
220     GNAPropagateMatcher & input(const std::string & inputName, const std::vector<float>& inputData) {
221         _env.input_init[inputName] = inputData;
222         return *this;
223     }
224
225     GNAPropagateMatcher & inputScale(const std::string & inputName, float scaleFactor) {
226         _env.config[std::string(GNA_CONFIG_KEY(SCALE_FACTOR)) + "_" + inputName] = std::to_string(scaleFactor);
227         return *this;
228     }
229
230     GNAPropagateMatcher & called_with_input_and_expected_output(const std::vector<float>& input_data,
231                                                                 const std::vector<float>& expect) {
232         _env.matchOutput = true;
233         _env.input_init["any_input_name"] = input_data;
234         _env.expected_output = expect;
235         return *this;
236     }
237
238     GNAPropagateMatcher & once() {
239         _env.matchQuantity = 1;
240         return *this;
241     }
242
243     GNAPropagateMatcher & twice() {
244         _env.matchQuantity = 2;
245         return *this;
246     }
247
248     GNAPropagateMatcher & args(std::string args) {
249         return *this;
250     }
251
252     GNAPropagateMatcher & exact_nnet_structure(intel_nnet_type_t * pNet) {
253
254         getMatcher() = GnaPluginTestEnvironment::exactNNetStructure;
255         original_nnet = pNet;
256         return *this;
257     }
258
259     GNAPropagateMatcher & pwl_inserted_into_nnet() {
260         getMatcher() = GnaPluginTestEnvironment::matchPwlInserted;
261         return *this;
262     }
263
264     GNAPropagateMatcher & max_pooling_inserted_into_nnet() {
265         getMatcher() = GnaPluginTestEnvironment::matchMaxPoolingInserted;
266         return *this;
267     }
268
269     GNAPropagateMatcher & succeed() {
270         return *this;
271     }
272
273     GNAPropagateMatcher & convolution_inserted_into_nnet() {
274         getMatcher() = GnaPluginTestEnvironment::matchConvInserted;
275         return *this;
276     }
277
278
279     GNAPropagateMatcher & pwl_quantization_activation(uint32_t activation_type) {
280         getMatcher() = GnaPluginTestEnvironment::matchPwlQuantizeMetrics;
281         _env.type = activation_type;
282         return *this;
283     }
284
285     GNAPropagateMatcher & pwl_quantization_precision_threshold(float threshold) {
286         getMatcher() = GnaPluginTestEnvironment::matchPwlQuantizeMetrics;
287         _env.quantization_presicion_threshold = threshold;
288         return *this;
289     }
290
291     GNAPropagateMatcher & pwl_quantization_segments_threshold(uint16_t threshold) {
292         getMatcher() = GnaPluginTestEnvironment::matchPwlQuantizeMetrics;
293         _env.quantization_segments_threshold = threshold;
294         return *this;
295     }
296
297     GNAPropagateMatcher & diagonal_inserted_into_nnet() {
298         getMatcher() = GnaPluginTestEnvironment::matchDiagonalInserted;
299         return *this;
300     }
301
302     GNAPropagateMatcher &preprocessed_input_data(std::vector<float> input_init, std::vector<int16_t> input_processed,
303                                                  InferenceEngine::Precision inputPrecision) {
304         getMatcher() = GnaPluginTestEnvironment::matchInputData;
305         _env.input_processed = std::move(input_processed);
306         _env.input_init["placeholder"] = std::move(input_init);
307         _env.input_precision = inputPrecision;
308         return *this;
309     }
310
311     GNAPropagateMatcher & copy_inserted_into_nnet() {
312         getMatcher() = GnaPluginTestEnvironment::matchCopyInserted;
313         return *this;
314     }
315
316
317     GNAPropagateMatcher & affine_weights_transpozed(std::pair<int, int> &&transpozedArgs) {
318         getMatcher() = GnaPluginTestEnvironment::saveAffineWeights;
319         _env.transposedArgsForSaving = std::move(transpozedArgs);
320
321         return *this;
322     }
323
324     GNAPropagateMatcher & affine_weights() {
325         getMatcher() = GnaPluginTestEnvironment::saveAffineWeights;
326         return *this;
327     }
328
329     GNAPropagateMatcher & affine_weights_eq(std::vector<uint16_t> & sourceWeights) {
330         getMatcher() = GnaPluginTestEnvironment::matchAffineWeights;
331         _env.transposedData = &sourceWeights;
332         return *this;
333     }
334
335
336     GNAPropagateMatcher & affine_weights_transposed(std::vector<uint16_t> & sourceWeights, std::pair<int,int> transposeData) {
337         getMatcher() = GnaPluginTestEnvironment::matchAffineWeightsTranspose;
338         _env.transposeArgs = transposeData;
339         _env.transposedData = &sourceWeights;
340         return *this;
341     }
342
343     GNAPropagateMatcher & nnet_input_precision(const InferenceEngine::Precision &precision) {
344         getMatcher() = GnaPluginTestEnvironment::matchPrecision;
345         _env.nnet_precision.input_precision = precision;
346         return *this;
347     }
348     GNAPropagateMatcher & nnet_ouput_precision(const InferenceEngine::Precision &precision) {
349         getMatcher() = GnaPluginTestEnvironment::matchPrecision;
350         _env.nnet_precision.output_precision = precision;
351         return *this;
352     }
353     GNAPropagateMatcher & nnet_weights_precision(const InferenceEngine::Precision &precision) {
354         getMatcher() = GnaPluginTestEnvironment::matchPrecision;
355         _env.nnet_precision.weights_precision = precision;
356         return *this;
357     }
358     GNAPropagateMatcher & nnet_biases_precision(const InferenceEngine::Precision &precision) {
359         getMatcher() = GnaPluginTestEnvironment::matchPrecision;
360         _env.nnet_precision.biases_precision = precision;
361         return *this;
362     }
363
364     GNAPropagateMatcher & proc_type(uint32_t proc_type) {
365         getMatcher() = GnaPluginTestEnvironment::matchProcType;
366         _env.proc_type = proc_type;
367         return * this;
368     }
369
370     GNAPropagateMatcher & to(intel_nnet_type_t *savedNet) {
371         this->savedNet = savedNet;
372         return *this;
373     }
374
375     GNAPropagateMatcher & to(std::vector<uint16_t> & sourceWeights) {
376         _env.transposedData = &sourceWeights;
377         return *this;
378     }
379
380
381
382     GNAPropagateMatcher & onCPU() {
383         _env.target_device = InferenceEngine::TargetDevice::eCPU;
384         return *this;
385     }
386  protected:
387     void match();
388     intel_nnet_type_t * original_nnet = nullptr;
389     intel_nnet_type_t * savedNet = nullptr;
390 };
391
392
393 /**
394  * @brief GNAPlugin matches creation only case
395  */
396 class GNAPluginCreationMatcher : public GNATestConfigurability<GNAPluginCreationMatcher> {
397  public:
398     using base = GNATestConfigurability<GNAPluginCreationMatcher>;
399     using base::base;
400
401     GNAPluginCreationMatcher & gna_plugin() {
402         return * this;
403     }
404     ~GNAPluginCreationMatcher () {
405         match();
406     }
407  protected:
408     void match();
409 };
410
411 /**
412  * @brief GNAPlugin matches creation only case
413  */
414 class GNAPluginAOTMatcher : public GNATestConfigurability<GNAPluginAOTMatcher> {
415  public:
416     using base = GNATestConfigurability<GNAPluginAOTMatcher>;
417     using base::base;
418
419     ~GNAPluginAOTMatcher() {
420         match();
421     }
422  protected:
423     void match();
424 };
425
426 /**
427  * @brief xnn api tests
428  */
429 class GNADumpXNNMatcher : public GNATestConfigurability<GNADumpXNNMatcher> {
430  public:
431     using base = GNATestConfigurability<GNADumpXNNMatcher>;
432     using base::base;
433
434     ~GNADumpXNNMatcher() {
435         if (match_in_dctor) {
436             match();
437         }
438     }
439     GNADumpXNNMatcher& called() {
440         return *this;
441     }
442  protected:
443
444     bool match_in_dctor = true;
445     void load(GNAPluginNS::GNAPlugin & plugin);
446     void match();
447 };
448
449 /**
450  * @brief xnn api tests
451  */
452 class GNAQueryStateMatcher : public GNADumpXNNMatcher {
453  public:
454     using base = GNADumpXNNMatcher;
455     using base::base;
456
457     ~GNAQueryStateMatcher() {
458         if (match_in_dctor) {
459             match();
460             match_in_dctor = false;
461         }
462     }
463     void isEmpty() {
464         _env.numberOfStates = 0;
465     }
466     void isNotEmpty() {
467         _env.numberOfStates = GnaPluginTestEnvironment::kAnyNotNull;
468     }
469
470  protected:
471     void match();
472 };
473
474
475
476 /**
477  * @brief base for test fixture
478  */
479 class GNATest : public ::testing::Test, public GNATestConfigurability<GNATest>  {
480     using base = GNATestConfigurability<GNATest>;
481     using base::_env;
482     class XStorage {
483      public:
484         std::vector<uint8_t> data;
485         std::function<void (void *)> destroyer;
486        ~XStorage() {
487            destroyer(&data.front());
488        }
489     };
490     std::list<XStorage> dataUsedInMatchers;
491     std::list<std::shared_ptr<GNATestBase>> returnedMatchers;
492
493  public:
494     template <class T>
495     T & storage () {
496         dataUsedInMatchers.push_back({std::vector<uint8_t >(sizeof(T)), [](void * toDestroy) {
497             reinterpret_cast<T*>(toDestroy)->~T();
498         }});
499
500         auto ptr = reinterpret_cast<T*> (&dataUsedInMatchers.back().data.front());
501         // sad to say we are not using destructors here so data might leak
502         new(ptr) T;
503
504         return *ptr;
505     }
506     GNATest()  : base(GnaPluginTestEnvironment()) {}
507     GNATest & as() {
508         return *this;
509     }
510     GNATest & model() {
511         return *this;
512     }
513     GNATest & assert_that() {
514         return *this;
515     }
516     GNATest & export_network(std::string modelName) {
517         _env.model = modelName;
518         _env.exportNetworkOnly = true;
519         return *this;
520     }
521     GNATest & save_args() {
522         getMatcher() = GnaPluginTestEnvironment::saveArgs;
523         return *this;
524     }
525     GNATest & save() {
526         return *this;
527     }
528
529     GNATest & onInfer1AFModel() {
530         _env.model = GNATestIRs::Fc2DOutputModel();
531         return *this;
532     }
533     GNATest & onLoad(std::string _model) {
534         _env.model = _model;
535         return *this;
536     }
537     GNATest & afterLoadingModel(std::string _model) {
538         _env.model = _model;
539         return *this;
540     }
541
542     GNAQueryStateMatcher & queryState() {
543         returnedMatchers.push_back(std::make_shared<GNAQueryStateMatcher>(_env));
544         // clearing env;
545         _env = GnaPluginTestEnvironment();
546         return dynamic_cast<GNAQueryStateMatcher&>(*returnedMatchers.back());
547     }
548
549     /**importing indicates no infer happened ata all **/
550     GNAPropagateMatcher & importingModelFrom(std::string fileName) {
551         _env.importedModelFileName = fileName;
552         returnedMatchers.push_back(std::make_shared<GNAPropagateMatcher>(_env));
553         // clearing env;
554         _env = GnaPluginTestEnvironment();
555         return dynamic_cast<GNAPropagateMatcher&>(*returnedMatchers.back());
556     }
557     GNATest & importedFrom(std::string fileName) {
558         _env.importedModelFileName = fileName;
559         return *this;
560     }
561     GNATest & onInferModel(std::string _model = "",
562                            std::function<void (InferenceEngine::CNNNetwork &)> _cb = [](InferenceEngine::CNNNetwork & net){}) {
563         _env.model = _model;
564         _env.cb = _cb;
565         return *this;
566     }
567     GNATest &  withWeigthsPattern(std::vector<float> && initializer) {
568         _env.weightsFillPattern = std::move(initializer);
569         return *this;
570     }
571     GNATest & gna() {
572         return *this;
573     }
574     GNATest & from() {
575         return *this;
576     }
577     GNATest & inNotCompactMode() {
578         _env.config[GNA_CONFIG_KEY(COMPACT_MODE)] = CONFIG_VALUE(NO);
579         return *this;
580     }
581     GNATest & withUniformPWLAlgo() {
582         base::_env.config[GNA_CONFIG_KEY(PWL_UNIFORM_DESIGN)] = CONFIG_VALUE(YES);
583         return *this;
584     }
585     GNAPropagateMatcher& propagate_forward() {
586         returnedMatchers.push_back(std::make_shared<GNAPropagateMatcher>(_env));
587         //clearing env;
588         _env = GnaPluginTestEnvironment();
589         return dynamic_cast<GNAPropagateMatcher&>(*returnedMatchers.back());
590     }
591     GNADumpXNNMatcher& dumpXNN() {
592         returnedMatchers.push_back(std::make_shared<GNADumpXNNMatcher>(_env));
593         //clearing env;
594         _env = GnaPluginTestEnvironment();
595         return dynamic_cast<GNADumpXNNMatcher&>(*returnedMatchers.back());
596     }
597     GNATest & withNanScaleFactor() {
598         base::_env.config[GNA_CONFIG_KEY(SCALE_FACTOR)] = std::to_string(std::numeric_limits<float>::quiet_NaN());
599         return *this;
600     }
601     GNATest & withInfScaleFactor() {
602         base::_env.config[GNA_CONFIG_KEY(SCALE_FACTOR)] = std::to_string(std::numeric_limits<float>::infinity());
603         return *this;
604     }
605     GNAPluginCreationMatcher creating() {
606         return _env;
607     }
608
609     GNAPluginAOTMatcher & to (std::string fileName) {
610         _env.exportedModelFileName = fileName;
611         returnedMatchers.push_back(std::make_shared<GNAPluginAOTMatcher>(_env));
612         //clearing env;
613         _env = GnaPluginTestEnvironment();
614         return dynamic_cast<GNAPluginAOTMatcher&>(*returnedMatchers.back());
615     }
616
617     static void fillWeights(InferenceEngine::Blob::Ptr weights, std::vector<float> pattern = {1.f}) {
618         float * p = weights->buffer().as<float *>();
619         float * pEnd = p + weights->byteSize() / sizeof(float);
620
621         for(; p!=pEnd ;) {
622             for (int i = 0; i != (weights->byteSize() / sizeof(float) / 3) + 1; i++) {
623                 for (int j = 0; j != pattern.size() && p != pEnd; j++, p++) {
624                     *p = pattern[j];
625                 }
626             }
627         }
628     }
629 };