1696cd34dc0705e9ada691747821e279ca3026f1
[platform/core/ml/nntrainer.git] / test / unittest / compiler / unittest_realizer.cpp
1 // SPDX-License-Identifier: Apache-2.0
2 /**
3  * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
4  *
5  * @file unittest_realizer.h
6  * @date 09 October 2021
7  * @brief NNTrainer graph realizer related tests
8  * @see https://github.com/nnstreamer/nntrainer
9  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
10  * @bug No known bugs except for NYI items
11  */
12 #include <gtest/gtest.h>
13
14 #include <vector>
15
16 #include <activation_realizer.h>
17 #include <bn_realizer.h>
18 #include <connection.h>
19 #include <flatten_realizer.h>
20 #include <input_realizer.h>
21 #include <loss_realizer.h>
22 #include <multiout_realizer.h>
23 #include <nntrainer_error.h>
24 #include <previous_input_realizer.h>
25 #include <realizer.h>
26 #include <recurrent_realizer.h>
27 #include <remap_realizer.h>
28 #include <slice_realizer.h>
29
30 #include <compiler_test_util.h>
31 #include <nntrainer_test_util.h>
32
33 using namespace nntrainer;
34
35 /**
36  * @brief check realize and equal
37  *
38  * @param realizer realizer to use
39  * @param input input
40  * @param expected expected output
41  */
42 static void realizeAndEqual(GraphRealizer &realizer,
43                             const std::vector<LayerRepresentation> &input,
44                             const std::vector<LayerRepresentation> &expected) {
45   auto processed = realizer.realize(makeGraph(input));
46   auto expected_graph = makeGraph(expected);
47   graphEqual(processed, expected_graph);
48 }
49
50 static void compileAndRealizeAndEqual(
51   GraphRealizer &realizer,
52   std::vector<std::unique_ptr<GraphRealizer>> &realizers,
53   const std::vector<LayerRepresentation> &input,
54   const std::vector<LayerRepresentation> &expected) {
55   auto processed = realizer.realize(makeCompiledGraph(input, realizers));
56   std::vector<std::unique_ptr<nntrainer::GraphRealizer>> defalute_realizers;
57   auto expected_graph = makeCompiledGraph(expected, realizers);
58
59   graphEqual(processed, expected_graph);
60 }
61
62 TEST(FlattenRealizer, flatten_p) {
63   FlattenRealizer fr;
64
65   LayerRepresentation input1 = {
66     "fully_connected",
67     {"name=layer1", "flatten=true"},
68   };
69   LayerRepresentation expected1 = {"fully_connected", {"name=layer1"}};
70   LayerRepresentation expected2 = {
71     "flatten",
72     {"name=layer1/flatten_realized", "input_layers=layer1"},
73   };
74
75   EXPECT_NO_THROW(realizeAndEqual(fr, {input1}, {expected1, expected2}));
76 }
77
78 TEST(RecurrentRealizer, recurrent_no_return_sequence_p) {
79   using C = Connection;
80
81   RecurrentRealizer r(
82     {"unroll_for=3", "recurrent_input=fc_in", "recurrent_output=fc_out"},
83     {C("source")}, {C("fc_out")});
84
85   std::vector<LayerRepresentation> before = {
86     {"fully_connected", {"name=fc_in", "input_layers=source"}},
87     {"fully_connected", {"name=fc_out", "input_layers=fc_in"}}};
88
89   std::vector<LayerRepresentation> expected = {
90     /// t - 0
91     {"fully_connected",
92      {"name=fc_in/0", "input_layers=source", "shared_from=fc_in/0"}},
93     {"fully_connected",
94      {"name=fc_out/0", "input_layers=fc_in/0", "shared_from=fc_out/0"}},
95
96     /// t - 1
97     {"fully_connected",
98      {"name=fc_in/1", "input_layers=fc_out/0", "shared_from=fc_in/0"}},
99     {"fully_connected",
100      {"name=fc_out/1", "input_layers=fc_in/1", "shared_from=fc_out/0"}},
101
102     /// t - 2
103     {"fully_connected",
104      {"name=fc_in/2", "input_layers=fc_out/1", "shared_from=fc_in/0"}},
105     {"fully_connected",
106      {"name=fc_out/2", "input_layers=fc_in/2", "shared_from=fc_out/0"}},
107
108     /// mapping
109     {"identity", {"name=fc_out", "input_layers=fc_out/2"}},
110   };
111
112   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
113 }
114
115 TEST(RecurrentRealizer, recurrent_input_is_sequence_p) {
116   using C = Connection;
117
118   RecurrentRealizer r({"unroll_for=3", "input_is_sequence=source",
119                        "recurrent_input=fc_out", "recurrent_output=fc_out"},
120                       {C("source")}, {C("fc_out")});
121
122   std::vector<LayerRepresentation> before = {
123     {"fully_connected", {"name=fc_in", "input_layers=source"}},
124     {"fully_connected", {"name=fc_out", "input_layers=fc_in"}}};
125
126   std::vector<LayerRepresentation> expected = {
127     /// t - 0
128     {"fully_connected",
129      {"name=fc_in/0", "input_layers=source/0", "shared_from=fc_in/0"}},
130     {"fully_connected",
131      {"name=fc_out/0", "input_layers=fc_in/0", "shared_from=fc_out/0"}},
132
133     /// t - 1
134     {"fully_connected",
135      {"name=fc_in/1", "input_layers=source/1", "shared_from=fc_in/0"}},
136     {"fully_connected",
137      {"name=fc_out/1", "input_layers=fc_out/0", "shared_from=fc_out/0"}},
138
139     /// t - 2
140     {"fully_connected",
141      {"name=fc_in/2", "input_layers=source/2", "shared_from=fc_in/0"}},
142     {"fully_connected",
143      {"name=fc_out/2", "input_layers=fc_out/1", "shared_from=fc_out/0"}},
144
145     /// mapping
146     {"identity", {"name=fc_out", "input_layers=fc_out/2"}},
147   };
148
149   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
150 }
151
152 TEST(RecurrentRealizer, recurrent_return_sequence_single_p) {
153   using C = Connection;
154   RecurrentRealizer r({"unroll_for=3", "as_sequence=fc_out",
155                        "recurrent_input=lstmcell", "recurrent_output=fc_out"},
156                       {C("source")}, {C("fc_out")});
157
158   std::vector<LayerRepresentation> before = {
159     {"lstmcell", {"name=lstmcell", "input_layers=source"}},
160     {"fully_connected", {"name=fc_out", "input_layers=lstmcell"}}};
161
162   std::vector<LayerRepresentation> expected = {
163     /// t - 0
164     {"lstmcell",
165      {"name=lstmcell/0", "input_layers=source", "shared_from=lstmcell/0"}},
166     {"fully_connected",
167      {"name=fc_out/0", "input_layers=lstmcell/0", "shared_from=fc_out/0"}},
168
169     /// t - 1
170     {"lstmcell",
171      {"name=lstmcell/1", "input_layers=fc_out/0", "shared_from=lstmcell/0"}},
172     {"fully_connected",
173      {"name=fc_out/1", "input_layers=lstmcell/1", "shared_from=fc_out/0"}},
174
175     /// t - 2
176     {"lstmcell",
177      {"name=lstmcell/2", "input_layers=fc_out/1", "shared_from=lstmcell/0"}},
178     {"fully_connected",
179      {"name=fc_out/2", "input_layers=lstmcell/2", "shared_from=fc_out/0"}},
180
181     /// mapping
182     {"concat",
183      {"name=fc_out/concat_0", "input_layers=fc_out/0,fc_out/1,fc_out/2"}},
184     {"identity", {"name=fc_out", "input_layers=fc_out/concat_0"}},
185   };
186
187   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
188 }
189
190 TEST(RecurrentRealizer, recurrent_multi_inout_return_seq_p) {
191   using C = Connection;
192   RecurrentRealizer r(
193     {
194       "unroll_for=3",
195       "as_sequence=fc_out",
196       "recurrent_input=lstmcell,add(2)",
197       "recurrent_output=fc_out,split(1)",
198     },
199     {C("source"), C("source2"), C("source3")}, {C("fc_out")});
200
201   /// @note for below graph,
202   /// 1. fc_out feds back to lstmcell
203   /// 2. ouput_dummy feds back to source2_dummy
204   /// ========================================================
205   /// lstmcell        -------- addition - split ---- fc_out (to_lstmcell)
206   /// source2_dummy   --/                  \----- (to addition 3)
207   std::vector<LayerRepresentation> before = {
208     {"lstmcell", {"name=lstmcell", "input_layers=source"}},
209     {"addition", {"name=add", "input_layers=lstmcell,source2,source3"}},
210     {"split", {"name=split", "input_layers=add"}},
211     {"fully_connected", {"name=fc_out", "input_layers=split(0)"}},
212   };
213
214   std::vector<LayerRepresentation> expected = {
215     /// timestep 0
216     {"lstmcell",
217      {"name=lstmcell/0", "input_layers=source", "shared_from=lstmcell/0"}},
218     {"addition",
219      {"name=add/0", "input_layers=lstmcell/0,source2,source3",
220       "shared_from=add/0"}},
221     {"split", {"name=split/0", "input_layers=add/0", "shared_from=split/0"}},
222     {"fully_connected",
223      {"name=fc_out/0", "input_layers=split/0(0)", "shared_from=fc_out/0"}},
224
225     /// timestep 1
226     {"lstmcell",
227      {"name=lstmcell/1", "input_layers=fc_out/0", "shared_from=lstmcell/0"}},
228     {"addition",
229      {"name=add/1", "input_layers=lstmcell/1,source2,split/0(1)",
230       "shared_from=add/0"}},
231     {"split", {"name=split/1", "input_layers=add/1", "shared_from=split/0"}},
232     {"fully_connected",
233      {"name=fc_out/1", "input_layers=split/1(0)", "shared_from=fc_out/0"}},
234
235     /// timestep 2
236     {"lstmcell",
237      {"name=lstmcell/2", "input_layers=fc_out/1", "shared_from=lstmcell/0"}},
238     {"addition",
239      {"name=add/2", "input_layers=lstmcell/2,source2,split/1(1)",
240       "shared_from=add/0"}},
241     {"split", {"name=split/2", "input_layers=add/2", "shared_from=split/0"}},
242     {"fully_connected",
243      {"name=fc_out/2", "input_layers=split/2(0)", "shared_from=fc_out/0"}},
244
245     /// mapping
246     {"concat",
247      {"name=fc_out/concat_0", "input_layers=fc_out/0,fc_out/1,fc_out/2"}},
248     {"identity", {"name=fc_out", "input_layers=fc_out/concat_0"}},
249   };
250
251   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
252 }
253
254 TEST(RecurrentRealizer, recurrent_multi_inout_using_connection_p) {
255   using C = Connection;
256   RecurrentRealizer r(
257     {
258       "unroll_for=3",
259       "recurrent_input=lstmcell,add(2)",
260       "recurrent_output=fc_out,split(1)",
261     },
262     {C("source"), C("source2"), C("source3")}, {C("fc_out")});
263
264   /// @note for below graph,
265   /// 1. fc_out feds back to lstmcell
266   /// 2. ouput_dummy feds back to source2_dummy
267   /// ========================================================
268   /// lstmcell        -------- addition - split ---- fc_out (to_lstmcell)
269   /// source2_dummy   --/                  \----- (to addition 3)
270   std::vector<LayerRepresentation> before = {
271     {"lstmcell", {"name=lstmcell", "input_layers=source"}},
272     {"addition", {"name=add", "input_layers=lstmcell,source2,source3"}},
273     {"split", {"name=split", "input_layers=add"}},
274     {"fully_connected", {"name=fc_out", "input_layers=split(0)"}},
275   };
276
277   std::vector<LayerRepresentation> expected = {
278     /// timestep 0
279     {"lstmcell",
280      {"name=lstmcell/0", "input_layers=source", "shared_from=lstmcell/0"}},
281     {"addition",
282      {"name=add/0", "input_layers=lstmcell/0,source2,source3",
283       "shared_from=add/0"}},
284     {"split", {"name=split/0", "input_layers=add/0", "shared_from=split/0"}},
285     {"fully_connected",
286      {"name=fc_out/0", "input_layers=split/0(0)", "shared_from=fc_out/0"}},
287
288     /// timestep 1
289     {"lstmcell",
290      {"name=lstmcell/1", "input_layers=fc_out/0", "shared_from=lstmcell/0"}},
291     {"addition",
292      {"name=add/1", "input_layers=lstmcell/1,source2,split/0(1)",
293       "shared_from=add/0"}},
294     {"split", {"name=split/1", "input_layers=add/1", "shared_from=split/0"}},
295     {"fully_connected",
296      {"name=fc_out/1", "input_layers=split/1(0)", "shared_from=fc_out/0"}},
297
298     /// timestep 2
299     {"lstmcell",
300      {"name=lstmcell/2", "input_layers=fc_out/1", "shared_from=lstmcell/0"}},
301     {"addition",
302      {"name=add/2", "input_layers=lstmcell/2,source2,split/1(1)",
303       "shared_from=add/0"}},
304     {"split", {"name=split/2", "input_layers=add/2", "shared_from=split/0"}},
305     {"fully_connected",
306      {"name=fc_out/2", "input_layers=split/2(0)", "shared_from=fc_out/0"}},
307
308     /// mapping
309     {"identity", {"name=fc_out", "input_layers=fc_out/2"}},
310   };
311
312   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
313 }
314
315 TEST(RecurrentRealizer, recurrent_multi_inout_multi_connection_end_p) {
316   using C = Connection;
317   RecurrentRealizer r(
318     {
319       "unroll_for=3",
320       "recurrent_input=lstmcell,add(2)",
321       "recurrent_output=fc_out,split(1)",
322       "as_sequence=split(1)",
323     },
324     {
325       C("source"),
326       C("source2"),
327       C("source3"),
328     },
329     {
330       C("split(0)"),
331       C("split(1)"),
332     });
333
334   /// @note for below graph,
335   /// 1. fc_out feds back to lstmcell
336   /// 2. ouput_dummy feds back to source2_dummy
337   /// ========================================================
338   /// lstmcell        -------- addition - split ---- fc_out (to_lstmcell)
339   /// source2_dummy   --/                  \----- (to addition 3)
340   std::vector<LayerRepresentation> before = {
341     {"lstmcell", {"name=lstmcell", "input_layers=source"}},
342     {"addition", {"name=add", "input_layers=lstmcell,source2,source3"}},
343     {"split", {"name=split", "input_layers=add"}},
344     {"fully_connected", {"name=fc_out", "input_layers=split(0)"}},
345   };
346
347   std::vector<LayerRepresentation> expected = {
348     /// timestep 0
349     {"lstmcell",
350      {"name=lstmcell/0", "input_layers=source", "shared_from=lstmcell/0"}},
351     {"addition",
352      {"name=add/0", "input_layers=lstmcell/0,source2,source3",
353       "shared_from=add/0"}},
354     {"split", {"name=split/0", "input_layers=add/0", "shared_from=split/0"}},
355     {"fully_connected",
356      {"name=fc_out/0", "input_layers=split/0(0)", "shared_from=fc_out/0"}},
357
358     /// timestep 1
359     {"lstmcell",
360      {"name=lstmcell/1", "input_layers=fc_out/0", "shared_from=lstmcell/0"}},
361     {"addition",
362      {"name=add/1", "input_layers=lstmcell/1,source2,split/0(1)",
363       "shared_from=add/0"}},
364     {"split", {"name=split/1", "input_layers=add/1", "shared_from=split/0"}},
365     {"fully_connected",
366      {"name=fc_out/1", "input_layers=split/1(0)", "shared_from=fc_out/0"}},
367
368     /// timestep 2
369     {"lstmcell",
370      {"name=lstmcell/2", "input_layers=fc_out/1", "shared_from=lstmcell/0"}},
371     {"addition",
372      {"name=add/2", "input_layers=lstmcell/2,source2,split/1(1)",
373       "shared_from=add/0"}},
374     {"split", {"name=split/2", "input_layers=add/2", "shared_from=split/0"}},
375     {"fully_connected",
376      {"name=fc_out/2", "input_layers=split/2(0)", "shared_from=fc_out/0"}},
377
378     /// mapping
379     {"concat",
380      {"name=split/concat_1", "input_layers=split/0(1),split/1(1),split/2(1)"}},
381     {"identity", {"name=split", "input_layers=split/2(0),split/concat_1"}},
382   };
383
384   EXPECT_NO_THROW(realizeAndEqual(r, before, expected));
385 }
386
387 TEST(RemapRealizer, remap_01_n) {
388   std::function<void(std::string &, unsigned &)> remap_connection_function =
389     nullptr;
390
391   EXPECT_THROW(RemapRealizer r(remap_connection_function),
392                std::invalid_argument);
393 }
394
395 TEST(RemapRealizer, remap_02_n) {
396   std::function<void(std::string &)> remap_function = nullptr;
397
398   EXPECT_THROW(RemapRealizer r(remap_function), std::invalid_argument);
399 }
400
401 TEST(RemapRealizer, remap_03_n) {
402   auto model_graph = NetworkGraph();
403   LayerRepresentation input = {"input", {"name=layer1", "input_shape=1:1:1"}};
404
405   auto graph = makeGraph({input});
406   EXPECT_NO_THROW(model_graph.addLayer(graph[0]));
407   EXPECT_EQ(model_graph.compile("mse"), ML_ERROR_NONE);
408   EXPECT_NO_THROW(model_graph.finalizeContext(graph[0], {}));
409
410   RemapRealizer r([](std::string &name) { name = "scoped/" + name; });
411   EXPECT_THROW(r.realize(graph), std::invalid_argument);
412 }
413
414 TEST(RemapRealizer, remap_04_n) {
415   auto model_graph = NetworkGraph();
416   LayerRepresentation input = {"input", {"name=layer1", "input_shape=1:1:1"}};
417
418   auto graph = makeGraph({input});
419   EXPECT_NO_THROW(model_graph.addLayer(graph[0]));
420   EXPECT_EQ(model_graph.compile("mse"), ML_ERROR_NONE);
421   EXPECT_NO_THROW(model_graph.finalizeContext(graph[0], {}));
422
423   RemapRealizer r(
424     [](std::string &name, unsigned &_) { name = "scoped/" + name; });
425   EXPECT_THROW(r.realize(graph), std::invalid_argument);
426 }
427
428 TEST(RemapRealizer, remap_05_p) {
429   LayerRepresentation input1 = {
430     "fully_connected", {"name=layer1", "flatten=true", "input_layers=1,2"}};
431
432   {
433     RemapRealizer r([](std::string &name) { name = "scoped/" + name; });
434
435     LayerRepresentation expected1 = {
436       "fully_connected",
437       {"name=scoped/layer1", "flatten=true", "input_layers=scoped/1,scoped/2"}};
438
439     EXPECT_NO_THROW(realizeAndEqual(r, {input1}, {expected1}));
440   }
441   {
442     RemapRealizer r2(
443       [](std::string &name, unsigned &_) { name = "scoped/" + name; });
444
445     LayerRepresentation expected2 = {
446       "fully_connected",
447       {"name=layer1", "flatten=true", "input_layers=scoped/1,scoped/2"}};
448
449     EXPECT_NO_THROW(realizeAndEqual(r2, {input1}, {expected2}));
450   }
451 }
452
453 TEST(SliceRealizer, slice_01_p) {
454   /**
455    * graph architecture
456    *
457    * a1  a2
458    *  |   |
459    * b1   b2    b3
460    *  \  /  \  /
461    *   c1    c2
462    *  / \
463    * d1   d2
464    */
465   std::vector<LayerRepresentation> before = {
466     {"fully_connected", {"name=a1"}},
467     {"fully_connected", {"name=a2"}},
468     {"fully_connected", {"name=b1", "input_layers=a1"}},
469     {"fully_connected", {"name=b2", "input_layers=a2"}},
470     {"fully_connected", {"name=b3"}},
471     {"fully_connected", {"name=c1", "input_layers=b1,b2"}},
472     {"fully_connected", {"name=c2", "input_layers=b2,b3"}},
473     {"fully_connected", {"name=d1", "input_layers=c1"}},
474     {"fully_connected", {"name=d2", "input_layers=c1"}},
475   };
476
477   /**
478    * graph architecture
479    * start_layer = a1, b1, b2
480    * end_layer = a1, d1, d2
481    *
482    * a1 (was input port)
483    *  |
484    * b1   b2 (orphaned)
485    *  \  /
486    *   c1
487    *  / \
488    * d1   d2
489    */
490   std::vector<LayerRepresentation> after = {
491     {"fully_connected", {"name=a1"}},
492     {"fully_connected", {"name=b1", "input_layers=a1"}},
493     {"fully_connected", {"name=b2", "input_layers=a2"}},
494     {"fully_connected", {"name=c1", "input_layers=b1,b2"}},
495     {"fully_connected", {"name=d1", "input_layers=c1"}},
496     {"fully_connected", {"name=d2", "input_layers=c1"}},
497   };
498
499   using C = Connection;
500   SliceRealizer r(
501     {
502       C("a1"),
503       C("b1"),
504       C("b2"),
505     },
506     {
507       C("a1"),
508       C("d1"),
509       C("d2"),
510     });
511
512   EXPECT_NO_THROW(realizeAndEqual(r, before, after));
513 }
514
515 TEST(SliceRealizer, slice_02_p) {
516   /**
517    * graph architecture
518    *
519    * a1----
520    *  |   |
521    * b1   |
522    *  \  /
523    *   c1
524    */
525   std::vector<LayerRepresentation> before = {
526     {"fully_connected", {"name=a1"}},
527     {"fully_connected", {"name=b1", "input_layers=a1"}},
528     {"concat", {"name=c1", "input_layers=a1, b1"}},
529   };
530
531   /**
532    * a1----
533    *  |   |
534    * b1   |
535    *  \  /
536    *   c1
537    */
538   std::vector<LayerRepresentation> after = {
539     {"fully_connected", {"name=a1"}},
540     {"fully_connected", {"name=b1", "input_layers=a1"}},
541     {"concat", {"name=c1", "input_layers=a1, b1"}},
542   };
543
544   SliceRealizer r({Connection("a1")}, {Connection("c1")});
545
546   EXPECT_NO_THROW(realizeAndEqual(r, before, after));
547 }
548
549 TEST(SliceRealizer, slice_03_n) {
550   std::vector<LayerRepresentation> before = {
551     {"fully_connected", {"name=a1", "input_layers=a2"}},
552     {"fully_connected", {"name=a2", "input_layers=a1"}},
553   };
554
555   std::vector<LayerRepresentation> after = {};
556
557   using C = Connection;
558   SliceRealizer r({}, {C("a2")});
559
560   EXPECT_THROW(realizeAndEqual(r, before, after), std::runtime_error);
561 }
562
563 TEST(SliceRealizer, slice_04_n) {
564   std::vector<LayerRepresentation> before = {
565     {"fully_connected", {"name=a1", "input_layers=a2"}},
566     {"fully_connected", {"name=a2", "input_layers=a1"}},
567   };
568
569   std::vector<LayerRepresentation> after = {};
570
571   using C = Connection;
572   SliceRealizer r({C("a1")}, {});
573
574   EXPECT_THROW(realizeAndEqual(r, before, after), std::runtime_error);
575 }
576
577 TEST(SliceRealizer, slice_05_n) {
578   std::vector<LayerRepresentation> before = {
579     {"fully_connected", {"name=a1"}},
580     {"fully_connected", {"name=a2", "input_layers=a1"}},
581   };
582
583   std::vector<LayerRepresentation> after = {};
584
585   using C = Connection;
586   SliceRealizer r({C("a2")}, {C("a1")});
587
588   EXPECT_THROW(realizeAndEqual(r, before, after), std::invalid_argument);
589 }
590
591 TEST(InputRealizer, input_p) {
592   std::vector<LayerRepresentation> before = {
593     {"fully_connected", {"name=fc1"}},
594     {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
595     {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
596   };
597
598   std::vector<LayerRepresentation> after = {
599     {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
600     {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
601     {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
602   };
603
604   using C = Connection;
605   InputRealizer r(
606     {
607       C("fc1"),
608       C("fc2(0)"),
609       C("fc3(0)"),
610       C("fc3(2)"),
611     },
612     {
613       C("in1(0)"),
614       C("in2"),
615       C("in3(3)"),
616       C("in4"),
617     });
618   EXPECT_NO_THROW(realizeAndEqual(r, before, after));
619 }
620
621 TEST(InputRealizer, input_start_num_not_match_n) {
622   using C = Connection;
623   EXPECT_ANY_THROW(InputRealizer r(
624     {
625       C("fc1"),
626     },
627     {
628       C("in1(0)"),
629       C("in2"),
630       C("in3(3)"),
631       C("in4"),
632     }));
633 }
634
635 TEST(InputRealizer, start_empty_conn_not_defined_n) {
636   std::vector<LayerRepresentation> before = {
637     {"fully_connected", {"name=fc1"}},
638     {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
639     {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
640   };
641
642   std::vector<LayerRepresentation> after = {
643     {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
644     {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
645     {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
646   };
647
648   using C = Connection;
649   InputRealizer r(
650     {
651       C("fc1(2)"), /**< connection not defined, although fc1(0) is allowed */
652       C("fc2(0)"),
653       C("fc3(0)"),
654       C("fc3(2)"),
655     },
656     {
657       C("in1(0)"),
658       C("in2"),
659       C("in3(3)"),
660       C("in4"),
661     });
662   EXPECT_ANY_THROW(realizeAndEqual(r, before, after));
663 }
664
665 TEST(InputRealizer, intermediate_conn_not_defined_n) {
666   std::vector<LayerRepresentation> before = {
667     {"fully_connected", {"name=fc1"}},
668     {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
669     {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
670   };
671
672   std::vector<LayerRepresentation> after = {
673     {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
674     {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
675     {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
676   };
677
678   using C = Connection;
679   InputRealizer r(
680     {
681       C("fc1"),
682       C("fc2(4)"), /**< connection not defined */
683       C("fc3(0)"),
684       C("fc3(2)"),
685     },
686     {
687       C("in1(0)"),
688       C("in2"),
689       C("in3(3)"),
690       C("in4"),
691     });
692   EXPECT_ANY_THROW(realizeAndEqual(r, before, after));
693 }
694
695 TEST(PreviousInputRealizer, previous_p) {
696   { /// realization without identifying custom input
697     std::vector<LayerRepresentation> before = {
698       {"fully_connected", {"name=fc1", "input_shape=1"}}, // model input
699       {"fully_connected", {"name=fc2"}}, // auto connected to fc 1
700       {"fully_connected", {"name=fc3", "input_layers=fc1"}},
701       {"fully_connected", {"name=fc4"}}, // auto connected to fc 3
702     };
703
704     std::vector<LayerRepresentation> after = {
705       {"fully_connected", {"name=fc1", "input_shape=1"}},
706       {"fully_connected", {"name=fc2", "input_layers=fc1"}},
707       {"fully_connected", {"name=fc3", "input_layers=fc1"}},
708       {"fully_connected", {"name=fc4", "input_layers=fc3"}},
709     };
710     PreviousInputRealizer r({});
711     EXPECT_NO_THROW(realizeAndEqual(r, before, after));
712   }
713   { /// realization identifying fc1, fc4 is input layer
714     std::vector<LayerRepresentation> before = {
715       {"fully_connected", {"name=fc1"}}, // will be identified as model input
716       {"fully_connected", {"name=fc2"}}, // auto connected to fc 1
717       {"fully_connected", {"name=fc3", "input_layers=fc1"}},
718       {"fully_connected", {"name=fc4"}}, // will be identified as model input
719     };
720     std::vector<LayerRepresentation> after = {
721       {"fully_connected", {"name=fc1"}},
722       {"fully_connected", {"name=fc2", "input_layers=fc1"}},
723       {"fully_connected", {"name=fc3", "input_layers=fc1"}},
724       {"fully_connected", {"name=fc4"}},
725     };
726     PreviousInputRealizer r({Connection("fc1"), Connection("fc4")});
727     EXPECT_NO_THROW(realizeAndEqual(r, before, after));
728   }
729   { /// intermediate node is auto input
730     std::vector<LayerRepresentation> before = {
731       {"fully_connected",
732        {"name=fc1", "input_layers=fc2"}},                 // intermediate node
733       {"fully_connected", {"name=fc2", "input_shape=1"}}, // model input
734       {"fully_connected", {"name=fc3"}}, // auto connected to fc3
735       {"fully_connected", {"name=fc4"}}, // auto connected to fc 3
736     };
737
738     std::vector<LayerRepresentation> after = {
739       {"fully_connected", {"name=fc1", "input_layers=fc2"}},
740       {"fully_connected", {"name=fc2", "input_shape=1"}},
741       {"fully_connected", {"name=fc3", "input_layers=fc2"}},
742       {"fully_connected", {"name=fc4", "input_layers=fc3"}},
743     };
744     PreviousInputRealizer r({});
745     EXPECT_NO_THROW(realizeAndEqual(r, before, after));
746   }
747 }
748
749 TEST(PreviousInputRealizer, user_not_identifying_first_input_n) {
750   /// realization without identifying custom input
751   std::vector<LayerRepresentation> before = {
752     {"fully_connected", {"name=fc1"}}, // this should be model input but
753                                        // nothing has been connected
754     {"fully_connected", {"name=fc2"}}, // auto connected to fc 1
755     {"fully_connected", {"name=fc3", "input_layers=fc1"}},
756     {"fully_connected", {"name=fc4"}}, // auto connected to fc 3
757   };
758   PreviousInputRealizer r({});
759   EXPECT_ANY_THROW(realizeAndEqual(r, before, {}));
760 }
761 TEST(MultioutRealizer, multiout_p) {
762   { // source has single output, referred multiple times
763     std::vector<LayerRepresentation> before = {
764       {"fully_connected", {"name=a"}},
765       {"fully_connected", {"name=b", "input_layers=a"}},
766       {"fully_connected", {"name=c", "input_layers=a"}},
767       {"fully_connected", {"name=d", "input_layers=a"}},
768     };
769     std::vector<LayerRepresentation> after = {
770       {"fully_connected", {"name=a"}},
771       {"multiout", {"name=a/generated_out_0", "input_layers=a"}},
772       {"fully_connected", {"name=b", "input_layers=a/generated_out_0(0)"}},
773       {"fully_connected", {"name=c", "input_layers=a/generated_out_0(1)"}},
774       {"fully_connected", {"name=d", "input_layers=a/generated_out_0(2)"}},
775     };
776
777     MultioutRealizer r;
778     EXPECT_NO_THROW(realizeAndEqual(r, before, after));
779   }
780
781   { // source has single output, some are referred multiple times
782     std::vector<LayerRepresentation> before = {
783       {"split", {"name=a", "input_shape=1:1:1:2", "axis=3"}},
784       {"fully_connected", {"name=b", "input_layers=a(0)"}},
785       {"fully_connected", {"name=c", "input_layers=a(0)"}},
786       {"fully_connected", {"name=d", "input_layers=a(1)"}},
787     };
788     std::vector<LayerRepresentation> after = {
789       {"split", {"name=a", "input_shape=1:1:1:2", "axis=3"}},
790       {"multiout", {"name=a/generated_out_0", "input_layers=a(0)"}},
791       {"fully_connected", {"name=b", "input_layers=a/generated_out_0(0)"}},
792       {"fully_connected", {"name=c", "input_layers=a/generated_out_0(1)"}},
793       {"fully_connected", {"name=d", "input_layers=a(1)"}},
794     };
795
796     MultioutRealizer r;
797     EXPECT_NO_THROW(realizeAndEqual(r, before, after));
798   }
799 }
800
801 TEST(MultioutRealizer, multiout_clashing_name_n) {
802   std::vector<LayerRepresentation> before = {
803     {"split", {"name=a", "input_shape=1:1:1:2", "axis=3"}},
804     {"fully_connected", {"name=a", "input_layers=a(0)"}},
805   };
806
807   MultioutRealizer r;
808   EXPECT_ANY_THROW(realizeAndEqual(r, before, {}));
809 }
810
811 TEST(ActivationRealizer, activation_p) {
812   ActivationRealizer r;
813
814   std::vector<LayerRepresentation> before = {
815     {"fully_connected", {"name=a"}},
816     {"activation",
817      {"name=b", "activation=relu", "input_layers=a"}}, /// not realized
818     {"fully_connected",
819      {"name=c", "input_layers=b", "activation=softmax"}}, // realized
820   };
821
822   std::vector<LayerRepresentation> after = {
823     {"fully_connected", {"name=a"}},
824     {"activation", {"name=b", "activation=relu", "input_layers=a"}},
825     {"fully_connected", {"name=c", "input_layers=b", "activation=none"}},
826     {"activation",
827      {"name=c/activation_realized", "input_layers=c", "activation=softmax"}},
828   };
829
830   EXPECT_NO_THROW(realizeAndEqual(r, before, after));
831 }
832
833 TEST(ActivationRealizer, activation_unknown_n) {
834   ActivationRealizer r;
835
836   std::vector<LayerRepresentation> before = {
837     {"fully_connected", {"name=a"}},
838     {"activation",
839      {"name=b", "activation=relu", "input_layers=a"}}, /// not realized
840     {"fully_connected",
841      {"name=c", "input_layers=b", "activation=unknown"}}, // unknown
842   };
843
844   EXPECT_ANY_THROW(realizeAndEqual(r, before, {}));
845 }
846
847 TEST(BnRealizer, bn_realizer_p) {
848   /// realization without identifying custom input
849   std::vector<LayerRepresentation> before = {
850     {"fully_connected", {"name=fc1"}},
851     {"batch_normalization", {"name=bn1", "input_layers=fc1"}},
852     {"activation", {"name=ac1", "activation=relu", "input_layers=bn1"}},
853     {"fully_connected", {"name=fc2", "input_layers=ac1"}},
854     {"batch_normalization", {"name=bn2", "input_layers=fc2"}},
855     {"activation", {"name=ac2", "activation=relu", "input_layers=bn2"}},
856     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
857   };
858   std::vector<LayerRepresentation> after = {
859     {"fully_connected", {"name=fc1"}},
860     {"activation", {"name=ac1", "activation=relu", "input_layers=fc1"}},
861     {"fully_connected", {"name=fc2", "input_layers=ac1"}},
862     {"activation", {"name=ac2", "activation=relu", "input_layers=fc2"}},
863     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
864   };
865   BnRealizer r;
866   std::vector<std::unique_ptr<nntrainer::GraphRealizer>> realizers;
867   EXPECT_NO_THROW(compileAndRealizeAndEqual(r, realizers, before, after));
868 }
869
870 TEST(BnRealizer, bn_realizer_resblock_p) {
871   std::vector<LayerRepresentation> before = {
872     {"input", {"name=input0"}},
873     {"conv2d", {"name=conv0", "kernel_size=3,3", "input_layers=input0"}},
874     {"batch_normalization", {"name=first_bn", "input_layers=conv0"}},
875     {"activation", {"name=ac0", "activation=relu", "input_layers=first_bn"}},
876     {"conv2d", {"name=a1", "kernel_size=3,3", "input_layers=ac0"}},
877     {"batch_normalization", {"name=bn1", "input_layers=a1"}},
878     {"activation", {"name=ac1", "activation=relu", "input_layers=bn1"}},
879     {"conv2d", {"name=a2", "kernel_size=3,3", "input_layers=ac1"}},
880     {"conv2d", {"name=b1", "kernel_size=3,3", "input_layers=ac0"}},
881     {"addition", {"name=c1", "input_layers=a2,b1"}},
882     {"batch_normalization", {"name=bn2", "input_layers=c1"}},
883     {"activation", {"name=ac2", "activation=relu", "input_layers=bn2"}},
884     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
885   };
886   std::vector<LayerRepresentation> after = {
887     {"input", {"name=input0"}},
888     {"conv2d", {"name=conv0", "kernel_size=3,3", "input_layers=input0"}},
889     {"activation", {"name=ac0", "activation=relu", "input_layers=conv0"}},
890     {"conv2d", {"name=a1", "kernel_size=3,3", "input_layers=ac0"}},
891     {"activation", {"name=ac1", "activation=relu", "input_layers=a1"}},
892     {"conv2d", {"name=a2", "kernel_size=3,3", "input_layers=ac1"}},
893     {"conv2d", {"name=b1", "kernel_size=3,3", "input_layers=ac0"}},
894     {"addition", {"name=c1", "input_layers=a2,b1"}},
895     {"activation", {"name=ac2", "activation=relu", "input_layers=c1"}},
896     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
897   };
898   std::vector<std::unique_ptr<nntrainer::GraphRealizer>> realizers;
899   realizers.emplace_back(new nntrainer::MultioutRealizer());
900   BnRealizer r;
901   EXPECT_NO_THROW(compileAndRealizeAndEqual(r, realizers, before, after));
902 }
903
904 TEST(LossRealizer, loss_realizer_p) {
905   /// realization without identifying custom input
906   std::vector<LayerRepresentation> before = {
907     {"fully_connected", {"name=fc1"}},
908     {"activation", {"name=ac1", "activation=relu", "input_layers=fc1"}},
909     {"fully_connected", {"name=fc2", "input_layers=ac1"}},
910     {"activation", {"name=ac2", "activation=relu", "input_layers=fc2"}},
911     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
912     {"mse", {"name=loss", "input_layers=fc3"}},
913   };
914   std::vector<LayerRepresentation> after = {
915     {"fully_connected", {"name=fc1"}},
916     {"activation", {"name=ac1", "activation=relu", "input_layers=fc1"}},
917     {"fully_connected", {"name=fc2", "input_layers=ac1"}},
918     {"activation", {"name=ac2", "activation=relu", "input_layers=fc2"}},
919     {"fully_connected", {"name=fc3", "input_layers=ac2"}},
920   };
921   LossRealizer r;
922   std::vector<std::unique_ptr<nntrainer::GraphRealizer>> realizers;
923   compileAndRealizeAndEqual(r, realizers, before, after);
924 }