From e774e41cd23bdec9ce418f1f1a9486d6c241a3a8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9C=A4=ED=98=84=EC=8B=9D/On-Device=20Lab=28SR=29/Princip?= =?utf8?q?al=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 18 Jun 2019 11:23:31 +0900 Subject: [PATCH] [moco/tf] Adding BiasAdd (#3815) [moco/tf] Adding BiasAdd This comits adds BiasAdd for moco/tf. Signed-off-by: Hyun Sik Yoon Signed-off-by: Pavel Iliutchenko p.iliutchenk@samsung.com --- contrib/moco/lib/frontend/tf/src/Op/BiasAdd.cpp | 165 +++++++++++++++ .../moco/lib/frontend/tf/src/Op/BiasAdd.test.cpp | 231 +++++++++++++++++++++ .../tf/src/Transforms/FixPaddingTransform.cpp | 12 ++ .../tf/src/Transforms/FixShapeTransform.cpp | 13 ++ .../lib/frontend/tf/src/Transforms/MocoNodes.lst | 2 + 5 files changed, 423 insertions(+) create mode 100644 contrib/moco/lib/frontend/tf/src/Op/BiasAdd.cpp create mode 100644 contrib/moco/lib/frontend/tf/src/Op/BiasAdd.test.cpp diff --git a/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.cpp b/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.cpp new file mode 100644 index 0000000..ffc4284 --- /dev/null +++ b/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Convert.h" +#include "GraphBuilder.h" +#include "GraphBuilderContext.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace +{ +using namespace moco::tf; + +class ValueInputUpdate final : public GraphUpdate +{ +public: + ValueInputUpdate(loco::BiasAdd *bias_add, const TensorName &&input_name) + : _bias_add(bias_add), _input_name(input_name) + { + } + + void input(const SymbolTable *) const override; + +private: + loco::BiasAdd *_bias_add; + const TensorName _input_name; +}; + +void ValueInputUpdate::input(const SymbolTable *node_table) const +{ + loco::Node *input_node = node_table->node(_input_name); + _bias_add->value(input_node); +} + +class BiasInputUpdate final : public GraphUpdate +{ +public: + BiasInputUpdate(loco::BiasEncode *bias_enc, const TensorName &&input_name) + : _bias_enc(bias_enc), _input_name(input_name) + { + } + + void input(const SymbolTable *) const override; + +private: + loco::BiasEncode *_bias_enc; + const TensorName _input_name; +}; + +void BiasInputUpdate::input(const SymbolTable *node_table) const +{ + loco::Node *input_node = node_table->node(_input_name); + _bias_enc->input(input_node); +} + +} // namespace + +namespace moco +{ +namespace tf +{ + +/** + * @brief GraphBuilder for BiasAdd node + */ +class BiasAddGraphBuilder final : public GraphBuilder +{ +public: + bool validate(const tensorflow::NodeDef &) const override; + void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override; +}; + +bool BiasAddGraphBuilder::validate(const tensorflow::NodeDef &node) const +{ + assert(node.input_size() == 2); + + // note: even though "data_format" is not entered when a model is written, + // TF seems to generate "data_format" field into a pb file + if (!has_attrs(node, {"T", "data_format"})) + return false; + + // TODO add type check + // type of input and bias should be same (except using quantization) + + // Note In case of TF.nn.bias_add, + // "value may have any number of dimensions." ... + // but "data_format: A string. 'NHWC' and 'NCHW' are supported." + // Not sure if value should be 4-D tensor. Let's skip this check for now. + + return true; +} + +void BiasAddGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const +{ + assert(context != nullptr); + + loco::Graph *graph = context->graph(); + SymbolTable *tensor_names = context->tensor_names(); + UpdateQueue *updates = context->updates(); + + // tensorflow data_format: one of NHWC or NCHW. + auto data_layout = get_data_layout(node, "data_format"); + + // creating loco nodes + auto bias_enc = graph->nodes()->create(); + + auto bias_add = graph->nodes()->create>(); + { + if (data_layout == DataLayout::NHWC) + { + bias_add->axis(3); + } + else if (data_layout == DataLayout::NCHW) + { + bias_add->axis(1); // Channel + // Note: the following descrition of TF 1.13 at + // https://www.tensorflow.org/api_docs/python/tf/nn/bias_add seems wrong: + // "bias: A 1-D Tensor with size matching the last dimension of value." + // because providing the size of W (last dimension) to bias throws an error with Tensorflow + } + } + + // link nodes + bias_add->bias(bias_enc); + + // To set the input node of encode_node with biasAdd_name + TensorName output_name(node.name(), 0); + tensor_names->enroll(output_name, bias_add); + + // Record ifm inputs to featureEncode_node + auto value_update = stdex::make_unique(bias_add, TensorName(node.input(0))); + auto bias_update = stdex::make_unique(bias_enc, TensorName(node.input(1))); + + updates->enroll(std::move(value_update)); + updates->enroll(std::move(bias_update)); +} + +} // namespace tf +} // namespace moco + +#include "GraphBuilderRegistry.h" + +REGISTER_OP_BUILDER(BiasAdd, BiasAddGraphBuilder) diff --git a/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.test.cpp b/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.test.cpp new file mode 100644 index 0000000..2550f48 --- /dev/null +++ b/contrib/moco/lib/frontend/tf/src/Op/BiasAdd.test.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestHelper.h" + +#include + +#include + +#include + +#include + +using namespace moco::tf::test; + +namespace +{ + +// clang-format off +const char *bias_add_01_pbtxtdata = STRING_CONTENT( + +node { + name: "val" + op: "Const" + attr { + key: "dtype" + value { type: DT_FLOAT } + } + attr { + key: "value" + value { + tensor { + dtype: DT_FLOAT + tensor_shape { + dim { size: 1 } + dim { size: 5 } + dim { size: 5 } + dim { size: 3 } + } + float_val: 2.1 + } + } + } +} +node { + name: "bias" + op: "Const" + attr { + key: "dtype" + value { type: DT_FLOAT } + } + attr { + key: "value" + value { + tensor { + dtype: DT_FLOAT + tensor_shape { + dim { size: 3 } + } + float_val: 1.1 + } + } + } +} +node { + name: "out" + op: "BiasAdd" + input: "val" + input: "bias" + attr { + key: "T" + value { type: DT_FLOAT } + } + attr { + key: "data_format" + value { s: "NHWC" } + } +} + +); +// clang-format on + +} // namespace + +TEST(TensorFlowFrontend, bias_add_01) +{ + moco::tf::Frontend frontend; + moco::tf::ModelSignature signature; + signature.add_output(moco::tf::TensorName("out", 0)); + + imemstream mempb(bias_add_01_pbtxtdata, std::strlen(bias_add_01_pbtxtdata)); + std::unique_ptr graph = + frontend.load(signature, &mempb, moco::tf::Frontend::FileType::Text); + + // test 1. + // loco node : 1. ConstGen ------------------+-- 4. BiasAdd -- 5. Push + // 2. ConstGen - 3. BiasEncode -/ + loco::Graph::NodeContext *loco_nodes = graph->nodes(); + + loco::Graph::InputContext *loco_inputs = graph->inputs(); + ASSERT_EQ(loco_inputs->size(), 0); + ASSERT_EQ(loco_nodes->size(), 5); + + int idx = 0; + + loco::ConstGen *value = dynamic_cast(loco_nodes->at(idx++)); + loco::ConstGen *bias = dynamic_cast(loco_nodes->at(idx++)); + loco::BiasEncode *enc = dynamic_cast(loco_nodes->at(idx++)); + loco::BiasAdd *bias_add = + dynamic_cast *>(loco_nodes->at(idx++)); + loco::Push *push = dynamic_cast(loco_nodes->at(idx++)); + + ASSERT_NE(value, nullptr); + ASSERT_NE(bias, nullptr); + ASSERT_NE(enc, nullptr); + ASSERT_NE(bias_add, nullptr); + ASSERT_NE(push, nullptr); + + // check their connection is all OK + ASSERT_TRUE(enc->input() == bias); + ASSERT_TRUE(bias_add->bias() == enc); + ASSERT_TRUE(bias_add->value() == value); + ASSERT_TRUE(push->from() == bias_add); + + // test 2. + // attrs inside BiasAdd + + // axis + ASSERT_EQ(bias_add->axis(), 3); // NHWC +} + +namespace +{ + +// clang-format off +const char *bias_add_NCHW_pbtxtdata = STRING_CONTENT( + +node { + name: "val" + op: "Const" + attr { + key: "dtype" + value { type: DT_FLOAT } + } + attr { + key: "value" + value { + tensor { + dtype: DT_FLOAT + tensor_shape { + dim { size: 1 } + dim { size: 3 } + dim { size: 299 } + dim { size: 299 } + } + float_val: 2.1 + } + } + } +} +node { + name: "bias" + op: "Const" + attr { + key: "dtype" + value { type: DT_FLOAT } + } + attr { + key: "value" + value { + tensor { + dtype: DT_FLOAT + tensor_shape { + dim { size: 3 } + } + float_val: 1.1 + } + } + } +} +node { + name: "out" + op: "BiasAdd" + input: "val" + input: "bias" + attr { + key: "T" + value { type: DT_FLOAT } + } + attr { + key: "data_format" + value { s: "NCHW" } + } +} + +); +// clang-format on + +} // namespace + +TEST(TensorFlowFrontend, bias_add_NCHW_axis) +{ + moco::tf::Frontend frontend; + moco::tf::ModelSignature signature; + signature.add_output(moco::tf::TensorName("out", 0)); + + imemstream mempb(bias_add_NCHW_pbtxtdata, std::strlen(bias_add_NCHW_pbtxtdata)); + std::unique_ptr graph = + frontend.load(signature, &mempb, moco::tf::Frontend::FileType::Text); + + // testing axis value of biasAdd + loco::Graph::NodeContext *loco_nodes = graph->nodes(); + loco::BiasAdd *bias_add = + dynamic_cast *>(loco_nodes->at(3)); + ASSERT_NE(bias_add, nullptr); + + ASSERT_EQ(bias_add->axis(), 1); // NCHW +} diff --git a/contrib/moco/lib/frontend/tf/src/Transforms/FixPaddingTransform.cpp b/contrib/moco/lib/frontend/tf/src/Transforms/FixPaddingTransform.cpp index b030e31..5055670 100644 --- a/contrib/moco/lib/frontend/tf/src/Transforms/FixPaddingTransform.cpp +++ b/contrib/moco/lib/frontend/tf/src/Transforms/FixPaddingTransform.cpp @@ -97,6 +97,18 @@ bool fix_padding(loco::AvgPool2D *node) return true; } +bool fix_padding(loco::BiasAdd *node) +{ + // Nothing to do with padding + return false; +} + +bool fix_padding(loco::BiasEncode *node) +{ + // Nothing to do with padding + return false; +} + bool fix_padding(loco::ConstGen *node) { // Nothing to do with padding diff --git a/contrib/moco/lib/frontend/tf/src/Transforms/FixShapeTransform.cpp b/contrib/moco/lib/frontend/tf/src/Transforms/FixShapeTransform.cpp index 93e1559..d551fe4 100644 --- a/contrib/moco/lib/frontend/tf/src/Transforms/FixShapeTransform.cpp +++ b/contrib/moco/lib/frontend/tf/src/Transforms/FixShapeTransform.cpp @@ -150,6 +150,19 @@ bool fix_shape(loco::AvgPool2D *node) return true; } +bool fix_shape(loco::BiasAdd *node) +{ + // Output shape is same as the input + auto input = node->value(); // BiasAdd accepts n dimension tensor + return copy_shapedata(input, node); // after adding Bias, output shape is same with input +} + +bool fix_shape(loco::BiasEncode *node) +{ + auto input = node->input(); + return copy_shapedata(input, node); +} + bool fix_shape(loco::ConstGen *node) { auto shapedata = node->annot(); diff --git a/contrib/moco/lib/frontend/tf/src/Transforms/MocoNodes.lst b/contrib/moco/lib/frontend/tf/src/Transforms/MocoNodes.lst index 3dd849e..536b771 100644 --- a/contrib/moco/lib/frontend/tf/src/Transforms/MocoNodes.lst +++ b/contrib/moco/lib/frontend/tf/src/Transforms/MocoNodes.lst @@ -5,6 +5,8 @@ // MOCONODE(Name) : alphabetic order please MOCONODE(AvgPool2D) +MOCONODE(BiasAdd) +MOCONODE(BiasEncode) MOCONODE(ConstGen) MOCONODE(Conv2D) MOCONODE(FeatureDecode) -- 2.7.4