Release 18.08
[platform/upstream/armnn.git] / src / armnnTfParser / test / FullyConnected.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
4 //
5
6 #include <boost/test/unit_test.hpp>
7 #include "armnnTfParser/ITfParser.hpp"
8 #include "ParserPrototxtFixture.hpp"
9 #include "Runtime.hpp"
10 #include "Network.hpp"
11 #include "Graph.hpp"
12
13 BOOST_AUTO_TEST_SUITE(TensorflowParser)
14
15 // In Tensorflow fully connected layers are expressed as a MatMul followed by an Add.
16 // The TfParser must detect this case and convert them to a FullyConnected layer.
17 struct FullyConnectedFixture : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
18 {
19     FullyConnectedFixture()
20     {
21         // Input = tf.placeholder(tf.float32, [1, 1], "input")
22         // Weights = tf.constant([2], tf.float32, [1, 1])
23         // Matmul = tf.matmul(input, weights)
24         // Bias = tf.constant([1], tf.float32)
25         // Output = tf.add(matmul, bias, name="output")
26         m_Prototext = R"(
27 node {
28   name: "input"
29   op: "Placeholder"
30   attr {
31     key: "dtype"
32     value {
33       type: DT_FLOAT
34     }
35   }
36   attr {
37     key: "shape"
38     value {
39       shape {
40         dim {
41           size: 1
42         }
43         dim {
44           size: 1
45         }
46       }
47     }
48   }
49 }
50 node {
51   name: "Const"
52   op: "Const"
53   attr {
54     key: "dtype"
55     value {
56       type: DT_FLOAT
57     }
58   }
59   attr {
60     key: "value"
61     value {
62       tensor {
63         dtype: DT_FLOAT
64         tensor_shape {
65           dim {
66             size: 1
67           }
68           dim {
69             size: 1
70           }
71         }
72         float_val: 2.0
73       }
74     }
75   }
76 }
77 node {
78   name: "MatMul"
79   op: "MatMul"
80   input: "input"
81   input: "Const"
82   attr {
83     key: "T"
84     value {
85       type: DT_FLOAT
86     }
87   }
88   attr {
89     key: "transpose_a"
90     value {
91       b: false
92     }
93   }
94   attr {
95     key: "transpose_b"
96     value {
97       b: false
98     }
99   }
100 }
101 node {
102   name: "Const_1"
103   op: "Const"
104   attr {
105     key: "dtype"
106     value {
107       type: DT_FLOAT
108     }
109   }
110   attr {
111     key: "value"
112     value {
113       tensor {
114         dtype: DT_FLOAT
115         tensor_shape {
116           dim {
117             size: 1
118           }
119         }
120         float_val: 1.0
121       }
122     }
123   }
124 }
125 node {
126   name: "output"
127   op: "Add"
128   input: "MatMul"
129   input: "Const_1"
130   attr {
131     key: "T"
132     value {
133       type: DT_FLOAT
134     }
135   }
136 }
137         )";
138         SetupSingleInputSingleOutput({ 1, 1 }, "input", "output");
139     }
140 };
141
142 BOOST_FIXTURE_TEST_CASE(FullyConnected, FullyConnectedFixture)
143 {
144     RunTest<1>({ 3 }, { 7 });
145 }
146
147 // Similar to FullyConnectedFixture, but this time the MatMul's output is used by two Adds. This should result
148 // in two FullyConnected layers being created.
149 //      I
150 //      |
151 //      M -- C
152 //     / \'
153 // C-- A  A -- C
154 //     \ /
155 //      A
156 struct MatMulUsedInTwoFcFixture : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
157 {
158     MatMulUsedInTwoFcFixture()
159     {
160         m_Prototext = R"(
161 node {
162   name: "input"
163   op: "Placeholder"
164   attr {
165     key: "dtype"
166     value {
167       type: DT_FLOAT
168     }
169   }
170   attr {
171     key: "shape"
172     value {
173       shape {
174         dim {
175           size: 1
176         }
177         dim {
178           size: 1
179         }
180       }
181     }
182   }
183 }
184 node {
185   name: "Const"
186   op: "Const"
187   attr {
188     key: "dtype"
189     value {
190       type: DT_FLOAT
191     }
192   }
193   attr {
194     key: "value"
195     value {
196       tensor {
197         dtype: DT_FLOAT
198         tensor_shape {
199           dim {
200             size: 1
201           }
202           dim {
203             size: 1
204           }
205         }
206         float_val: 2.0
207       }
208     }
209   }
210 }
211 node {
212   name: "MatMul"
213   op: "MatMul"
214   input: "input"
215   input: "Const"
216   attr {
217     key: "T"
218     value {
219       type: DT_FLOAT
220     }
221   }
222   attr {
223     key: "transpose_a"
224     value {
225       b: false
226     }
227   }
228   attr {
229     key: "transpose_b"
230     value {
231       b: false
232     }
233   }
234 }
235 node {
236   name: "Const_1"
237   op: "Const"
238   attr {
239     key: "dtype"
240     value {
241       type: DT_FLOAT
242     }
243   }
244   attr {
245     key: "value"
246     value {
247       tensor {
248         dtype: DT_FLOAT
249         tensor_shape {
250           dim {
251             size: 1
252           }
253         }
254         float_val: 5.0
255       }
256     }
257   }
258 }
259 node {
260   name: "Const_2"
261   op: "Const"
262   attr {
263     key: "dtype"
264     value {
265       type: DT_FLOAT
266     }
267   }
268   attr {
269     key: "value"
270     value {
271       tensor {
272         dtype: DT_FLOAT
273         tensor_shape {
274           dim {
275             size: 1
276           }
277         }
278         float_val: 15.0
279       }
280     }
281   }
282 }
283 node {
284   name: "Add"
285   op: "Add"
286   input: "MatMul"
287   input: "Const_1"
288   attr {
289     key: "T"
290     value {
291       type: DT_FLOAT
292     }
293   }
294 }
295 node {
296   name: "Add_1"
297   op: "Add"
298   input: "MatMul"
299   input: "Const_2"
300   attr {
301     key: "T"
302     value {
303       type: DT_FLOAT
304     }
305   }
306 }
307 node {
308   name: "output"
309   op: "Add"
310   input: "Add"
311   input: "Add_1"
312   attr {
313     key: "T"
314     value {
315       type: DT_FLOAT
316     }
317   }
318 }
319         )";
320         SetupSingleInputSingleOutput({ 1, 1 }, "input", "output");
321     }
322 };
323
324 BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFc, MatMulUsedInTwoFcFixture)
325 {
326     RunTest<1>({ 3 }, { 32 });
327     // Ideally we would check here that the armnn network has 5 layers:
328     //  Input, 2 x FullyConnected (biased), Add and Output.
329     // This would make sure the parser hasn't incorrectly added some unconnected layers corresponding to the MatMul.
330 }
331
332 // Similar to MatMulUsedInTwoFc, but this time the Adds are 'staggered' (see diagram), which means that only one
333 // FullyConnected layer can be created (the other should just be an Add).
334 //        I
335 //        |
336 //        M -- C1
337 //       / \'
338 // C2 -- A  |
339 //       \ /
340 //        A
341 struct MatMulUsedInTwoFcStaggeredFixture : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
342 {
343     MatMulUsedInTwoFcStaggeredFixture()
344     {
345         // Input = tf.placeholder(tf.float32, shape=[1,1], name = "input")
346         // Const1 = tf.constant([17], tf.float32, [1,1])
347         // Mul = tf.matmul(input, const1)
348         // Monst2 = tf.constant([7], tf.float32, [1])
349         // Fc = tf.add(mul, const2)
350         // Output = tf.add(mul, fc, name="output")
351         m_Prototext = R"(
352 node {
353   name: "input"
354   op: "Placeholder"
355   attr {
356     key: "dtype"
357     value {
358       type: DT_FLOAT
359     }
360   }
361   attr {
362     key: "shape"
363     value {
364       shape {
365         dim {
366           size: 1
367         }
368         dim {
369           size: 1
370         }
371       }
372     }
373   }
374 }
375 node {
376   name: "Const"
377   op: "Const"
378   attr {
379     key: "dtype"
380     value {
381       type: DT_FLOAT
382     }
383   }
384   attr {
385     key: "value"
386     value {
387       tensor {
388         dtype: DT_FLOAT
389         tensor_shape {
390           dim {
391             size: 1
392           }
393           dim {
394             size: 1
395           }
396         }
397         float_val: 17.0
398       }
399     }
400   }
401 }
402 node {
403   name: "MatMul"
404   op: "MatMul"
405   input: "input"
406   input: "Const"
407   attr {
408     key: "T"
409     value {
410       type: DT_FLOAT
411     }
412   }
413   attr {
414     key: "transpose_a"
415     value {
416       b: false
417     }
418   }
419   attr {
420     key: "transpose_b"
421     value {
422       b: false
423     }
424   }
425 }
426 node {
427   name: "Const_1"
428   op: "Const"
429   attr {
430     key: "dtype"
431     value {
432       type: DT_FLOAT
433     }
434   }
435   attr {
436     key: "value"
437     value {
438       tensor {
439         dtype: DT_FLOAT
440         tensor_shape {
441           dim {
442             size: 1
443           }
444         }
445         float_val: 7.0
446       }
447     }
448   }
449 }
450 node {
451   name: "Add"
452   op: "Add"
453   input: "MatMul"
454   input: "Const_1"
455   attr {
456     key: "T"
457     value {
458       type: DT_FLOAT
459     }
460   }
461 }
462 node {
463   name: "output"
464   op: "Add"
465   input: "MatMul"
466   input: "Add"
467   attr {
468     key: "T"
469     value {
470       type: DT_FLOAT
471     }
472   }
473 }
474         )";
475         SetupSingleInputSingleOutput({ 1, 1 }, "input", "output");
476     }
477 };
478
479 BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFcStaggered, MatMulUsedInTwoFcStaggeredFixture)
480 {
481     RunTest<1>({ 2 }, { 75 });
482     // Ideally we would check here that the armnn network has 5 layers:
483     //   Input, FullyConnected (biased), FullyConnected (non biased), Add and Output.
484 }
485
486 // A MatMul in isolation, not connected to an add. Should result in a non-biased FullyConnected layer.
487 struct MatMulFixture : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
488 {
489     MatMulFixture()
490     {
491         // Input = tf.placeholder(tf.float32, shape = [1, 1], name = "input")
492         // Const = tf.constant([17], tf.float32, [1, 1])
493         //  Output = tf.matmul(input, const, name = "output")
494         m_Prototext = R"(
495 node {
496   name: "input"
497   op: "Placeholder"
498   attr {
499     key: "dtype"
500     value {
501       type: DT_FLOAT
502     }
503   }
504   attr {
505     key: "shape"
506     value {
507       shape {
508         dim {
509           size: 1
510         }
511         dim {
512           size: 1
513         }
514       }
515     }
516   }
517 }
518 node {
519   name: "Const"
520   op: "Const"
521   attr {
522     key: "dtype"
523     value {
524       type: DT_FLOAT
525     }
526   }
527   attr {
528     key: "value"
529     value {
530       tensor {
531         dtype: DT_FLOAT
532         tensor_shape {
533           dim {
534             size: 1
535           }
536           dim {
537             size: 1
538           }
539         }
540         float_val: 17.0
541       }
542     }
543   }
544 }
545 node {
546   name: "output"
547   op: "MatMul"
548   input: "input"
549   input: "Const"
550   attr {
551     key: "T"
552     value {
553       type: DT_FLOAT
554     }
555   }
556   attr {
557     key: "transpose_a"
558     value {
559       b: false
560     }
561   }
562   attr {
563     key: "transpose_b"
564     value {
565       b: false
566     }
567   }
568 }
569         )";
570         SetupSingleInputSingleOutput({ 1, 1 }, "input", "output");
571     }
572 };
573
574 BOOST_FIXTURE_TEST_CASE(MatMul, MatMulFixture)
575 {
576     RunTest<1>({ 2 }, { 34 });
577 }
578
579 BOOST_AUTO_TEST_SUITE_END()