From 718f32fce1df290c3244974518c73b6c3cf4f0ff Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Wed, 17 Apr 2019 21:29:35 -0700 Subject: [PATCH 01/16] Search for graph def in function library if not found --- src/ngraph_cluster_manager.cc | 2 +- src/ngraph_encapsulate_op.cc | 25 +- test/python/common.py | 8 +- test/python/flib_graph_1.pbtxt | 284 ++++++++++++++++++++ test/python/flib_graph_2.pbtxt | 478 +++++++++++++++++++++++++++++++++ test/python/test_flib.py | 89 ++++++ 6 files changed, 878 insertions(+), 8 deletions(-) create mode 100644 test/python/flib_graph_1.pbtxt create mode 100644 test/python/flib_graph_2.pbtxt create mode 100644 test/python/test_flib.py diff --git a/src/ngraph_cluster_manager.cc b/src/ngraph_cluster_manager.cc index c6f27b86..bbb8a115 100644 --- a/src/ngraph_cluster_manager.cc +++ b/src/ngraph_cluster_manager.cc @@ -34,7 +34,7 @@ int NGraphClusterManager::NewCluster() { GraphDef* NGraphClusterManager::GetClusterGraph(int idx) { std::lock_guard guard(s_cluster_graphs_mutex); - return s_cluster_graphs[idx]; + return idx < s_cluster_graphs.size() ? s_cluster_graphs[idx] : nullptr; } } // namespace ngraph_bridge diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index 4365625e..5aacbc1c 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -18,6 +18,7 @@ #include #include "tensorflow/core/common_runtime/dma_helper.h" +#include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/optimization_registry.h" #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/framework/node_def_util.h" @@ -93,9 +94,27 @@ class NGraphEncapsulateOp : public OpKernel { OP_REQUIRES_OK(ctx, ctx->GetAttr("ngraph_cluster", &m_ngraph_cluster)); graph_def = NGraphClusterManager::GetClusterGraph(m_ngraph_cluster); - GraphConstructorOptions opts; - opts.allow_internal_ops = true; - OP_REQUIRES_OK(ctx, ConvertGraphDefToGraph(opts, *graph_def, &m_graph)); + if (graph_def == nullptr) { + // Read graphdef from function library + const FunctionLibraryDefinition flib = + *ctx->function_library()->GetFunctionLibraryDefinition(); + const FunctionDef* fdef = + flib.Find("Enc_" + to_string(m_ngraph_cluster) + "_native_segment"); + if (fdef == nullptr) { + // TODO: error + } + // TODO: how to convert from functiondef to graphdef. Anything easier? + FunctionBody* fnbody; + const auto get_func_sig = [&flib](const string& op, const OpDef** sig) { + return flib.LookUpOpDef(op, sig); + }; + FunctionDefToBodyHelper(*fdef, {}, &flib, get_func_sig, &fnbody); + CopyGraph(*fnbody->graph, &m_graph); + } else { + GraphConstructorOptions opts; + opts.allow_internal_ops = true; + OP_REQUIRES_OK(ctx, ConvertGraphDefToGraph(opts, *graph_def, &m_graph)); + } OP_REQUIRES_OK(ctx, ctx->GetAttr("ngraph_graph_id", &m_graph_id)); // // Initialize the "m_input_is_static" vector as follows: diff --git a/test/python/common.py b/test/python/common.py index 2a34dea4..4155ddfa 100644 --- a/test/python/common.py +++ b/test/python/common.py @@ -32,7 +32,7 @@ class NgraphTest(object): - def with_ngraph(self, l, config=tf.ConfigProto()): + def with_ngraph(self, l, config=tf.ConfigProto(), graph=None): if ngraph_bridge.is_grappler_enabled(): rewrite_options = rewriter_config_pb2.RewriterConfig( meta_optimizer_iterations=rewriter_config_pb2.RewriterConfig. @@ -50,7 +50,7 @@ def with_ngraph(self, l, config=tf.ConfigProto()): os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' ngraph_bridge.enable() - with tf.Session(config=config) as sess: + with tf.Session(graph=graph, config=config) as sess: retval = l(sess) os.environ.pop('NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS', None) @@ -61,12 +61,12 @@ def with_ngraph(self, l, config=tf.ConfigProto()): return retval - def without_ngraph(self, l, config=tf.ConfigProto()): + def without_ngraph(self, l, config=tf.ConfigProto(), graph=None): ngraph_tf_disable_deassign_clusters = os.environ.pop( 'NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS', None) ngraph_bridge.disable() - with tf.Session(config=config) as sess: + with tf.Session(graph=graph, config=config) as sess: retval = l(sess) if ngraph_tf_disable_deassign_clusters is not None: diff --git a/test/python/flib_graph_1.pbtxt b/test/python/flib_graph_1.pbtxt new file mode 100644 index 00000000..a7411386 --- /dev/null +++ b/test/python/flib_graph_1.pbtxt @@ -0,0 +1,284 @@ +node { + name: "Placeholder_2" + op: "Placeholder" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } +} +node { + name: "Placeholder_1" + op: "Placeholder" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } +} +node { + name: "Placeholder" + op: "Placeholder" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } +} +node { + name: "ngraph_cluster_0" + op: "NGraphEncapsulate" + input: "Placeholder" + input: "Placeholder_1" + input: "Placeholder_2" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "Targuments" + value { + list { + type: DT_FLOAT + type: DT_FLOAT + type: DT_FLOAT + } + } + } + attr { + key: "Tresults" + value { + list { + type: DT_FLOAT + type: DT_FLOAT + } + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "ngraph_cluster" + value { + i: 0 + } + } + attr { + key: "ngraph_graph_id" + value { + i: 0 + } + } +} +node { + name: "add_1" + op: "IdentityN" + input: "ngraph_cluster_0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + list { + type: DT_FLOAT + } + } + } +} +node { + name: "Sigmoid" + op: "IdentityN" + input: "ngraph_cluster_0:1" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + list { + type: DT_FLOAT + } + } + } +} +library { + function { + signature { + name: "Enc_0_native_segment" + input_arg { + name: "ngraph_input_0" + type: DT_FLOAT + } + input_arg { + name: "ngraph_input_1" + type: DT_FLOAT + } + input_arg { + name: "ngraph_input_2" + type: DT_FLOAT + } + output_arg { + name: "ngraph_output_0" + type: DT_FLOAT + } + output_arg { + name: "ngraph_output_1" + type: DT_FLOAT + } + } + node_def { + name: "add" + op: "Add" + input: "ngraph_input_0" + input: "ngraph_input_1" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_FLOAT + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 0 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "add" + } + } + node_def { + name: "add_1_ngraph/_0" + op: "Add" + input: "add:z:0" + input: "ngraph_input_2" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_FLOAT + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 0 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "add_1_ngraph/_0" + } + } + node_def { + name: "Sigmoid_ngraph/_1" + op: "Sigmoid" + input: "add_1_ngraph/_0:z:0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_FLOAT + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 0 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "Sigmoid_ngraph/_1" + } + } + ret { + key: "ngraph_output_0" + value: "add_1_ngraph/_0:z:0" + } + ret { + key: "ngraph_output_1" + value: "Sigmoid_ngraph/_1:y:0" + } + } +} +versions { + producer: 27 +} \ No newline at end of file diff --git a/test/python/flib_graph_2.pbtxt b/test/python/flib_graph_2.pbtxt new file mode 100644 index 00000000..405c188b --- /dev/null +++ b/test/python/flib_graph_2.pbtxt @@ -0,0 +1,478 @@ +node { + name: "Variable_2/peek/_2" + op: "NGraphVariable" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "container" + value { + s: "" + } + } + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "just_looking" + value { + b: true + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } + attr { + key: "shared_name" + value { + s: "Variable_2" + } + } +} +node { + name: "Variable_1/peek/_3" + op: "NGraphVariable" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "container" + value { + s: "" + } + } + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "just_looking" + value { + b: true + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } + attr { + key: "shared_name" + value { + s: "Variable_1" + } + } +} +node { + name: "Variable/peek/_4" + op: "NGraphVariable" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "container" + value { + s: "" + } + } + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "just_looking" + value { + b: true + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } + attr { + key: "shared_name" + value { + s: "Variable" + } + } +} +node { + name: "ngraph_cluster_1" + op: "NGraphEncapsulate" + input: "Variable_2/peek/_2" + input: "Variable_1/peek/_3" + input: "Variable/peek/_4" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "Targuments" + value { + list { + type: DT_DOUBLE + type: DT_DOUBLE + type: DT_DOUBLE + } + } + } + attr { + key: "Tresults" + value { + list { + type: DT_DOUBLE + type: DT_DOUBLE + } + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "ngraph_graph_id" + value { + i: 1 + } + } +} +node { + name: "add_1" + op: "IdentityN" + input: "ngraph_cluster_1" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + list { + type: DT_DOUBLE + } + } + } +} +node { + name: "Sigmoid" + op: "IdentityN" + input: "ngraph_cluster_1:1" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + list { + type: DT_DOUBLE + } + } + } +} +library { + function { + signature { + name: "Enc_1_native_segment" + input_arg { + name: "ngraph_input_0" + type: DT_DOUBLE + } + input_arg { + name: "ngraph_input_1" + type: DT_DOUBLE + } + input_arg { + name: "ngraph_input_2" + type: DT_DOUBLE + } + output_arg { + name: "ngraph_output_0" + type: DT_DOUBLE + } + output_arg { + name: "ngraph_output_1" + type: DT_DOUBLE + } + } + node_def { + name: "Variable_2/read" + op: "Identity" + input: "ngraph_input_0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@Variable_2" + } + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "Variable_2/read" + } + } + node_def { + name: "Variable_1/read" + op: "Identity" + input: "ngraph_input_1" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@Variable_1" + } + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "Variable_1/read" + } + } + node_def { + name: "Variable/read" + op: "Identity" + input: "ngraph_input_2" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@Variable" + } + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "Variable/read" + } + } + node_def { + name: "add" + op: "Add" + input: "Variable/read:output:0" + input: "Variable_1/read:output:0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_grappler:ArithmeticOptimizer:MinimizeBroadcasts" + value { + b: true + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "add" + } + } + node_def { + name: "add_1_ngraph/_0" + op: "Add" + input: "add:z:0" + input: "Variable_2/read:output:0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_grappler:ArithmeticOptimizer:MinimizeBroadcasts" + value { + b: true + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "add_1_ngraph/_0" + } + } + node_def { + name: "Sigmoid_ngraph/_1" + op: "Sigmoid" + input: "add_1_ngraph/_0:z:0" + device: "/job:localhost/replica:0/task:0/device:CPU:0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_ngraph_backend" + value { + s: "CPU" + } + } + attr { + key: "_ngraph_cluster" + value { + i: 1 + } + } + attr { + key: "_ngraph_marked_for_clustering" + value { + b: true + } + } + experimental_debug_info { + original_node_names: "Sigmoid_ngraph/_1" + } + } + ret { + key: "ngraph_output_0" + value: "add_1_ngraph/_0:z:0" + } + ret { + key: "ngraph_output_1" + value: "Sigmoid_ngraph/_1:y:0" + } + } + function { + signature { + name: "Enc_0_native_segment" + } + } +} +versions { + producer: 27 +} \ No newline at end of file diff --git a/test/python/test_flib.py b/test/python/test_flib.py new file mode 100644 index 00000000..20f225f4 --- /dev/null +++ b/test/python/test_flib.py @@ -0,0 +1,89 @@ +# ============================================================================== +# Copyright 2019 Intel Corporation +# +# 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. +# ============================================================================== +"""nGraph TensorFlow bridge floor operation test +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest, pdb + +import tensorflow as tf +import numpy as np +from common import NgraphTest +from google.protobuf import text_format + + +def import_pbtxt(pb_filename): + graph_def = tf.GraphDef() + with open(pb_filename, "r") as f: + text_format.Merge(f.read(), graph_def) + + with tf.Graph().as_default() as graph: + tf.import_graph_def(graph_def) + return graph + + +def get_tensor(graph, tname): + return graph.get_tensor_by_name("import/" + tname) + + +class TestFloorOperations(NgraphTest): + + def test_flib_1(self): + graph = import_pbtxt('flib_graph_1.pbtxt') + + x = get_tensor(graph, "Placeholder:0") + y = get_tensor(graph, "Placeholder_1:0") + z = get_tensor(graph, "Placeholder_2:0") + + a = get_tensor(graph, "add_1:0") + b = get_tensor(graph, "Sigmoid:0") + + sess_fn = lambda sess: sess.run( + [a, b], feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) + + res1 = self.with_ngraph(sess_fn, graph=graph) + res2 = self.without_ngraph(sess_fn, graph=graph) + exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] + # Note both run on Host (because NgraphEncapsulate can only run on host) + assert np.isclose(res1, res2).all() + # Comparing with expected value + assert np.isclose(res1, exp).all() + + @pytest.mark.skip(reason="Not passing through grappler") + def test_flib_2(self): + graph = import_pbtxt('flib_graph_2.pbtxt') + + x = get_tensor(graph, "Variable_2/peek/_2:0") + y = get_tensor(graph, "Variable_1/peek/_3:0") + z = get_tensor(graph, "Variable/peek/_4:0") + + a = get_tensor(graph, "add_1:0") + b = get_tensor(graph, "Sigmoid:0") + + def sess_fn(sess): + #sess.run(tf.global_variables_initializer()) + return sess.run( + [a, b], feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) + + res1 = self.with_ngraph(sess_fn, graph=graph) + res2 = self.without_ngraph(sess_fn, graph=graph) + exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] + # Note both run on Host (because NgraphEncapsulate can only run on host) + assert np.isclose(res1, res2).all() + # Comparing with expected value + assert np.isclose(res1, exp).all() #fails From b3e57b047fb613e433210857d6caf8851f35d141 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Wed, 17 Apr 2019 21:32:56 -0700 Subject: [PATCH 02/16] Handle error (when gdef not found) --- src/ngraph_encapsulate_op.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index 5aacbc1c..7f38383f 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -101,7 +101,10 @@ class NGraphEncapsulateOp : public OpKernel { const FunctionDef* fdef = flib.Find("Enc_" + to_string(m_ngraph_cluster) + "_native_segment"); if (fdef == nullptr) { - // TODO: error + OP_REQUIRES_OK( + ctx, errors::Internal( + "Did not find graphdef for encapsulate ", m_ngraph_cluster, + " in NGraphClusterManager or function library")); } // TODO: how to convert from functiondef to graphdef. Anything easier? FunctionBody* fnbody; From 8015046258abe3296b7244302aa1d4afee908183 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 18 Apr 2019 09:37:19 -0700 Subject: [PATCH 03/16] Fixing file path to pass ci --- test/python/test_flib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 20f225f4..8ae05a79 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -44,7 +44,7 @@ def get_tensor(graph, tname): class TestFloorOperations(NgraphTest): def test_flib_1(self): - graph = import_pbtxt('flib_graph_1.pbtxt') + graph = import_pbtxt('../../../test/python/flib_graph_1.pbtxt') x = get_tensor(graph, "Placeholder:0") y = get_tensor(graph, "Placeholder_1:0") @@ -66,7 +66,7 @@ def test_flib_1(self): @pytest.mark.skip(reason="Not passing through grappler") def test_flib_2(self): - graph = import_pbtxt('flib_graph_2.pbtxt') + graph = import_pbtxt('../../../test/python/flib_graph_2.pbtxt') x = get_tensor(graph, "Variable_2/peek/_2:0") y = get_tensor(graph, "Variable_1/peek/_3:0") From 5af5bb9fe2a864ceaba2c9a246a5bc249b7db838 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 18 Apr 2019 13:33:02 -0700 Subject: [PATCH 04/16] Make symlinks to the pbtxts --- test/python/CMakeLists.txt | 11 +++++++++++ test/python/test_flib.py | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/test/python/CMakeLists.txt b/test/python/CMakeLists.txt index fe5cbf3e..71360b93 100644 --- a/test/python/CMakeLists.txt +++ b/test/python/CMakeLists.txt @@ -23,4 +23,15 @@ foreach(file ${files}) ) endforeach() +execute_process( + COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/flib_graph_1.pbtxt + ${CMAKE_CURRENT_BINARY_DIR}/flib_graph_1.pbtxt +) + +execute_process( + COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/flib_graph_2.pbtxt + ${CMAKE_CURRENT_BINARY_DIR}/flib_graph_2.pbtxt +) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 8ae05a79..20f225f4 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -44,7 +44,7 @@ def get_tensor(graph, tname): class TestFloorOperations(NgraphTest): def test_flib_1(self): - graph = import_pbtxt('../../../test/python/flib_graph_1.pbtxt') + graph = import_pbtxt('flib_graph_1.pbtxt') x = get_tensor(graph, "Placeholder:0") y = get_tensor(graph, "Placeholder_1:0") @@ -66,7 +66,7 @@ def test_flib_1(self): @pytest.mark.skip(reason="Not passing through grappler") def test_flib_2(self): - graph = import_pbtxt('../../../test/python/flib_graph_2.pbtxt') + graph = import_pbtxt('flib_graph_2.pbtxt') x = get_tensor(graph, "Variable_2/peek/_2:0") y = get_tensor(graph, "Variable_1/peek/_3:0") From 0f9c6c45cd3a277c5a8815f2262dae350e056e9f Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 18 Apr 2019 13:45:01 -0700 Subject: [PATCH 05/16] Adding debug prints to see dir in ci --- test/python/test_flib.py | 3 +++ tools/test_utils.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 20f225f4..121854be 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -44,6 +44,9 @@ def get_tensor(graph, tname): class TestFloorOperations(NgraphTest): def test_flib_1(self): + import os + cwd = os.getcwd() + print(cwd) graph = import_pbtxt('flib_graph_1.pbtxt') x = get_tensor(graph, "Placeholder:0") diff --git a/tools/test_utils.py b/tools/test_utils.py index 87b1c7a1..f201e383 100755 --- a/tools/test_utils.py +++ b/tools/test_utils.py @@ -124,7 +124,7 @@ def run_ngtf_pytests(venv_dir, build_dir): command_executor(["pip", "install", "-U", "pytest"]) command_executor(["pip", "install", "-U", "psutil"]) command_executor([ - "python", "-m", "pytest", ('--junitxml=%s/xunit_pytest.xml' % build_dir) + "python", "-m", "pytest", "-s", ('--junitxml=%s/xunit_pytest.xml' % build_dir) ], verbose=True) From dd95acea723c27b46195cd2e893dfcdfca6116a0 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 18 Apr 2019 14:07:25 -0700 Subject: [PATCH 06/16] Copying to artifacts/test/python --- test/CMakeLists.txt | 5 +++++ test/python/test_flib.py | 2 +- tools/test_utils.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 16e20d2f..68668a18 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -108,3 +108,8 @@ install( DESTINATION ${CMAKE_INSTALL_PREFIX}/test FILES_MATCHING PATTERN "*.py" ) +install( + DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/python + DESTINATION ${CMAKE_INSTALL_PREFIX}/test + FILES_MATCHING PATTERN "*.pbtxt" +) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 121854be..930e731f 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -19,7 +19,7 @@ from __future__ import division from __future__ import print_function -import pytest, pdb +import pytest import tensorflow as tf import numpy as np diff --git a/tools/test_utils.py b/tools/test_utils.py index f201e383..87b1c7a1 100755 --- a/tools/test_utils.py +++ b/tools/test_utils.py @@ -124,7 +124,7 @@ def run_ngtf_pytests(venv_dir, build_dir): command_executor(["pip", "install", "-U", "pytest"]) command_executor(["pip", "install", "-U", "psutil"]) command_executor([ - "python", "-m", "pytest", "-s", ('--junitxml=%s/xunit_pytest.xml' % build_dir) + "python", "-m", "pytest", ('--junitxml=%s/xunit_pytest.xml' % build_dir) ], verbose=True) From fee79fe3e4db1245b1fa1eb67f60aefcbde706c7 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 18 Apr 2019 17:29:19 -0700 Subject: [PATCH 07/16] WIP: check if graph is already processed --- src/grappler/ngraph_optimizer.cc | 3 ++- src/ngraph_rewrite_pass.cc | 6 ++++-- src/ngraph_utils.cc | 7 ++++++- src/ngraph_utils.h | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/grappler/ngraph_optimizer.cc b/src/grappler/ngraph_optimizer.cc index 5879e885..d59dc9ca 100644 --- a/src/grappler/ngraph_optimizer.cc +++ b/src/grappler/ngraph_optimizer.cc @@ -64,7 +64,8 @@ Status NgraphOptimizer::Optimize(tensorflow::grappler::Cluster* cluster, // we will not do anything; all subsequent // passes become a no-op. if (config::IsEnabled() == false || - std::getenv("NGRAPH_TF_DISABLE") != nullptr) { + std::getenv("NGRAPH_TF_DISABLE") != nullptr || + IsProcessedByNgraphPass(&graph)) { NGRAPH_VLOG(0) << "NGTF_OPTIMIZER: Ngraph is disabled "; graph.ToGraphDef(output); return Status::OK(); diff --git a/src/ngraph_rewrite_pass.cc b/src/ngraph_rewrite_pass.cc index 966a853f..05bcf7e5 100644 --- a/src/ngraph_rewrite_pass.cc +++ b/src/ngraph_rewrite_pass.cc @@ -123,7 +123,8 @@ class NGraphVariableCapturePass : public NGraphRewritePass { // we will not do anything; all subsequent // passes become a no-op. if (config::IsEnabled() == false || - std::getenv("NGRAPH_TF_DISABLE") != nullptr) { + std::getenv("NGRAPH_TF_DISABLE") != nullptr || + IsProcessedByNgraphPass(options.graph)) { return Status::OK(); } @@ -182,7 +183,8 @@ class NGraphEncapsulationPass : public NGraphRewritePass { // we will not do anything; all subsequent // passes become a no-op. if (config::IsEnabled() == false || - std::getenv("NGRAPH_TF_DISABLE") != nullptr) { + std::getenv("NGRAPH_TF_DISABLE") != nullptr || + IsProcessedByNgraphPass(options.graph)) { return Status::OK(); } diff --git a/src/ngraph_utils.cc b/src/ngraph_utils.cc index 342086e4..255a00d7 100644 --- a/src/ngraph_utils.cc +++ b/src/ngraph_utils.cc @@ -378,7 +378,12 @@ void AllreduceOpControlOrder( } } } -}; +} + +bool IsProcessedByNgraphPass(Graph* g) { + // TODO: + return false; +} } // namespace ngraph_bridge diff --git a/src/ngraph_utils.h b/src/ngraph_utils.h index 78953e37..696398a9 100644 --- a/src/ngraph_utils.h +++ b/src/ngraph_utils.h @@ -63,6 +63,8 @@ bool IsNGVariableType(string node_type); // Node-types that are executed on nGraph bool IsNGSupportedType(string node_type); +bool IsProcessedByNgraphPass(Graph* g); + // Taken from: tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc // Extract values from a Const op to `values`. Returns true if succeeds. // From 41787247eb442a00b8d1941e1ff537487fd8255c Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 11:18:48 -0700 Subject: [PATCH 08/16] Do not reprocess if already processed --- src/ngraph_mark_for_clustering.cc | 1 + src/ngraph_utils.cc | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ngraph_mark_for_clustering.cc b/src/ngraph_mark_for_clustering.cc index e598d7ae..f050e4d1 100644 --- a/src/ngraph_mark_for_clustering.cc +++ b/src/ngraph_mark_for_clustering.cc @@ -291,6 +291,7 @@ Status MarkForClustering(Graph* graph, confirmation_function_map["Minimum"] = SimpleConfirmationFunction(); confirmation_function_map["Mul"] = SimpleConfirmationFunction(); confirmation_function_map["Neg"] = SimpleConfirmationFunction(); + confirmation_function_map["NoOp"] = SimpleConfirmationFunction(); confirmation_function_map["OneHot"] = SimpleConfirmationFunction(); confirmation_function_map["Pad"] = SimpleConfirmationFunction(); confirmation_function_map["Pow"] = SimpleConfirmationFunction(); diff --git a/src/ngraph_utils.cc b/src/ngraph_utils.cc index 255a00d7..a4af33d1 100644 --- a/src/ngraph_utils.cc +++ b/src/ngraph_utils.cc @@ -381,7 +381,15 @@ void AllreduceOpControlOrder( } bool IsProcessedByNgraphPass(Graph* g) { - // TODO: + // TODO: place a dummy node as a marker + // Current method may fail when graph had no encapsulates or ngvars after + // first pass + // Also variable/optimizer change introduces other types of ng nodes + for (Node* node : g->nodes()) { + if (node->type_string() == "NGraphEncapsulate" || + node->type_string() == "NGraphVariable") + return true; + } return false; } From a931716888818db7be8bc60f56d5a27773dc1e3d Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 11:24:34 -0700 Subject: [PATCH 09/16] Review comment --- src/ngraph_encapsulate_op.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index 7f38383f..e5103345 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -100,12 +100,12 @@ class NGraphEncapsulateOp : public OpKernel { *ctx->function_library()->GetFunctionLibraryDefinition(); const FunctionDef* fdef = flib.Find("Enc_" + to_string(m_ngraph_cluster) + "_native_segment"); - if (fdef == nullptr) { - OP_REQUIRES_OK( - ctx, errors::Internal( - "Did not find graphdef for encapsulate ", m_ngraph_cluster, - " in NGraphClusterManager or function library")); - } + OP_REQUIRES( + ctx, fdef == nullptr, + errors::Internal("Did not find graphdef for encapsulate ", + m_ngraph_cluster, + " in NGraphClusterManager or function library")); + // TODO: how to convert from functiondef to graphdef. Anything easier? FunctionBody* fnbody; const auto get_func_sig = [&flib](const string& op, const OpDef** sig) { From 354bc3eb1af8349871044d1e4d61befd4947910c Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 11:40:07 -0700 Subject: [PATCH 10/16] Boolean flip --- src/ngraph_encapsulate_op.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index e5103345..09b0115b 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -101,11 +101,10 @@ class NGraphEncapsulateOp : public OpKernel { const FunctionDef* fdef = flib.Find("Enc_" + to_string(m_ngraph_cluster) + "_native_segment"); OP_REQUIRES( - ctx, fdef == nullptr, + ctx, fdef != nullptr, errors::Internal("Did not find graphdef for encapsulate ", m_ngraph_cluster, " in NGraphClusterManager or function library")); - // TODO: how to convert from functiondef to graphdef. Anything easier? FunctionBody* fnbody; const auto get_func_sig = [&flib](const string& op, const OpDef** sig) { From f404662929d6b9426d1e8e9fe0706a769d62388b Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 11:50:34 -0700 Subject: [PATCH 11/16] Making pbtxt graph default --- test/python/common.py | 8 ++--- test/python/test_flib.py | 71 +++++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/test/python/common.py b/test/python/common.py index 4155ddfa..2a34dea4 100644 --- a/test/python/common.py +++ b/test/python/common.py @@ -32,7 +32,7 @@ class NgraphTest(object): - def with_ngraph(self, l, config=tf.ConfigProto(), graph=None): + def with_ngraph(self, l, config=tf.ConfigProto()): if ngraph_bridge.is_grappler_enabled(): rewrite_options = rewriter_config_pb2.RewriterConfig( meta_optimizer_iterations=rewriter_config_pb2.RewriterConfig. @@ -50,7 +50,7 @@ def with_ngraph(self, l, config=tf.ConfigProto(), graph=None): os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' ngraph_bridge.enable() - with tf.Session(graph=graph, config=config) as sess: + with tf.Session(config=config) as sess: retval = l(sess) os.environ.pop('NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS', None) @@ -61,12 +61,12 @@ def with_ngraph(self, l, config=tf.ConfigProto(), graph=None): return retval - def without_ngraph(self, l, config=tf.ConfigProto(), graph=None): + def without_ngraph(self, l, config=tf.ConfigProto()): ngraph_tf_disable_deassign_clusters = os.environ.pop( 'NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS', None) ngraph_bridge.disable() - with tf.Session(graph=graph, config=config) as sess: + with tf.Session(config=config) as sess: retval = l(sess) if ngraph_tf_disable_deassign_clusters is not None: diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 930e731f..1ee89601 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -48,45 +48,50 @@ def test_flib_1(self): cwd = os.getcwd() print(cwd) graph = import_pbtxt('flib_graph_1.pbtxt') + with graph.as_default() as g: - x = get_tensor(graph, "Placeholder:0") - y = get_tensor(graph, "Placeholder_1:0") - z = get_tensor(graph, "Placeholder_2:0") + x = get_tensor(g, "Placeholder:0") + y = get_tensor(g, "Placeholder_1:0") + z = get_tensor(g, "Placeholder_2:0") - a = get_tensor(graph, "add_1:0") - b = get_tensor(graph, "Sigmoid:0") + a = get_tensor(g, "add_1:0") + b = get_tensor(g, "Sigmoid:0") - sess_fn = lambda sess: sess.run( - [a, b], feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) + sess_fn = lambda sess: sess.run( + [a, b], feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) - res1 = self.with_ngraph(sess_fn, graph=graph) - res2 = self.without_ngraph(sess_fn, graph=graph) - exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] - # Note both run on Host (because NgraphEncapsulate can only run on host) - assert np.isclose(res1, res2).all() - # Comparing with expected value - assert np.isclose(res1, exp).all() + res1 = self.with_ngraph(sess_fn) + res2 = self.without_ngraph(sess_fn) + exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] + # Note both run on Host (because NgraphEncapsulate can only run on host) + assert np.isclose(res1, res2).all() + # Comparing with expected value + assert np.isclose(res1, exp).all() @pytest.mark.skip(reason="Not passing through grappler") def test_flib_2(self): graph = import_pbtxt('flib_graph_2.pbtxt') - x = get_tensor(graph, "Variable_2/peek/_2:0") - y = get_tensor(graph, "Variable_1/peek/_3:0") - z = get_tensor(graph, "Variable/peek/_4:0") - - a = get_tensor(graph, "add_1:0") - b = get_tensor(graph, "Sigmoid:0") - - def sess_fn(sess): - #sess.run(tf.global_variables_initializer()) - return sess.run( - [a, b], feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) - - res1 = self.with_ngraph(sess_fn, graph=graph) - res2 = self.without_ngraph(sess_fn, graph=graph) - exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] - # Note both run on Host (because NgraphEncapsulate can only run on host) - assert np.isclose(res1, res2).all() - # Comparing with expected value - assert np.isclose(res1, exp).all() #fails + graph = import_pbtxt('flib_graph_1.pbtxt') + with graph.as_default() as g: + + x = get_tensor(g, "Variable_2/peek/_2:0") + y = get_tensor(g, "Variable_1/peek/_3:0") + z = get_tensor(g, "Variable/peek/_4:0") + + a = get_tensor(g, "add_1:0") + b = get_tensor(g, "Sigmoid:0") + + def sess_fn(sess): + #sess.run(tf.global_variables_initializer()) + return sess.run( + [a, b], + feed_dict={i: np.full((2, 3), 1.0) for i in [x, y, z]}) + + res1 = self.with_ngraph(sess_fn) + res2 = self.without_ngraph(sess_fn) + exp = [np.full((2, 3), 3.0), np.full((2, 3), 0.95257413)] + # Note both run on Host (because NgraphEncapsulate can only run on host) + assert np.isclose(res1, res2).all() + # Comparing with expected value + assert np.isclose(res1, exp).all() #fails From d29966e263e5924c58b9b023899c6b0ec846e8fc Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 12:22:30 -0700 Subject: [PATCH 12/16] Pass pointer instead of unq ptr --- src/ngraph_rewrite_pass.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngraph_rewrite_pass.cc b/src/ngraph_rewrite_pass.cc index 05bcf7e5..cb733f5b 100644 --- a/src/ngraph_rewrite_pass.cc +++ b/src/ngraph_rewrite_pass.cc @@ -124,7 +124,7 @@ class NGraphVariableCapturePass : public NGraphRewritePass { // passes become a no-op. if (config::IsEnabled() == false || std::getenv("NGRAPH_TF_DISABLE") != nullptr || - IsProcessedByNgraphPass(options.graph)) { + IsProcessedByNgraphPass(options.graph->get())) { return Status::OK(); } @@ -184,7 +184,7 @@ class NGraphEncapsulationPass : public NGraphRewritePass { // passes become a no-op. if (config::IsEnabled() == false || std::getenv("NGRAPH_TF_DISABLE") != nullptr || - IsProcessedByNgraphPass(options.graph)) { + IsProcessedByNgraphPass(options.graph->get())) { return Status::OK(); } From 91b88e6b84617c88a23225519a3da7b89f8104e0 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Fri, 19 Apr 2019 12:58:40 -0700 Subject: [PATCH 13/16] Remove check from normal pass --- src/ngraph_rewrite_pass.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ngraph_rewrite_pass.cc b/src/ngraph_rewrite_pass.cc index cb733f5b..966a853f 100644 --- a/src/ngraph_rewrite_pass.cc +++ b/src/ngraph_rewrite_pass.cc @@ -123,8 +123,7 @@ class NGraphVariableCapturePass : public NGraphRewritePass { // we will not do anything; all subsequent // passes become a no-op. if (config::IsEnabled() == false || - std::getenv("NGRAPH_TF_DISABLE") != nullptr || - IsProcessedByNgraphPass(options.graph->get())) { + std::getenv("NGRAPH_TF_DISABLE") != nullptr) { return Status::OK(); } @@ -183,8 +182,7 @@ class NGraphEncapsulationPass : public NGraphRewritePass { // we will not do anything; all subsequent // passes become a no-op. if (config::IsEnabled() == false || - std::getenv("NGRAPH_TF_DISABLE") != nullptr || - IsProcessedByNgraphPass(options.graph->get())) { + std::getenv("NGRAPH_TF_DISABLE") != nullptr) { return Status::OK(); } From 04c7a008845060790f2df14418beb635648e847f Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Sun, 21 Apr 2019 16:45:01 -0700 Subject: [PATCH 14/16] Change floor to flib --- test/python/test_flib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 1ee89601..937d2e07 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""nGraph TensorFlow bridge floor operation test +"""nGraph TensorFlow bridge function library test """ from __future__ import absolute_import from __future__ import division @@ -41,7 +41,7 @@ def get_tensor(graph, tname): return graph.get_tensor_by_name("import/" + tname) -class TestFloorOperations(NgraphTest): +class TestFlibOperations(NgraphTest): def test_flib_1(self): import os From 126eeb13c39f28638db1682606838efe4bca233a Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Sun, 21 Apr 2019 16:46:24 -0700 Subject: [PATCH 15/16] Minor change --- test/python/test_flib.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index 937d2e07..f6b094b4 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -44,9 +44,6 @@ def get_tensor(graph, tname): class TestFlibOperations(NgraphTest): def test_flib_1(self): - import os - cwd = os.getcwd() - print(cwd) graph = import_pbtxt('flib_graph_1.pbtxt') with graph.as_default() as g: From ca8af0abe9287c76dcf2f0c75be1fd10e6a855b2 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Sun, 21 Apr 2019 16:58:44 -0700 Subject: [PATCH 16/16] Minor change --- test/python/test_flib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/python/test_flib.py b/test/python/test_flib.py index f6b094b4..7fcb7438 100644 --- a/test/python/test_flib.py +++ b/test/python/test_flib.py @@ -68,8 +68,6 @@ def test_flib_1(self): @pytest.mark.skip(reason="Not passing through grappler") def test_flib_2(self): graph = import_pbtxt('flib_graph_2.pbtxt') - - graph = import_pbtxt('flib_graph_1.pbtxt') with graph.as_default() as g: x = get_tensor(g, "Variable_2/peek/_2:0")