// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include #include "armnnTfParser/ITfParser.hpp" #include "ParserPrototxtFixture.hpp" #include "Runtime.hpp" #include "Network.hpp" #include "Graph.hpp" BOOST_AUTO_TEST_SUITE(TensorflowParser) // In Tensorflow fully connected layers are expressed as a MatMul followed by an Add. // The TfParser must detect this case and convert them to a FullyConnected layer. struct FullyConnectedFixture : public armnnUtils::ParserPrototxtFixture { FullyConnectedFixture() { // Input = tf.placeholder(tf.float32, [1, 1], "input") // Weights = tf.constant([2], tf.float32, [1, 1]) // Matmul = tf.matmul(input, weights) // Bias = tf.constant([1], tf.float32) // Output = tf.add(matmul, bias, name="output") m_Prototext = R"( node { name: "input" op: "Placeholder" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "shape" value { shape { dim { size: 1 } dim { size: 1 } } } } } node { name: "Const" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } dim { size: 1 } } float_val: 2.0 } } } } node { name: "MatMul" op: "MatMul" input: "input" input: "Const" attr { key: "T" value { type: DT_FLOAT } } attr { key: "transpose_a" value { b: false } } attr { key: "transpose_b" value { b: false } } } node { name: "Const_1" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } } float_val: 1.0 } } } } node { name: "output" op: "Add" input: "MatMul" input: "Const_1" attr { key: "T" value { type: DT_FLOAT } } } )"; SetupSingleInputSingleOutput({ 1, 1 }, "input", "output"); } }; BOOST_FIXTURE_TEST_CASE(FullyConnected, FullyConnectedFixture) { RunTest<1>({ 3 }, { 7 }); } // Similar to FullyConnectedFixture, but this time the MatMul's output is used by two Adds. This should result // in two FullyConnected layers being created. // I // | // M -- C // / \' // C-- A A -- C // \ / // A struct MatMulUsedInTwoFcFixture : public armnnUtils::ParserPrototxtFixture { MatMulUsedInTwoFcFixture() { m_Prototext = R"( node { name: "input" op: "Placeholder" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "shape" value { shape { dim { size: 1 } dim { size: 1 } } } } } node { name: "Const" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } dim { size: 1 } } float_val: 2.0 } } } } node { name: "MatMul" op: "MatMul" input: "input" input: "Const" attr { key: "T" value { type: DT_FLOAT } } attr { key: "transpose_a" value { b: false } } attr { key: "transpose_b" value { b: false } } } node { name: "Const_1" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } } float_val: 5.0 } } } } node { name: "Const_2" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } } float_val: 15.0 } } } } node { name: "Add" op: "Add" input: "MatMul" input: "Const_1" attr { key: "T" value { type: DT_FLOAT } } } node { name: "Add_1" op: "Add" input: "MatMul" input: "Const_2" attr { key: "T" value { type: DT_FLOAT } } } node { name: "output" op: "Add" input: "Add" input: "Add_1" attr { key: "T" value { type: DT_FLOAT } } } )"; SetupSingleInputSingleOutput({ 1, 1 }, "input", "output"); } }; BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFc, MatMulUsedInTwoFcFixture) { RunTest<1>({ 3 }, { 32 }); // Ideally we would check here that the armnn network has 5 layers: // Input, 2 x FullyConnected (biased), Add and Output. // This would make sure the parser hasn't incorrectly added some unconnected layers corresponding to the MatMul. } // Similar to MatMulUsedInTwoFc, but this time the Adds are 'staggered' (see diagram), which means that only one // FullyConnected layer can be created (the other should just be an Add). // I // | // M -- C1 // / \' // C2 -- A | // \ / // A struct MatMulUsedInTwoFcStaggeredFixture : public armnnUtils::ParserPrototxtFixture { MatMulUsedInTwoFcStaggeredFixture() { // Input = tf.placeholder(tf.float32, shape=[1,1], name = "input") // Const1 = tf.constant([17], tf.float32, [1,1]) // Mul = tf.matmul(input, const1) // Monst2 = tf.constant([7], tf.float32, [1]) // Fc = tf.add(mul, const2) // Output = tf.add(mul, fc, name="output") m_Prototext = R"( node { name: "input" op: "Placeholder" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "shape" value { shape { dim { size: 1 } dim { size: 1 } } } } } node { name: "Const" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } dim { size: 1 } } float_val: 17.0 } } } } node { name: "MatMul" op: "MatMul" input: "input" input: "Const" attr { key: "T" value { type: DT_FLOAT } } attr { key: "transpose_a" value { b: false } } attr { key: "transpose_b" value { b: false } } } node { name: "Const_1" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } } float_val: 7.0 } } } } node { name: "Add" op: "Add" input: "MatMul" input: "Const_1" attr { key: "T" value { type: DT_FLOAT } } } node { name: "output" op: "Add" input: "MatMul" input: "Add" attr { key: "T" value { type: DT_FLOAT } } } )"; SetupSingleInputSingleOutput({ 1, 1 }, "input", "output"); } }; BOOST_FIXTURE_TEST_CASE(MatMulUsedInTwoFcStaggered, MatMulUsedInTwoFcStaggeredFixture) { RunTest<1>({ 2 }, { 75 }); // Ideally we would check here that the armnn network has 5 layers: // Input, FullyConnected (biased), FullyConnected (non biased), Add and Output. } // A MatMul in isolation, not connected to an add. Should result in a non-biased FullyConnected layer. struct MatMulFixture : public armnnUtils::ParserPrototxtFixture { MatMulFixture() { // Input = tf.placeholder(tf.float32, shape = [1, 1], name = "input") // Const = tf.constant([17], tf.float32, [1, 1]) // Output = tf.matmul(input, const, name = "output") m_Prototext = R"( node { name: "input" op: "Placeholder" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "shape" value { shape { dim { size: 1 } dim { size: 1 } } } } } node { name: "Const" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 1 } dim { size: 1 } } float_val: 17.0 } } } } node { name: "output" op: "MatMul" input: "input" input: "Const" attr { key: "T" value { type: DT_FLOAT } } attr { key: "transpose_a" value { b: false } } attr { key: "transpose_b" value { b: false } } } )"; SetupSingleInputSingleOutput({ 1, 1 }, "input", "output"); } }; BOOST_FIXTURE_TEST_CASE(MatMul, MatMulFixture) { RunTest<1>({ 2 }, { 34 }); } BOOST_AUTO_TEST_SUITE_END()