ArmNN
 20.11
FullyConnected.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <boost/test/unit_test.hpp>
9 
10 BOOST_AUTO_TEST_SUITE(OnnxParser)
11 
12 // A MatMul in isolation, not connected to an add. Should result in a non-biased FullyConnected layer.
13 struct MatMulFixture : public armnnUtils::ParserPrototxtFixture<armnnOnnxParser::IOnnxParser>
14 {
15  MatMulFixture()
16  {
17  m_Prototext = R"(
18  ir_version: 3
19  producer_name: "CNTK "
20  producer_version: "2.5.1 "
21  domain: "ai.cntk "
22  model_version: 1
23  graph {
24  name: "CNTKGraph "
25  input {
26  name: "Input"
27  type {
28  tensor_type {
29  elem_type: 1
30  shape {
31  dim {
32  dim_value: 1
33  }
34  dim {
35  dim_value: 1
36  }
37  }
38  }
39  }
40  }
41  input {
42  name: "Const"
43  type {
44  tensor_type {
45  elem_type: 1
46  shape {
47  dim {
48  dim_value: 1
49  }
50  dim {
51  dim_value: 1
52  }
53  }
54  }
55  }
56  }
57  initializer {
58  dims: 1
59  dims: 1
60  data_type: 1
61  float_data: 17.0
62  name: "Const"
63  }
64  node {
65  input: "Input"
66  input: "Const"
67  output: "Output"
68  name: "SimpleMatmul"
69  op_type: "MatMul"
70  }
71  output {
72  name: "Output"
73  type {
74  tensor_type {
75  elem_type: 1
76  shape {
77  dim {
78  dim_value: 1
79  }
80  dim {
81  dim_value: 1
82  }
83  }
84  }
85  }
86  }
87  }
88  opset_import {
89  version: 7
90  })";
91 
92  Setup();
93  }
94 };
95 
96 BOOST_FIXTURE_TEST_CASE(MatMul, MatMulFixture)
97 {
98  RunTest<1>({{"Input", { 2 }}}, {{"Output", { 34 }}});
99 }
100 
101 // In Onnx fully connected layers are expressed as a MatMul followed by an Add.
102 // The OnnxParser must detect this case and convert them to a FullyConnected layer.
103 struct FullyConnectedFixture : public armnnUtils::ParserPrototxtFixture<armnnOnnxParser::IOnnxParser>
104 {
105  FullyConnectedFixture()
106  {
107  m_Prototext = R"(
108  ir_version: 3
109  producer_name: "CNTK "
110  producer_version: "2.5.1 "
111  domain: "ai.cntk "
112  model_version: 1
113  graph {
114  name: "CNTKGraph "
115  input {
116  name: "Input"
117  type {
118  tensor_type {
119  elem_type: 1
120  shape {
121  dim {
122  dim_value: 1
123  }
124  dim {
125  dim_value: 1
126  }
127  }
128  }
129  }
130  }
131  input {
132  name: "Weight"
133  type {
134  tensor_type {
135  elem_type: 1
136  shape {
137  dim {
138  dim_value: 1
139  }
140  dim {
141  dim_value: 1
142  }
143  }
144  }
145  }
146  }
147  initializer {
148  dims: 1
149  dims: 1
150  data_type: 1
151  float_data: 2
152  name: "Weight"
153  }
154  input {
155  name: "Bias"
156  type {
157  tensor_type {
158  elem_type: 1
159  shape {
160  dim {
161  dim_value: 1
162  }
163  }
164  }
165  }
166  }
167  initializer {
168  dims: 1
169  data_type: 1
170  float_data: 1
171  name: "Bias"
172  }
173  node {
174  input: "Input"
175  input: "Weight"
176  output: "AddInput"
177  name: "FCMatmul"
178  op_type: "MatMul"
179  }
180  node {
181  input: "AddInput"
182  input: "Bias"
183  output: "Output"
184  name: "FCAdd"
185  op_type: "Add"
186  }
187  value_info {
188  name: "AddInput"
189  type {
190  tensor_type {
191  elem_type: 1
192  shape {
193  dim {
194  dim_value: 1
195  }
196  dim {
197  dim_value: 1
198  }
199  }
200  }
201  }
202  }
203  output {
204  name: "Output"
205  type {
206  tensor_type {
207  elem_type: 1
208  shape {
209  dim {
210  dim_value: 1
211  }
212  dim {
213  dim_value: 1
214  }
215  }
216  }
217  }
218  }
219  }
220  opset_import {
221  version: 7
222  })";
223 
224  Setup();
225  }
226 };
227 
229 {
230  RunTest<1>({{"Input", { 3 }}}, {{"Output", { 7 }}});
231 }
232 
233 
234 // Similar to FullyConnectedFixture, but this time the MatMul's output is used by two Adds. This should result
235 // in two FullyConnected layers being created.
236 // I
237 // |
238 // M -- C
239 // / \'
240 // C-- A A -- C
241 // \ /
242 // A
243 struct MatMulUsedInTwoFcFixture : public armnnUtils::ParserPrototxtFixture<armnnOnnxParser::IOnnxParser>
244 {
245  MatMulUsedInTwoFcFixture()
246  {
247  m_Prototext = R"(
248  ir_version: 3
249  producer_name: "CNTK "
250  producer_version: "2.5.1 "
251  domain: "ai.cntk "
252  model_version: 1
253  graph {
254  name: "CNTKGraph "
255  input {
256  name: "Input"
257  type {
258  tensor_type {
259  elem_type: 1
260  shape {
261  dim {
262  dim_value: 1
263  }
264  dim {
265  dim_value: 1
266  }
267  }
268  }
269  }
270  }
271  input {
272  name: "Weight"
273  type {
274  tensor_type {
275  elem_type: 1
276  shape {
277  dim {
278  dim_value: 1
279  }
280  dim {
281  dim_value: 1
282  }
283  }
284  }
285  }
286  }
287  initializer {
288  dims: 1
289  dims: 1
290  data_type: 1
291  float_data: 2
292  name: "Weight"
293  }
294  input {
295  name: "Bias"
296  type {
297  tensor_type {
298  elem_type: 1
299  shape {
300  dim {
301  dim_value: 1
302  }
303  }
304  }
305  }
306  }
307  initializer {
308  dims: 1
309  data_type: 1
310  float_data: 1
311  name: "Bias"
312  }
313  input {
314  name: "Bias_1"
315  type {
316  tensor_type {
317  elem_type: 1
318  shape {
319  dim {
320  dim_value: 1
321  }
322  }
323  }
324  }
325  }
326  initializer {
327  dims: 1
328  data_type: 1
329  float_data: 10.0
330  name: "Bias_1"
331  }
332  node {
333  input: "Input"
334  input: "Weight"
335  output: "AddInput"
336  name: "FCMatmul"
337  op_type: "MatMul"
338  }
339  node {
340  input: "AddInput"
341  input: "Bias"
342  output: "AddOutput"
343  name: "FCAdd"
344  op_type: "Add"
345  }
346  node {
347  input: "AddInput"
348  input: "Bias_1"
349  output: "AddOutput_1"
350  name: "FCAdd_1"
351  op_type: "Add"
352  }
353  node {
354  input: "AddOutput"
355  input: "AddOutput_1"
356  output: "Output"
357  name: "FinalAdd"
358  op_type: "Add"
359  }
360  value_info {
361  name: "AddInput"
362  type {
363  tensor_type {
364  elem_type: 1
365  shape {
366  dim {
367  dim_value: 1
368  }
369  dim {
370  dim_value: 1
371  }
372  }
373  }
374  }
375  }
376  value_info {
377  name: "AddOutput"
378  type {
379  tensor_type {
380  elem_type: 1
381  shape {
382  dim {
383  dim_value: 1
384  }
385  dim {
386  dim_value: 1
387  }
388  }
389  }
390  }
391  }
392  value_info {
393  name: "AddOutput_1"
394  type {
395  tensor_type {
396  elem_type: 1
397  shape {
398  dim {
399  dim_value: 1
400  }
401  dim {
402  dim_value: 1
403  }
404  }
405  }
406  }
407  }
408  output {
409  name: "Output"
410  type {
411  tensor_type {
412  elem_type: 1
413  shape {
414  dim {
415  dim_value: 1
416  }
417  dim {
418  dim_value: 1
419  }
420  }
421  }
422  }
423  }
424  }
425  opset_import {
426  version: 7
427  })";
428 
429  Setup();
430  }
431 };
432 
433 BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFc, MatMulUsedInTwoFcFixture)
434 {
435  RunTest<1>({{"Input", { 3 }}}, {{"Output", { 23 }}});
436 }
437 
438 
439 // Similar to MatMulUsedInTwoFc, but this time the Adds are 'staggered' (see diagram), which means that only one
440 // FullyConnected layer can be created (the other should just be an Add).
441 // I
442 // |
443 // M -- C1
444 // / \'
445 // C2 -- A |
446 // \ /
447 // A
448 struct MatMulUsedInTwoFcStaggeredFixture : public armnnUtils::ParserPrototxtFixture<armnnOnnxParser::IOnnxParser>
449 {
450  MatMulUsedInTwoFcStaggeredFixture()
451  {
452  m_Prototext = R"(
453  ir_version: 3
454  producer_name: "CNTK "
455  producer_version: "2.5.1 "
456  domain: "ai.cntk "
457  model_version: 1
458  graph {
459  name: "CNTKGraph "
460  input {
461  name: "Input"
462  type {
463  tensor_type {
464  elem_type: 1
465  shape {
466  dim {
467  dim_value: 1
468  }
469  dim {
470  dim_value: 1
471  }
472  }
473  }
474  }
475  }
476  input {
477  name: "Weight"
478  type {
479  tensor_type {
480  elem_type: 1
481  shape {
482  dim {
483  dim_value: 1
484  }
485  dim {
486  dim_value: 1
487  }
488  }
489  }
490  }
491  }
492  initializer {
493  dims: 1
494  dims: 1
495  data_type: 1
496  float_data: 2
497  name: "Weight"
498  }
499  input {
500  name: "Bias"
501  type {
502  tensor_type {
503  elem_type: 1
504  shape {
505  dim {
506  dim_value: 1
507  }
508  }
509  }
510  }
511  }
512  initializer {
513  dims: 1
514  data_type: 1
515  float_data: 1
516  name: "Bias"
517  }
518  node {
519  input: "Input"
520  input: "Weight"
521  output: "AddInput"
522  name: "MatmulFC&NFC"
523  op_type: "MatMul"
524  }
525  node {
526  input: "AddInput"
527  input: "Bias"
528  output: "AddOutput"
529  name: "FCAdd"
530  op_type: "Add"
531  }
532 
533  node {
534  input: "AddInput"
535  input: "AddOutput"
536  output: "Output"
537  name: "FinalAdd"
538  op_type: "Add"
539  }
540  value_info {
541  name: "AddInput"
542  type {
543  tensor_type {
544  elem_type: 1
545  shape {
546  dim {
547  dim_value: 1
548  }
549  dim {
550  dim_value: 1
551  }
552  }
553  }
554  }
555  }
556  value_info {
557  name: "AddOutput"
558  type {
559  tensor_type {
560  elem_type: 1
561  shape {
562  dim {
563  dim_value: 1
564  }
565  dim {
566  dim_value: 1
567  }
568  }
569  }
570  }
571  }
572  output {
573  name: "Output"
574  type {
575  tensor_type {
576  elem_type: 1
577  shape {
578  dim {
579  dim_value: 1
580  }
581  dim {
582  dim_value: 1
583  }
584  }
585  }
586  }
587  }
588  }
589  opset_import {
590  version: 7
591  })";
592  Setup();
593  }
594 };
595 
596 BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFcStaggered, MatMulUsedInTwoFcStaggeredFixture)
597 {
598  RunTest<1>({{"Input", { 3 }}}, {{"Output", { 13 }}});
599 }
600 
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
void FullyConnected(const TensorShape &rInputShape, Decoder< float > &rInputDecoder, const TensorShape &rOutputShape, Encoder< float > &rOutputEncoder, const TensorShape &rWeightsShape, Decoder< float > &rWeightDecoder, Decoder< float > &rBiasDecoder, const bool biasEnabled, const unsigned int K, const bool transposeWeights)
Performs a matrix multiplication and optionally adds a bias.
BOOST_AUTO_TEST_SUITE_END()
BOOST_FIXTURE_TEST_CASE(MatMul, MatMulFixture)