From 9fd8350f64c1afdab38ae93b68459cc6f6778fbc Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Fri, 12 Jul 2019 17:05:19 -0700 Subject: [PATCH 01/31] Made changes to NGraphAssignOp --- src/enable_variable_ops/ngraph_assign_op.cc | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/enable_variable_ops/ngraph_assign_op.cc b/src/enable_variable_ops/ngraph_assign_op.cc index 3965f72eb..5553d2ec0 100644 --- a/src/enable_variable_ops/ngraph_assign_op.cc +++ b/src/enable_variable_ops/ngraph_assign_op.cc @@ -125,19 +125,19 @@ class NGraphAssignOp : public OpKernel { // DO NOT CARE ABOUT SYNCING AS WE ARE ALWAYS SETTING THE NGTENSOR // Get input[1] - string valkey = to_string(ng_graph_id_) + "_" + def().input(1); - bool valref_exists = NGraphCatalog::ExistsInEncapOutputTensorMap(valkey); - if (valref_exists) { - // Value is from encap - NGRAPH_VLOG(4) << "NGraphAssign::Getting from catalog: " << valkey; - auto ng_val = NGraphCatalog::GetTensorFromEncapOutputTensorMap(valkey); - var->update_ng_tensor(ng_val); - } else { - NGRAPH_VLOG(4) << "NGraphAssign::Getting from TF : " << valkey; - if (var->update_ng_tensor(rhs_tensor)) { - number_of_copies++; - copy_log_str << " COPY_INP_VAL[0]"; - } + + // input[1] cannot be from NGraphEncap Op + // No way to get input node and check its type + string input_1_name = def().input(1); + OP_REQUIRES( + context, input_1_name.find("ngraph_cluster") == -1, + errors::Internal( + "Caught exception: Input to NGAssign from Encapsulate Op.\n")); + + NGRAPH_VLOG(4) << "NGraphAssign:: Updating"; + if (var->update_ng_tensor(rhs_tensor)) { + number_of_copies++; + copy_log_str << " COPY_INP_VAL[0]"; } mutex_lock l(*context->input_ref_mutex(0)); From 8e5a8ea8f37af7710f04ceea9d5485c0d9563b0a Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 15 Jul 2019 14:19:02 -0700 Subject: [PATCH 02/31] Added utilities to remove the enteries from the catalog maps. Removed entries in destructor of Encap Op --- src/enable_variable_ops/ngraph_catalog.cc | 8 ++++++++ src/enable_variable_ops/ngraph_catalog.h | 2 ++ .../ngraph_enter_in_catalog.h | 1 + src/ngraph_encapsulate_op.cc | 16 ++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/enable_variable_ops/ngraph_catalog.cc b/src/enable_variable_ops/ngraph_catalog.cc index ef1801828..1be782212 100644 --- a/src/enable_variable_ops/ngraph_catalog.cc +++ b/src/enable_variable_ops/ngraph_catalog.cc @@ -54,6 +54,10 @@ bool NGraphCatalog::EncapOutputIndexNeedsCopy(string key, int index) { return true; } +void NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(string key) { + NGraphCatalog::encap_output_copy_indexes_map_.erase(key); +} + string NGraphCatalog::CreateNodeKey(int graph_id, string node_name, int index) { if (index == 0) { return to_string(graph_id) + "_" + node_name; @@ -111,5 +115,9 @@ bool NGraphCatalog::ExistsInInputVariableSharedNameMap(int graphid, NGraphCatalog::CreateNodeKey(graphid, node_name, input_index)); } +void NGraphCatalog::DeleteFromInputVariableSharedNameMap(string key) { + NGraphCatalog::input_variable_sharedname_map_.erase(key); +} + } // ngraph_bridge } // tensorflow diff --git a/src/enable_variable_ops/ngraph_catalog.h b/src/enable_variable_ops/ngraph_catalog.h index 523e9c590..3fa74bbde 100644 --- a/src/enable_variable_ops/ngraph_catalog.h +++ b/src/enable_variable_ops/ngraph_catalog.h @@ -79,6 +79,7 @@ class NGraphCatalog { unordered_set val); static bool EncapOutputIndexNeedsCopy(string key, int index); static unordered_set GetEncapOutputIndexesThatNeedCopy(string key); + static void DeleteFromEncapOutputCopyIndexesMap(string key); // Functions for InputVariableSharedName Map static string GetInputVariableSharedName(int graphid, string node_name, @@ -89,6 +90,7 @@ class NGraphCatalog { static bool ExistsInInputVariableSharedNameMap(string key); static bool ExistsInInputVariableSharedNameMap(int graphid, string node_name, int input_index); + static void DeleteFromInputVariableSharedNameMap(string key); // Functions for EncapOutputTensorMap static void AddToEncapOutputTensorMap(string key, diff --git a/src/enable_variable_ops/ngraph_enter_in_catalog.h b/src/enable_variable_ops/ngraph_enter_in_catalog.h index ebb598daf..1a70f7c89 100644 --- a/src/enable_variable_ops/ngraph_enter_in_catalog.h +++ b/src/enable_variable_ops/ngraph_enter_in_catalog.h @@ -49,6 +49,7 @@ namespace ngraph_bridge { // We add mapping of {graphId_nodename_InputIndex : Shared_Name} to the // InputVariableSharedNameMap // +// TODO: Update the comments for EnacapOutputInfoMap // 2. If the output of NGraphEncapsulate Op is an input to NGraphVariableType // Op, we store this NG-Tensor // so that it can be directly accessed in compute call of NGraphVariableType. diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index f585aeb85..55de20b7b 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -225,13 +225,29 @@ class NGraphEncapsulateOp : public OpKernel { } #if defined(NGRAPH_TF_ENABLE_VARIABLES_AND_OPTIMIZERS) + // Remove Entries from Catalog + // Remove entries related to outputs for (int i = 0; i < m_number_outputs; i++) { string key = NGraphCatalog::CreateNodeKey(m_graph_id, name(), i); if (NGraphCatalog::ExistsInEncapOutputTensorMap(key)) { NGraphCatalog::DeleteFromEncapOutputTensorMap(key); NGRAPH_VLOG(2) << "Deleting from output tensor map " << key; } + if (NGraphCatalog::EncapOutputIndexNeedsCopy(name(), i)) { + NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(name()); + NGRAPH_VLOG(2) << "Deleting from Output Copy Index map " << name(); + } } + // Remove entries related to inputs + for (int i = 0; i < m_number_inputs; i++) { + string key = NGraphCatalog::CreateNodeKey(m_graph_id, name(), i); + if (NGraphCatalog::ExistsInInputVariableSharedNameMap(key)) { + NGraphCatalog::DeleteFromInputVariableSharedNameMap(key); + NGRAPH_VLOG(2) << "Deleting from input variable shared name map " + << key; + } + } + #endif // Release the backend From 168570957486e76d2726a9097a10fc5552241ac9 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 15 Jul 2019 14:41:50 -0700 Subject: [PATCH 03/31] Remove entries from Catalog in NGVariable Destructors. --- src/enable_variable_ops/ngraph_assign_op.cc | 8 +++++++- src/enable_variable_ops/ngraph_tracked_variable.cc | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/enable_variable_ops/ngraph_assign_op.cc b/src/enable_variable_ops/ngraph_assign_op.cc index 5553d2ec0..d647a164f 100644 --- a/src/enable_variable_ops/ngraph_assign_op.cc +++ b/src/enable_variable_ops/ngraph_assign_op.cc @@ -59,7 +59,13 @@ class NGraphAssignOp : public OpKernel { // use_exclusive_lock_, validate_shape_, relax_constraints_; public: - ~NGraphAssignOp() { NGRAPH_VLOG(4) << "~NGraphAssignOp::" << name() << endl; } + ~NGraphAssignOp() { + NGRAPH_VLOG(4) << "~NGraphAssignOp::" << name() << endl; + // Delete from Input Variable Shared Name Map + string key = NGraphCatalog::CreateNodeKey(ng_graph_id_, name(), 0); + NGraphCatalog::DeleteFromInputVariableSharedNameMap(key); + } + explicit NGraphAssignOp(OpKernelConstruction* context) : OpKernel(context), is_tf_just_looking_(false), copy_to_tf_(false) { OP_REQUIRES_OK( diff --git a/src/enable_variable_ops/ngraph_tracked_variable.cc b/src/enable_variable_ops/ngraph_tracked_variable.cc index 9c31a81a8..9675b941d 100644 --- a/src/enable_variable_ops/ngraph_tracked_variable.cc +++ b/src/enable_variable_ops/ngraph_tracked_variable.cc @@ -113,6 +113,8 @@ NGraphVariableOp::NGraphVariableOp(OpKernelConstruction* context) NGraphVariableOp::~NGraphVariableOp() { NGRAPH_VLOG(4) << "~NGraphVariableOp:: " << name() << endl; + string node_key = NGraphCatalog::CreateNodeKey(ng_graph_id_, name(), 0); + NGraphCatalog::DeleteFromInputVariableSharedNameMap(key); tracker_->Unref(); } From 8c3dd8051756df816531ca2614e0fbcc7d804f5f Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 15 Jul 2019 18:25:37 -0700 Subject: [PATCH 04/31] Modifications to catalog. Compiles --- src/enable_variable_ops/ngraph_catalog.cc | 15 +++++++++++---- src/enable_variable_ops/ngraph_catalog.h | 13 ++++++++----- .../ngraph_enter_in_catalog.cc | 2 +- .../ngraph_tracked_variable.cc | 3 ++- src/ngraph_encapsulate_op.cc | 14 +++++++++----- 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/enable_variable_ops/ngraph_catalog.cc b/src/enable_variable_ops/ngraph_catalog.cc index 1be782212..3c32dc818 100644 --- a/src/enable_variable_ops/ngraph_catalog.cc +++ b/src/enable_variable_ops/ngraph_catalog.cc @@ -34,17 +34,22 @@ unordered_map> NGraphCatalog::encap_output_copy_indexes_map_; // Functions for Encapsulate Output Copy Indexes Map -void NGraphCatalog::AddToEncapOutputCopyIndexesMap(string key, +void NGraphCatalog::AddToEncapOutputCopyIndexesMap(int graphid, + string node_name, unordered_set val) { + string key = graphid + "_" + node_name; NGraphCatalog::encap_output_copy_indexes_map_[key] = val; } unordered_set NGraphCatalog::GetEncapOutputIndexesThatNeedCopy( - string key) { + int graphid, string node_name) { + string key = graphid + "_" + node_name; return NGraphCatalog::encap_output_copy_indexes_map_[key]; } -bool NGraphCatalog::EncapOutputIndexNeedsCopy(string key, int index) { +bool NGraphCatalog::EncapOutputIndexNeedsCopy(int graphid, string node_name, + int index) { + string key = graphid + "_" + node_name; auto itr = NGraphCatalog::encap_output_copy_indexes_map_.find(key); if (itr != NGraphCatalog::encap_output_copy_indexes_map_.end()) { auto op_copy_indexes = itr->second; @@ -54,7 +59,9 @@ bool NGraphCatalog::EncapOutputIndexNeedsCopy(string key, int index) { return true; } -void NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(string key) { +void NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(int graphid, + string node_name) { + string key = graphid + "_" + node_name; NGraphCatalog::encap_output_copy_indexes_map_.erase(key); } diff --git a/src/enable_variable_ops/ngraph_catalog.h b/src/enable_variable_ops/ngraph_catalog.h index 3fa74bbde..49aefb042 100644 --- a/src/enable_variable_ops/ngraph_catalog.h +++ b/src/enable_variable_ops/ngraph_catalog.h @@ -67,7 +67,7 @@ class NGraphCatalog { // Will be used by NGraphEncapsulateOP // Map of // Key - // string : nodename (nGraphEncapsulateOp name) + // string : GraphId + _ + nodename // Value : Set of indices static unordered_map> encap_output_copy_indexes_map_; @@ -75,11 +75,14 @@ class NGraphCatalog { public: // Utility Functions for the data structures // Functions for EncapsulateOutputCopyIndexes Map - static void AddToEncapOutputCopyIndexesMap(string key, + static void AddToEncapOutputCopyIndexesMap(int graphid, string node_name, unordered_set val); - static bool EncapOutputIndexNeedsCopy(string key, int index); - static unordered_set GetEncapOutputIndexesThatNeedCopy(string key); - static void DeleteFromEncapOutputCopyIndexesMap(string key); + static bool EncapOutputIndexNeedsCopy(int graphid, string node_name, + int index); + static unordered_set GetEncapOutputIndexesThatNeedCopy(int graphid, + string node_name); + static void DeleteFromEncapOutputCopyIndexesMap(int graphid, + string node_name); // Functions for InputVariableSharedName Map static string GetInputVariableSharedName(int graphid, string node_name, diff --git a/src/enable_variable_ops/ngraph_enter_in_catalog.cc b/src/enable_variable_ops/ngraph_enter_in_catalog.cc index 3c05e8349..476d4c419 100644 --- a/src/enable_variable_ops/ngraph_enter_in_catalog.cc +++ b/src/enable_variable_ops/ngraph_enter_in_catalog.cc @@ -106,7 +106,7 @@ Status EnterInCatalog(Graph* graph, int graph_id) { op_index_to_copy.insert(edge->src_output()); } } - NGraphCatalog::AddToEncapOutputCopyIndexesMap(node->name(), + NGraphCatalog::AddToEncapOutputCopyIndexesMap(graph_id, node->name(), op_index_to_copy); } // end of node is type NGraphEncapsulate diff --git a/src/enable_variable_ops/ngraph_tracked_variable.cc b/src/enable_variable_ops/ngraph_tracked_variable.cc index 9675b941d..b8a758305 100644 --- a/src/enable_variable_ops/ngraph_tracked_variable.cc +++ b/src/enable_variable_ops/ngraph_tracked_variable.cc @@ -27,6 +27,7 @@ #include "ngraph_freshness_tracker.h" #include "ngraph_utils.h" #include "ngraph_var.h" +#include "ngraph_catalog.h" #include "ngraph/event_tracing.hpp" @@ -114,7 +115,7 @@ NGraphVariableOp::NGraphVariableOp(OpKernelConstruction* context) NGraphVariableOp::~NGraphVariableOp() { NGRAPH_VLOG(4) << "~NGraphVariableOp:: " << name() << endl; string node_key = NGraphCatalog::CreateNodeKey(ng_graph_id_, name(), 0); - NGraphCatalog::DeleteFromInputVariableSharedNameMap(key); + NGraphCatalog::DeleteFromInputVariableSharedNameMap(node_key); tracker_->Unref(); } diff --git a/src/ngraph_encapsulate_op.cc b/src/ngraph_encapsulate_op.cc index 55de20b7b..025c95883 100644 --- a/src/ngraph_encapsulate_op.cc +++ b/src/ngraph_encapsulate_op.cc @@ -233,11 +233,11 @@ class NGraphEncapsulateOp : public OpKernel { NGraphCatalog::DeleteFromEncapOutputTensorMap(key); NGRAPH_VLOG(2) << "Deleting from output tensor map " << key; } - if (NGraphCatalog::EncapOutputIndexNeedsCopy(name(), i)) { - NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(name()); - NGRAPH_VLOG(2) << "Deleting from Output Copy Index map " << name(); - } } + + NGRAPH_VLOG(2) << "Deleting from Output Copy Index map " << name(); + NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(m_graph_id, name()); + // Remove entries related to inputs for (int i = 0; i < m_number_inputs; i++) { string key = NGraphCatalog::CreateNodeKey(m_graph_id, name(), i); @@ -817,6 +817,8 @@ class NGraphEncapsulateOp : public OpKernel { if (m_number_outputs == -1) { NGRAPH_VLOG(4) << "Settig number of outputs for " << def().name(); m_number_outputs = output_caches.size(); + NGRAPH_VLOG(4) << "Settig number of inputs for " << def().name(); + m_number_inputs = ng_inputs.size(); } for (size_t i = 0; i < output_tensor_count; ++i) { string key = NGraphCatalog::CreateNodeKey(m_graph_id, def().name(), i); @@ -831,7 +833,8 @@ class NGraphEncapsulateOp : public OpKernel { } if (m_op_backend_name != "CPU" && - NGraphCatalog::EncapOutputIndexNeedsCopy(def().name(), i)) { + NGraphCatalog::EncapOutputIndexNeedsCopy(m_graph_id, def().name(), + i)) { number_of_copies++; copy_log_str << " COPY_OP_VAL[" << i << "]"; @@ -1009,6 +1012,7 @@ class NGraphEncapsulateOp : public OpKernel { static int s_instance_count; int my_instance_id{0}; int m_number_outputs = -1; + int m_number_inputs = -1; }; int NGraphEncapsulateOp::s_instance_count = 0; From 6c2dd52047155d61a866fa8e8e35cf32e10c6b9f Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Fri, 19 Jul 2019 10:46:00 -0700 Subject: [PATCH 05/31] Code Format --- src/enable_variable_ops/ngraph_tracked_variable.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enable_variable_ops/ngraph_tracked_variable.cc b/src/enable_variable_ops/ngraph_tracked_variable.cc index f96d59320..ac413d82c 100644 --- a/src/enable_variable_ops/ngraph_tracked_variable.cc +++ b/src/enable_variable_ops/ngraph_tracked_variable.cc @@ -23,10 +23,10 @@ #include "ngraph/runtime/backend.hpp" #include "ngraph_backend_manager.h" +#include "ngraph_catalog.h" #include "ngraph_freshness_tracker.h" #include "ngraph_utils.h" #include "ngraph_var.h" -#include "ngraph_catalog.h" #include "ngraph/event_tracing.hpp" From bc9b16a39b494da5cfd01cf7c541c199a4913871 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 22 Jul 2019 17:32:31 -0700 Subject: [PATCH 06/31] Not using RemoveEdge Api. Made changes to RewritePass --- .../ngraph_remove_ngraphassigns.cc | 7 ++-- .../ngraph_rewrite_pass.cc | 33 +++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc index 9752248be..6bf6fb1a5 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc @@ -45,6 +45,11 @@ Status RemoveNGraphAssigns(Graph* graph) { input_1->type_string()); } + // Handle input and output edges + // Only adding the new edges, edges to and from the current node will be + // removed when + // node is removed + // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/graph/graph.h#L495 // Handle input edges NGRAPH_VLOG(3) << "Handling input edges "; for (auto edge : node->in_edges()) { @@ -55,7 +60,6 @@ Status RemoveNGraphAssigns(Graph* graph) { if (edge->src() == input_1) continue; graph->AddEdge(edge->src(), edge->src_output(), input_1, edge->dst_input()); - graph->RemoveEdge(edge); } } @@ -80,7 +84,6 @@ Status RemoveNGraphAssigns(Graph* graph) { graph->AddEdge(input_1, Graph::kControlSlot, edge->dst(), Graph::kControlSlot); } - graph->RemoveEdge(edge); } // Add the node for removal diff --git a/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc b/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc index 98e1067f5..603dbc50f 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc @@ -22,6 +22,7 @@ #include "logging/ngraph_log.h" #include "logging/tf_graph_writer.h" #include "ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h" +#include "ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.h" #include "ngraph_bridge/enable_variable_ops/ngraph_replace_variable_modifiers.h" #include "ngraph_bridge/ngraph_api.h" #include "ngraph_bridge/ngraph_assign_clusters.h" @@ -206,16 +207,22 @@ class NGraphVariableCapturePass : public NGraphRewritePass { // 2. Cluster Assignment [ngraph_assign_clusters.cc] // 3. Cluster Deassignment [ngraph_deassign_clusters.cc] // 4. Cluster Encapsulation [ngraph_encapsulate_clusters.cc] -// +// 5. Rewrite Variable Type Ops for Tracking [ngraph_rewrite_for_tracking.cc] +// 6. Enter In Catalog [ngraph_enter_in_catalog.cc] +// 7. Remove NGraphAssigns [ngraph_remove_ngraphassigns.cc] // Between phases, graph dumps (in both .dot and .pbtxt format) may be // requested by setting the following environment variables: // -// NGRAPH_TF_DUMP_UNMARKED_GRAPHS=1 dumps graphs before phase 1 -// NGRAPH_TF_DUMP_MARKED_GRAPHS=1 dumps graphs after phase 1 -// NGRAPH_TF_DUMP_CLUSTERED_GRAPHS=1 dumps graphs after phase 2 -// NGRAPH_TF_DUMP_DECLUSTERED_GRAPHS=1 dumps graphs after phase 3 -// NGRAPH_TF_DUMP_ENCAPSULATED_GRAPHS=1 dumps graphs after phase 4 -// NGRAPH_TF_DUMP_GRAPHS=1 all of the above +// NGRAPH_TF_DUMP_UNMARKED_GRAPHS=1 dumps graphs before phase 0 +// NGRAPH_TF_DUMP_REPLACEDMODIFIERS_GRAPHS=1 dumps graphs after phase 0 +// NGRAPH_TF_DUMP_MARKED_GRAPHS=1 dumps graphs after phase 1 +// NGRAPH_TF_DUMP_CLUSTERED_GRAPHS=1 dumps graphs after phase 2 +// NGRAPH_TF_DUMP_DECLUSTERED_GRAPHS=1 dumps graphs after phase 3 +// NGRAPH_TF_DUMP_ENCAPSULATED_GRAPHS=1 dumps graphs after phase 4 +// NGRAPH_TF_DUMP_TRACKED_GRAPHS=1 dumps graphs after phase 5 +// NGRAPH_TF_DUMP_CATALOGED_GRAPHS=1 dumps graphs after phase 6 +// NGRAPH_TF_DUMP_REMOVENGASSIGNS_GRAPHS=1 dumps graphs after phase 7 +// NGRAPH_TF_DUMP_GRAPHS=1 all of the above // class NGraphEncapsulationPass : public NGraphRewritePass { public: @@ -323,6 +330,13 @@ class NGraphEncapsulationPass : public NGraphRewritePass { "Graph with Variables Inputs Entered in Catalog"); } + // Remove Certain NGraphAssigns then. + TF_RETURN_IF_ERROR(RemoveNGraphAssigns(options.graph->get())); + if (DumpRemoveNGraphAssignsGraphs()) { + DumpGraphs(options, idx, "ngraphssigns_optimized", + "Graph with NGraphAssigns Optimized/Removed"); + } + return Status::OK(); } @@ -360,6 +374,11 @@ class NGraphEncapsulationPass : public NGraphRewritePass { return DumpAllGraphs() || std::getenv("NGRAPH_TF_DUMP_CATALOGED_GRAPHS") != nullptr; } + + static bool DumpRemoveNGraphAssignsGraphs() { + return DumpAllGraphs() || + std::getenv("NGRAPH_TF_DUMP_REMOVENGASSIGNS_GRAPHS") != nullptr; + } }; } // namespace ngraph_bridge From a2f13366e29e38413cc298560f8b0fcd25c5e165 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 22 Jul 2019 17:55:55 -0700 Subject: [PATCH 07/31] changes to get var before compute --- ngraph_bridge/ngraph_encapsulate_op.cc | 27 ++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 243229a90..6c49064c8 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -683,13 +683,32 @@ class NGraphEncapsulateOp : public OpKernel { output_caches[i].second; void* current_dst_ptr = DMAHelper::base(output_tensor); - std::shared_ptr current_ng_tensor = - GetCurrentNgTensor(current_dst_ptr, last_dst_ptr, last_ng_tensor, - true, ng_exec, op_backend, ng_element_type, - ng_shape); + std::shared_ptr current_ng_tensor = nullptr; +// if the output tensor is going to be assigned to a variable +// we ask nGraph to provide the output directly in the variable tensor +#if defined(NGRAPH_TF_ENABLE_VARIABLES_AND_OPTIMIZERS) + if (NGraphCatalog::ExistsInEncapOutputInfoMap(m_graph_id, name(), i)) { + string output_key = NGraphCatalog::CreatNodeKey(m_graph_id, name(), i); + string ref_var_name = + NGraphCatalog::GetVariableSharedNameFromEncapOutputInfoMap( + output_key); + NGraphVar* var; + OP_REQUIRES_OK(ctx, ctx->resource_manager()->Lookup( + ctx->resource_manager()->default_container(), + ref_var_name, &var)); + current_ng_tensor = var->ng_tensor(); + var->Unref(); + ng_outputs.push_back(current_ng_tensor); + continue; + } +#endif + current_ng_tensor = GetCurrentNgTensor( + current_dst_ptr, last_dst_ptr, last_ng_tensor, true, ng_exec, + op_backend, ng_element_type, ng_shape); current_ng_tensor->set_stale(true); output_caches[i] = std::make_pair(current_dst_ptr, current_ng_tensor); + ng_outputs.push_back(current_ng_tensor); } From 6f7543343509b4741f69101a6212721735b12f9e Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Mon, 22 Jul 2019 19:12:01 -0700 Subject: [PATCH 08/31] Made changes to remove edges right way.Added syncing in encap --- .../ngraph_remove_ngraphassigns.cc | 7 ++++ ngraph_bridge/ngraph_encapsulate_op.cc | 42 +++++++++++++++---- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc index 6bf6fb1a5..498e07f16 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc @@ -52,6 +52,7 @@ Status RemoveNGraphAssigns(Graph* graph) { // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/graph/graph.h#L495 // Handle input edges NGRAPH_VLOG(3) << "Handling input edges "; + vector remove_edges; for (auto edge : node->in_edges()) { // attach incoming control edge to input_1, as that's where update // will happen @@ -61,6 +62,7 @@ Status RemoveNGraphAssigns(Graph* graph) { graph->AddEdge(edge->src(), edge->src_output(), input_1, edge->dst_input()); } + remove_edges.push_back(edge); } // Handle output edges @@ -84,6 +86,11 @@ Status RemoveNGraphAssigns(Graph* graph) { graph->AddEdge(input_1, Graph::kControlSlot, edge->dst(), Graph::kControlSlot); } + remove_edges.push_back(edge); + } + + for (auto edge : remove_edges) { + graph->RemoveEdge(edge); } // Add the node for removal diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 6c49064c8..2d1f52921 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -688,7 +688,7 @@ class NGraphEncapsulateOp : public OpKernel { // we ask nGraph to provide the output directly in the variable tensor #if defined(NGRAPH_TF_ENABLE_VARIABLES_AND_OPTIMIZERS) if (NGraphCatalog::ExistsInEncapOutputInfoMap(m_graph_id, name(), i)) { - string output_key = NGraphCatalog::CreatNodeKey(m_graph_id, name(), i); + string output_key = NGraphCatalog::CreateNodeKey(m_graph_id, name(), i); string ref_var_name = NGraphCatalog::GetVariableSharedNameFromEncapOutputInfoMap( output_key); @@ -828,15 +828,41 @@ class NGraphEncapsulateOp : public OpKernel { m_number_inputs = ng_inputs.size(); } for (size_t i = 0; i < output_tensor_count; ++i) { - string key = NGraphCatalog::CreateNodeKey(m_graph_id, def().name(), i); - bool ref_exists = NGraphCatalog::ExistsInEncapOutputTensorMap(key); - void* dst_ptr; + // Sync the Var Tensor if required + string output_key = + NGraphCatalog::CreateNodeKey(m_graph_id, def().name(), i); + bool ref_exists = NGraphCatalog::ExistsInEncapOutputInfoMap(output_key); std::shared_ptr dst_ng_tensor; - std::tie(dst_ptr, dst_ng_tensor) = output_caches[i]; - + void* dst_ptr; if (ref_exists) { - NGRAPH_VLOG(4) << "Adding in output tensor map " << key; - NGraphCatalog::AddToEncapOutputTensorMap(key, dst_ng_tensor); + NGRAPH_VLOG(4) << "Syncing the output var tensor " << output_key; + + // Get var + string ref_var_name = + NGraphCatalog::GetVariableSharedNameFromEncapOutputInfoMap( + output_key); + NGraphVar* var; + OP_REQUIRES_OK(ctx, ctx->resource_manager()->Lookup( + ctx->resource_manager()->default_container(), + ref_var_name, &var)); + + if (NGraphCatalog::GetCopyToTFFromEncapOutputInfoMap(output_key)) { + if (var->copy_ng_to_tf()) { + number_of_copies++; + copy_log_str << " COPY_TF "; + } + if (!NGraphCatalog::GetIsTFJustLookingFromEncapOutputInfoMap( + output_key)) { + // Some tf op might update the ng-tensor value so mark it stale + copy_log_str << " SET_SYNC "; + var->set_sync_ng_tensor(true); + } + } + dst_ng_tensor = var->ng_tensor(); + var->Unref(); + dst_ptr = output_caches[i].first; + } else { + std::tie(dst_ptr, dst_ng_tensor) = output_caches[i]; } if (m_op_backend_name != "CPU" && From aeb8514c1769a6500b3b9d55a56a82dabb6b4d08 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Tue, 23 Jul 2019 17:23:33 -0700 Subject: [PATCH 09/31] Removed Enacap Output Tensor Map --- .../enable_variable_ops/ngraph_catalog.cc | 43 ++++--------------- .../enable_variable_ops/ngraph_catalog.h | 30 ++----------- .../ngraph_enter_in_catalog.cc | 26 +---------- ngraph_bridge/ngraph_encapsulate_op.cc | 6 +-- 4 files changed, 15 insertions(+), 90 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_catalog.cc b/ngraph_bridge/enable_variable_ops/ngraph_catalog.cc index c7afb4e29..158d9cadb 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_catalog.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_catalog.cc @@ -29,13 +29,19 @@ namespace tensorflow { namespace ngraph_bridge { unordered_map NGraphCatalog::input_variable_sharedname_map_; -unordered_map> - NGraphCatalog::encap_output_tensor_map_; unordered_map> NGraphCatalog::encap_output_copy_indexes_map_; unordered_map> NGraphCatalog::encap_output_info_map_; +// Function to create the Node Key +string NGraphCatalog::CreateNodeKey(int graph_id, string node_name, int index) { + if (index == 0) { + return to_string(graph_id) + "_" + node_name; + } + return to_string(graph_id) + "_" + node_name + ":" + to_string(index); +} + // Functions for Encapsulate Output Copy Indexes Map void NGraphCatalog::AddToEncapOutputCopyIndexesMap(int graphid, string node_name, @@ -68,39 +74,6 @@ void NGraphCatalog::DeleteFromEncapOutputCopyIndexesMap(int graphid, NGraphCatalog::encap_output_copy_indexes_map_.erase(key); } -string NGraphCatalog::CreateNodeKey(int graph_id, string node_name, int index) { - if (index == 0) { - return to_string(graph_id) + "_" + node_name; - } - return to_string(graph_id) + "_" + node_name + ":" + to_string(index); -} - -// Functions for OutputTensorMap -void NGraphCatalog::AddToEncapOutputTensorMap( - string key, shared_ptr ng_val) { - NGraphCatalog::encap_output_tensor_map_[key] = ng_val; -} - -bool NGraphCatalog::ExistsInEncapOutputTensorMap(string key) { - auto itr = NGraphCatalog::encap_output_tensor_map_.find(key); - return itr != NGraphCatalog::encap_output_tensor_map_.end(); -} - -bool NGraphCatalog::ExistsInEncapOutputTensorMap(int graphid, string node_name, - int input_index) { - return NGraphCatalog::ExistsInEncapOutputTensorMap( - NGraphCatalog::CreateNodeKey(graphid, node_name, input_index)); -} - -shared_ptr -NGraphCatalog::GetTensorFromEncapOutputTensorMap(string key) { - return NGraphCatalog::encap_output_tensor_map_[key]; -} - -void NGraphCatalog::DeleteFromEncapOutputTensorMap(string key) { - NGraphCatalog::encap_output_tensor_map_.erase(key); -} - // Functions relating Input Variable Shared Name Map string NGraphCatalog::GetInputVariableSharedName(int graphid, string node_name, int input_index) { diff --git a/ngraph_bridge/enable_variable_ops/ngraph_catalog.h b/ngraph_bridge/enable_variable_ops/ngraph_catalog.h index 9b354f7c7..ce11bc530 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_catalog.h +++ b/ngraph_bridge/enable_variable_ops/ngraph_catalog.h @@ -50,19 +50,6 @@ class NGraphCatalog { // LOCK? static unordered_map input_variable_sharedname_map_; - // Map keeps track of nodes whose input is a tensor computed by NGraph - // For e.g. if the value to be assigned was computed by NGraphEncapsulate Op - // Will be used by Assign/Optimizers - // Map of - // Key - // when op index ==0 - // string : GraphId + _ + nodename - // otherwise - // string : GraphId + _ + nodename + : + output_index - // Value : shared_ptr - static unordered_map> - encap_output_tensor_map_; - // Map keeps track of output indexes of NGraphEncapsulate Op // that will be used by TF Nodes or other NGraphEncapsulate Op // Will be used by NGraphEncapsulateOP @@ -91,6 +78,9 @@ class NGraphCatalog { encap_output_info_map_; public: + // Utility to create key to query the maps + static string CreateNodeKey(int graph_id, string node_name, int index); + // Utility Functions for the data structures // Functions for EncapsulateOutputCopyIndexes Map static void AddToEncapOutputCopyIndexesMap(int graphid, string node_name, @@ -113,17 +103,6 @@ class NGraphCatalog { int input_index); static void DeleteFromInputVariableSharedNameMap(string key); - // Functions for EncapOutputTensorMap - static void AddToEncapOutputTensorMap(string key, - shared_ptr ng_val); - static bool ExistsInEncapOutputTensorMap(string key); - static bool ExistsInEncapOutputTensorMap(int graphid, string node_name, - int input_index); - - static shared_ptr GetTensorFromEncapOutputTensorMap( - string key); - static void DeleteFromEncapOutputTensorMap(string key); - // Functions for EncapOutputInfo Map static void AddToEncapOutputInfoMap(string key, tuple val); @@ -139,9 +118,6 @@ class NGraphCatalog { static void DeleteFromEncapOutputInfoMap(string key); static void ClearEncapOutputInfoMap(); static void PrintEncapOutputInfoMap(); - - // Utility to create key to query the maps - static string CreateNodeKey(int graph_id, string node_name, int index); }; } // ngraph_bridge diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc index 1a209c05c..d1db4241d 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc @@ -98,8 +98,7 @@ Status EnterInCatalog(Graph* graph, int graph_id) { NGRAPH_VLOG(4) << "Value: " << get<0>(value) << " " << get<1>(value) << " " << get<2>(value); NGraphCatalog::AddToEncapOutputInfoMap(key, value); - // TODO: Uncomment the continue when all the tasks are integrated - // continue; + continue; } } // Update the input variable map @@ -145,29 +144,6 @@ Status EnterInCatalog(Graph* graph, int graph_id) { op_index_to_copy); } // end of node is type NGraphEncapsulate - - // Update the output tensor map - if (IsNGVariableType(node->type_string())) { - for (auto edge : node->in_edges()) { - if (!edge->src()->IsOp() || edge->IsControlEdge() || - IsRefType(edge->dst()->input_type(edge->dst_input())) || - edge->src()->type_string() != "NGraphEncapsulate") { - continue; - } - - NGRAPH_VLOG(4) << "Get " << node->type_string() - << " and input is from NGraphEncapsulate"; - - auto src = edge->src(); - int src_output = edge->src_output(); - string node_key = - NGraphCatalog::CreateNodeKey(graph_id, src->name(), src_output); - // Will be updated with real tensors in Encapsulate - NGraphCatalog::AddToEncapOutputTensorMap(node_key, nullptr); - NGRAPH_VLOG(4) << "Adding in Output Tensor Map"; - NGRAPH_VLOG(4) << "Key: " << node_key; - } - } // end of if node of type NGraphAssign } // enter in catalog NGRAPH_VLOG(4) << "Entered in Catalog"; diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 2d1f52921..5a5236358 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -218,9 +218,9 @@ class NGraphEncapsulateOp : public OpKernel { // Remove entries related to outputs for (int i = 0; i < m_number_outputs; i++) { string key = NGraphCatalog::CreateNodeKey(m_graph_id, name(), i); - if (NGraphCatalog::ExistsInEncapOutputTensorMap(key)) { - NGraphCatalog::DeleteFromEncapOutputTensorMap(key); - NGRAPH_VLOG(2) << "Deleting from output tensor map " << key; + if (NGraphCatalog::ExistsInEncapOutputInfoMap(key)) { + NGraphCatalog::DeleteFromEncapOutputInfoMap(key); + NGRAPH_VLOG(2) << "Deleting from output info map " << key; } } From 90591541c98e12d0d141ff3d9aa0009f0929b402 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Tue, 23 Jul 2019 17:29:48 -0700 Subject: [PATCH 10/31] Updated Comments --- .../enable_variable_ops/ngraph_enter_in_catalog.h | 12 ++++++------ .../ngraph_remove_ngraphassigns.cc | 5 ----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h index 5ddf7f4be..26eeb4e61 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h @@ -50,12 +50,12 @@ namespace ngraph_bridge { // We add mapping of {graphId_nodename_InputIndex : Shared_Name} to the // InputVariableSharedNameMap // -// TODO: Update the comments for EnacapOutputInfoMap -// 2. If the output of NGraphEncapsulate Op is an input to NGraphVariableType -// Op, we store this NG-Tensor -// so that it can be directly accessed in compute call of NGraphVariableType. -// We add mapping of {graphId_encapnodename_OutputIndex : NG-Tensor} to the -// EncapOutputTensorMap +// 2. If the input to NGraphAssign Op is from NGraphEncapsulate Op +// We add mapping of +// {graphId_encapnodename_OutputIndex : tuple:{Variable_Shared_Name, CopyToTF, +// IsTFJustLooking}} +// to the EncapOutputInfoMap +// We attach "_ngraph_remove" attribute to the NGraphAssign node // // 3. If the output of NGraphEncapsulate Op is not required by a TF Op or // NGraphEncapsulate Op, diff --git a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc index 498e07f16..f18804978 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc @@ -45,11 +45,6 @@ Status RemoveNGraphAssigns(Graph* graph) { input_1->type_string()); } - // Handle input and output edges - // Only adding the new edges, edges to and from the current node will be - // removed when - // node is removed - // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/graph/graph.h#L495 // Handle input edges NGRAPH_VLOG(3) << "Handling input edges "; vector remove_edges; From 48bf3fe6aecd11e31b502b3536d76c940cdb4096 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Tue, 23 Jul 2019 17:29:48 -0700 Subject: [PATCH 11/31] Updated Comments --- .../enable_variable_ops/ngraph_enter_in_catalog.cc | 3 +++ .../enable_variable_ops/ngraph_enter_in_catalog.h | 12 ++++++------ .../ngraph_remove_ngraphassigns.cc | 5 ----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc index d1db4241d..1145f4cac 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc @@ -98,9 +98,12 @@ Status EnterInCatalog(Graph* graph, int graph_id) { NGRAPH_VLOG(4) << "Value: " << get<0>(value) << " " << get<1>(value) << " " << get<2>(value); NGraphCatalog::AddToEncapOutputInfoMap(key, value); + // This NGraphAssign will be removed subsequently + // so we dont need to fill the rest of the catalog continue; } } + // Update the input variable map if (IsNGVariableType(node->type_string())) { string node_key = NGraphCatalog::CreateNodeKey(graph_id, node->name(), 0); diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h index 5ddf7f4be..26eeb4e61 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h @@ -50,12 +50,12 @@ namespace ngraph_bridge { // We add mapping of {graphId_nodename_InputIndex : Shared_Name} to the // InputVariableSharedNameMap // -// TODO: Update the comments for EnacapOutputInfoMap -// 2. If the output of NGraphEncapsulate Op is an input to NGraphVariableType -// Op, we store this NG-Tensor -// so that it can be directly accessed in compute call of NGraphVariableType. -// We add mapping of {graphId_encapnodename_OutputIndex : NG-Tensor} to the -// EncapOutputTensorMap +// 2. If the input to NGraphAssign Op is from NGraphEncapsulate Op +// We add mapping of +// {graphId_encapnodename_OutputIndex : tuple:{Variable_Shared_Name, CopyToTF, +// IsTFJustLooking}} +// to the EncapOutputInfoMap +// We attach "_ngraph_remove" attribute to the NGraphAssign node // // 3. If the output of NGraphEncapsulate Op is not required by a TF Op or // NGraphEncapsulate Op, diff --git a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc index 498e07f16..f18804978 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc @@ -45,11 +45,6 @@ Status RemoveNGraphAssigns(Graph* graph) { input_1->type_string()); } - // Handle input and output edges - // Only adding the new edges, edges to and from the current node will be - // removed when - // node is removed - // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/graph/graph.h#L495 // Handle input edges NGRAPH_VLOG(3) << "Handling input edges "; vector remove_edges; From 4b1a475fc7fb76963168179302a914718f9f2457 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 14:08:53 -0700 Subject: [PATCH 12/31] Integrate with output cache --- ngraph_bridge/ngraph_encapsulate_op.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 5a5236358..438605654 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -697,6 +697,16 @@ class NGraphEncapsulateOp : public OpKernel { ctx->resource_manager()->default_container(), ref_var_name, &var)); current_ng_tensor = var->ng_tensor(); + + // There might be scenarios where the input and output tensors are the + // same. + // The staleness determined for the input tensor should be the final + // staleness + // for the given tensor. The staleness of output tensor should not + // matter + // as this tensor is meant to be overwritten with the computed value + // So not setting staleness here . + output_caches[i] = std::make_pair(current_dst_ptr, current_ng_tensor); var->Unref(); ng_outputs.push_back(current_ng_tensor); continue; @@ -832,8 +842,7 @@ class NGraphEncapsulateOp : public OpKernel { string output_key = NGraphCatalog::CreateNodeKey(m_graph_id, def().name(), i); bool ref_exists = NGraphCatalog::ExistsInEncapOutputInfoMap(output_key); - std::shared_ptr dst_ng_tensor; - void* dst_ptr; + if (ref_exists) { NGRAPH_VLOG(4) << "Syncing the output var tensor " << output_key; @@ -858,13 +867,13 @@ class NGraphEncapsulateOp : public OpKernel { var->set_sync_ng_tensor(true); } } - dst_ng_tensor = var->ng_tensor(); var->Unref(); - dst_ptr = output_caches[i].first; - } else { - std::tie(dst_ptr, dst_ng_tensor) = output_caches[i]; } + std::shared_ptr dst_ng_tensor; + void* dst_ptr; + std::tie(dst_ptr, dst_ng_tensor) = output_caches[i]; + if (m_op_backend_name != "CPU" && NGraphCatalog::EncapOutputIndexNeedsCopy(m_graph_id, def().name(), i)) { From 6e49e07078136c23b2165f47150db5ef9ac11c35 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 14:13:35 -0700 Subject: [PATCH 13/31] Update ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h --- ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h index 26eeb4e61..1857446f1 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.h @@ -55,7 +55,7 @@ namespace ngraph_bridge { // {graphId_encapnodename_OutputIndex : tuple:{Variable_Shared_Name, CopyToTF, // IsTFJustLooking}} // to the EncapOutputInfoMap -// We attach "_ngraph_remove" attribute to the NGraphAssign node +// We attach "_ngraph_remove" attribute to this NGraphAssign node // // 3. If the output of NGraphEncapsulate Op is not required by a TF Op or // NGraphEncapsulate Op, From c80ade72a872a7ac536bf07cb85d20e70e5accdf Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 14:21:52 -0700 Subject: [PATCH 14/31] Minor --- ngraph_bridge/ngraph_encapsulate_op.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 438605654..ac4816910 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -699,13 +699,13 @@ class NGraphEncapsulateOp : public OpKernel { current_ng_tensor = var->ng_tensor(); // There might be scenarios where the input and output tensors are the - // same. - // The staleness determined for the input tensor should be the final - // staleness - // for the given tensor. The staleness of output tensor should not - // matter - // as this tensor is meant to be overwritten with the computed value - // So not setting staleness here . + // same.The staleness determined for the input tensor should be the + // final + // staleness for the given tensor. The staleness of output tensor should + // not + // matter as this tensor is meant to be overwritten with the computed + // value. + // So not setting staleness here. output_caches[i] = std::make_pair(current_dst_ptr, current_ng_tensor); var->Unref(); ng_outputs.push_back(current_ng_tensor); @@ -833,7 +833,7 @@ class NGraphEncapsulateOp : public OpKernel { #if defined(NGRAPH_TF_ENABLE_VARIABLES_AND_OPTIMIZERS) if (m_number_outputs == -1) { NGRAPH_VLOG(4) << "Settig number of outputs for " << def().name(); - m_number_outputs = output_caches.size(); + m_number_outputs = ng_outputs.size(); NGRAPH_VLOG(4) << "Settig number of inputs for " << def().name(); m_number_inputs = ng_inputs.size(); } @@ -1063,4 +1063,4 @@ int NGraphEncapsulateOp::s_instance_count = 0; REGISTER_KERNEL_BUILDER(Name("NGraphEncapsulate").Device(DEVICE_CPU), ngraph_bridge::NGraphEncapsulateOp); -} // namespace tensorflow \ No newline at end of file +} // namespace tensorflow \ No newline at end of file From d4b647c7e779f925dfa3269d2841f565a63dcf43 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 14:24:46 -0700 Subject: [PATCH 15/31] minor --- ngraph_bridge/ngraph_encapsulate_op.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index ac4816910..b68e89bed 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -1063,4 +1063,4 @@ int NGraphEncapsulateOp::s_instance_count = 0; REGISTER_KERNEL_BUILDER(Name("NGraphEncapsulate").Device(DEVICE_CPU), ngraph_bridge::NGraphEncapsulateOp); -} // namespace tensorflow \ No newline at end of file +} // namespace tensorflow \ No newline at end of file From 19d1839f1e6e0b88dce95f6922a6bc19b80e0da1 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 15:29:28 -0700 Subject: [PATCH 16/31] Formatted for formatting --- ngraph_bridge/ngraph_encapsulate_op.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index b68e89bed..2d63d6d18 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -700,11 +700,9 @@ class NGraphEncapsulateOp : public OpKernel { // There might be scenarios where the input and output tensors are the // same.The staleness determined for the input tensor should be the - // final - // staleness for the given tensor. The staleness of output tensor should - // not - // matter as this tensor is meant to be overwritten with the computed - // value. + // final staleness for the given tensor. The staleness of output + // tensor should not matter as this tensor is meant to be + // overwritten with the computed value. // So not setting staleness here. output_caches[i] = std::make_pair(current_dst_ptr, current_ng_tensor); var->Unref(); From b44cee05cc18f45994931cdc40917a95c46aca64 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 24 Jul 2019 16:47:57 -0700 Subject: [PATCH 17/31] Update ngraph_bridge/ngraph_encapsulate_op.cc Co-Authored-By: kanvi-nervana --- ngraph_bridge/ngraph_encapsulate_op.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 2d63d6d18..ad801acae 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -832,7 +832,7 @@ class NGraphEncapsulateOp : public OpKernel { if (m_number_outputs == -1) { NGRAPH_VLOG(4) << "Settig number of outputs for " << def().name(); m_number_outputs = ng_outputs.size(); - NGRAPH_VLOG(4) << "Settig number of inputs for " << def().name(); + NGRAPH_VLOG(4) << "Setting number of inputs for " << def().name(); m_number_inputs = ng_inputs.size(); } for (size_t i = 0; i < output_tensor_count; ++i) { @@ -1061,4 +1061,4 @@ int NGraphEncapsulateOp::s_instance_count = 0; REGISTER_KERNEL_BUILDER(Name("NGraphEncapsulate").Device(DEVICE_CPU), ngraph_bridge::NGraphEncapsulateOp); -} // namespace tensorflow \ No newline at end of file +} // namespace tensorflow From 3fa1df0bb8e945cd06c8a27a44913b1cd01b4b06 Mon Sep 17 00:00:00 2001 From: kanvi-nervana Date: Wed, 24 Jul 2019 18:37:59 -0700 Subject: [PATCH 18/31] Kanvi/remove additional attr check (#150) Grappler to use rewriter config only. backend manager and env variable based backend setting is going to be deprecated for grappler. ngraph_backend & device_id are 2 mandatory fields, other extra params are optional. update_config has been modified to accept these new params --- ngraph_bridge/CMakeLists.txt | 1 - .../enable_variable_ops/ops/ngraph_ops.cc | 1 + ngraph_bridge/grappler/ngraph_optimizer.cc | 42 ++---- ngraph_bridge/grappler/ngraph_optimizer.h | 1 + ngraph_bridge/ngraph_backend_config.cc | 141 ------------------ ngraph_bridge/ngraph_backend_config.h | 68 --------- ngraph_bridge/ngraph_backend_manager.cc | 67 +++------ ngraph_bridge/ngraph_backend_manager.h | 21 +-- ngraph_bridge/ngraph_encapsulate_op.cc | 35 +++-- ngraph_bridge/ops/ngraph_ops.cc | 1 + python/ngraph_bridge/__init__.in.py | 22 +-- test/ci/buildkite/test_runner.py | 1 + test/graph_rewrites/backend_manager_test.cc | 72 ++------- .../config_for_grappler_test.cc | 109 ++++++++++---- .../encapsulate_clusters_test.cc | 4 +- test/graph_rewrites/enter_in_catalog_test.cc | 16 +- test/graph_rewrites/remove_ngraphassigns.cc | 20 ++- test/grappler/benchmark_cnn.patch | 18 ++- test/python/flib_graph_1.pbtxt | 2 +- test/python/flib_graph_2.pbtxt | 2 +- .../tf_unittest_ngraph_with_grappler.patch | 22 +-- test/python/tensorflow/tf_unittest_runner.py | 2 +- test/python/test_updateconfig.py | 48 ++++++ tools/test_utils.py | 4 + 24 files changed, 275 insertions(+), 445 deletions(-) delete mode 100644 ngraph_bridge/ngraph_backend_config.cc delete mode 100644 ngraph_bridge/ngraph_backend_config.h create mode 100644 test/python/test_updateconfig.py diff --git a/ngraph_bridge/CMakeLists.txt b/ngraph_bridge/CMakeLists.txt index fe41b4a85..8596efec9 100644 --- a/ngraph_bridge/CMakeLists.txt +++ b/ngraph_bridge/CMakeLists.txt @@ -35,7 +35,6 @@ set(SRC ngraph_assign_clusters.cc ngraph_builder.cc ngraph_backend_manager.cc - ngraph_backend_config.cc ngraph_capture_variables.cc ngraph_cluster_manager.cc ngraph_deassign_clusters.cc diff --git a/ngraph_bridge/enable_variable_ops/ops/ngraph_ops.cc b/ngraph_bridge/enable_variable_ops/ops/ngraph_ops.cc index d3cb26e98..b4dafe6e0 100644 --- a/ngraph_bridge/enable_variable_ops/ops/ngraph_ops.cc +++ b/ngraph_bridge/enable_variable_ops/ops/ngraph_ops.cc @@ -81,6 +81,7 @@ REGISTER_OP("NGraphEncapsulate") .Attr("ngraph_cluster: int") .Attr("ngraph_graph_id: int") .Attr("ngraph_backend: string") + .Attr("ngraph_device_id: string") .SetIsStateful() .Doc("nGraph Encapsulation Op. For use by the nGraph JIT only."); diff --git a/ngraph_bridge/grappler/ngraph_optimizer.cc b/ngraph_bridge/grappler/ngraph_optimizer.cc index c24802467..1ed6f6033 100644 --- a/ngraph_bridge/grappler/ngraph_optimizer.cc +++ b/ngraph_bridge/grappler/ngraph_optimizer.cc @@ -43,22 +43,22 @@ namespace ngraph_bridge { Status NgraphOptimizer::Init( const tensorflow::RewriterConfig_CustomGraphOptimizer* config) { const auto params = config->parameter_map(); - if (params.count("ngraph_backend")) { - config_backend_name = params.at("ngraph_backend").s(); - NGRAPH_VLOG(3) << config_backend_name; - std::vector additional_attributes = - BackendManager::GetBackendAdditionalAttributes(config_backend_name); - for (size_t i = 0; i < additional_attributes.size(); i++) { - if (params.count(additional_attributes[i])) { - config_map["_ngraph_" + additional_attributes[i]] = - params.at(additional_attributes[i]).s(); - NGRAPH_VLOG(3) << additional_attributes[i] << " " - << config_map["_ngraph_" + additional_attributes[i]]; - } + for (size_t i = 0; i < compulsory_attrs.size(); i++) { + if (params.count(compulsory_attrs[i]) == 0) { + NGRAPH_VLOG(0) << "NGTF_OPTIMIZER: Compulsory attribute " + << compulsory_attrs[i] << " not found."; + return errors::Internal("NGTF_OPTIMIZER: Missing compulsory attributes."); + } + } + config_backend_name = params.at("ngraph_backend").s(); + NGRAPH_VLOG(3) << "Backend name from config: " << config_backend_name; + for (auto i : params) { + if (i.first != "ngraph_backend") { + config_map[(i.first == "device_id" ? "" : "_") + std::string("ngraph_") + + i.first] = i.second.s(); + NGRAPH_VLOG(3) << "Attribute: " << i.first + << " Value: " << config_map["_ngraph_" + i.first]; } - } else { - NGRAPH_VLOG(5) - << "NGTF_OPTIMIZER: parameter_map does not have ngraph_backend"; } return Status::OK(); } @@ -194,7 +194,7 @@ Status NgraphOptimizer::Optimize(tensorflow::grappler::Cluster* cluster, } // Get backend + its configurations, to be attached to the nodes - // Precedence Order: RewriteConfig > Env Variable > BackendManager + // using RewriteConfig string backend_name; if (!config_backend_name.empty()) { if (!BackendManager::IsSupportedBackend(config_backend_name)) { @@ -203,16 +203,6 @@ Status NgraphOptimizer::Optimize(tensorflow::grappler::Cluster* cluster, } backend_name = config_backend_name; NGRAPH_VLOG(1) << "Setting backend from the RewriteConfig " << backend_name; - } else { - TF_RETURN_IF_ERROR( - BackendManager::GetCurrentlySetBackendName(&backend_name)); - // splits into {"ngraph_backend", "_ngraph_device_config"} - config_map = BackendManager::GetBackendAttributeValues( - backend_name); // SplitBackendConfig - backend_name = config_map.at("ngraph_backend"); - // config_map in EncapsulateClusters is not expected to contain - // ngraph_backend - config_map.erase("ngraph_backend"); } NGRAPH_VLOG(0) << "NGraph using backend: " << backend_name; diff --git a/ngraph_bridge/grappler/ngraph_optimizer.h b/ngraph_bridge/grappler/ngraph_optimizer.h index 780e47b2f..7495c4e99 100644 --- a/ngraph_bridge/grappler/ngraph_optimizer.h +++ b/ngraph_bridge/grappler/ngraph_optimizer.h @@ -74,6 +74,7 @@ class NgraphOptimizer : public tensorflow::grappler::CustomGraphOptimizer { private: std::string config_backend_name; std::unordered_map config_map; + std::vector compulsory_attrs = {"ngraph_backend", "device_id"}; void DumpGraphs(Graph&, int, std::string, std::string); diff --git a/ngraph_bridge/ngraph_backend_config.cc b/ngraph_bridge/ngraph_backend_config.cc deleted file mode 100644 index 9bb123a3e..000000000 --- a/ngraph_bridge/ngraph_backend_config.cc +++ /dev/null @@ -1,141 +0,0 @@ -/******************************************************************************* - * 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. - *******************************************************************************/ - -#include "ngraph_bridge/ngraph_backend_config.h" - -using namespace std; - -namespace tensorflow { - -namespace ngraph_bridge { - -BackendConfig::BackendConfig(const string& backend_name) { - NGRAPH_VLOG(3) << "BackendConfig() "; - backend_name_ = backend_name; - additional_attributes_ = {"device_config"}; -} - -string BackendConfig::Join( - const unordered_map& additional_parameters) { - // If device_config is not found throw an error - try { - additional_parameters.at("device_config"); - } catch (std::out_of_range e1) { - throw std::out_of_range("Attribute device_config not found"); - } - string backend_name = backend_name_; - if (additional_parameters.at("device_config") != "") { - backend_name = - backend_name + ":" + additional_parameters.at("device_config"); - } - return backend_name; -} - -unordered_map BackendConfig::Split( - const string& backend_config) { - unordered_map backend_parameters; - - int delimiter_index = backend_config.find(':'); - if (delimiter_index < 0) { - // ":" not found - backend_parameters["ngraph_backend"] = backend_config; - backend_parameters["_ngraph_device_config"] = ""; - } else { - backend_parameters["ngraph_backend"] = - backend_config.substr(0, delimiter_index); - backend_parameters["_ngraph_device_config"] = - backend_config.substr(delimiter_index + 1); - } - - NGRAPH_VLOG(3) << "Got Backend Name " << backend_parameters["ngraph_backend"]; - NGRAPH_VLOG(3) << "Got Device Config " - << backend_parameters["_ngraph_device_config"]; - - return backend_parameters; -} - -vector BackendConfig::GetAdditionalAttributes() { - return BackendConfig::additional_attributes_; -} - -BackendConfig::~BackendConfig() { - NGRAPH_VLOG(2) << "BackendConfig::~BackendConfig() DONE"; -}; - -// BackendNNPIConfig -// The NNPI backend is not supposed to specify the config parameters -// using the ENV variable or the script. NNPI backend is expected -// to use the RewriterConfig, hence the Split API is not implemented. -BackendNNPIConfig::BackendNNPIConfig() : BackendConfig("NNPI") { - additional_attributes_ = {"device_id", "ice_cores", "max_batch_size"}; -} - -string BackendNNPIConfig::Join( - const unordered_map& additional_parameters) { - // If device_id is not found throw an error - try { - additional_parameters.at("device_id"); - } catch (std::out_of_range e1) { - throw std::out_of_range("Attribute device_id not found"); - } - string backend_name = backend_name_; - if (additional_parameters.at("device_id") != "") { - backend_name = backend_name + ":" + additional_parameters.at("device_id"); - } - return backend_name; -} - -BackendNNPIConfig::~BackendNNPIConfig() { - NGRAPH_VLOG(3) << "BackendNNPIConfig::~BackendNNPIConfig() DONE"; -}; - -// BackendInterpreterConfig -BackendInterpreterConfig::BackendInterpreterConfig() - : BackendConfig("INTERPRETER") { - additional_attributes_ = {"test_echo"}; -} - -string BackendInterpreterConfig::Join( - const unordered_map& additional_parameters) { - NGRAPH_VLOG(3) << "BackendInterpreterConfig::Join - return the backend name"; - return backend_name_; -} - -unordered_map BackendInterpreterConfig::Split( - const string& backend_config) { - unordered_map backend_parameters; - - int delimiter_index = backend_config.find(':'); - if (delimiter_index < 0) { - // ":" not found - backend_parameters["ngraph_backend"] = backend_config; - backend_parameters["_ngraph_test_echo"] = ""; - } else { - backend_parameters["ngraph_backend"] = - backend_config.substr(0, delimiter_index); - backend_parameters["_ngraph_test_echo"] = - backend_config.substr(delimiter_index + 1); - } - return backend_parameters; -} - -BackendInterpreterConfig::~BackendInterpreterConfig() { - NGRAPH_VLOG(3) - << "BackendInterpreterConfig::~BackendInterpreterConfig() DONE"; -}; - -} // namespace ngraph_bridge -} // namespace tensorflow \ No newline at end of file diff --git a/ngraph_bridge/ngraph_backend_config.h b/ngraph_bridge/ngraph_backend_config.h deleted file mode 100644 index f8f7ff355..000000000 --- a/ngraph_bridge/ngraph_backend_config.h +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * 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. - *******************************************************************************/ - -#ifndef NGRAPH_TF_BRIDGE_BACKEND_CONFIG_H_ -#define NGRAPH_TF_BRIDGE_BACKEND_CONFIG_H_ - -#include - -#include "tensorflow/core/lib/core/errors.h" - -#include "logging/ngraph_log.h" -using namespace std; - -namespace tensorflow { - -namespace ngraph_bridge { - -class BackendConfig { - public: - BackendConfig() = delete; - BackendConfig(const string& backend_name); - vector GetAdditionalAttributes(); - - virtual unordered_map Split(const string& backend_config); - virtual string Join( - const unordered_map& additional_parameters); - virtual ~BackendConfig(); - - protected: - string backend_name_; - vector additional_attributes_; -}; - -class BackendNNPIConfig : public BackendConfig { - public: - BackendNNPIConfig(); - string Join( - const unordered_map& additional_parameters) override; - virtual ~BackendNNPIConfig(); -}; - -class BackendInterpreterConfig : public BackendConfig { - public: - BackendInterpreterConfig(); - unordered_map Split(const string& backend_config) override; - string Join( - const unordered_map& additional_parameters) override; - virtual ~BackendInterpreterConfig(); -}; - -} // namespace ngraph_bridge -} // namespace tensorflow - -#endif -// NGRAPH_TF_BRIDGE_BACKEND_CONFIG_H \ No newline at end of file diff --git a/ngraph_bridge/ngraph_backend_manager.cc b/ngraph_bridge/ngraph_backend_manager.cc index dc799ddc3..332bd0979 100644 --- a/ngraph_bridge/ngraph_backend_manager.cc +++ b/ngraph_bridge/ngraph_backend_manager.cc @@ -34,9 +34,6 @@ map BackendManager::ng_backend_map_; mutex BackendManager::ng_backend_map_mutex_; map BackendManager::ref_count_each_backend_; -unordered_map> - BackendManager::ng_backendconfig_map_; - Status BackendManager::SetBackendName(const string& backend_name) { std::lock_guard lock(BackendManager::ng_backend_name_mutex_); if (backend_name.empty() || !IsSupportedBackend(backend_name)) { @@ -171,53 +168,37 @@ Status BackendManager::GetCurrentlySetBackendName(string* backend_name) { return Status::OK(); }; -// Backend Config functions -// BackendConfig is expected to be a readonly class -// hence only locked at creation and not during later access -std::unique_ptr& BackendManager::GetBackendConfig( - const string& backend_name) { - std::lock_guard lock(BackendManager::ng_backend_map_mutex_); - auto itr = BackendManager::ng_backendconfig_map_.find(backend_name); - if (itr == BackendManager::ng_backendconfig_map_.end()) { - if (backend_name == "NNPI") { - BackendManager::ng_backendconfig_map_.insert(std::make_pair( - backend_name, - std::unique_ptr(new BackendNNPIConfig()))); - } - if (backend_name == "INTERPRETER") { - BackendManager::ng_backendconfig_map_.insert(std::make_pair( - backend_name, std::unique_ptr( - new BackendInterpreterConfig()))); - } else { - BackendManager::ng_backendconfig_map_.insert(std::make_pair( - backend_name, - std::unique_ptr(new BackendConfig(backend_name)))); - } - } - return BackendManager::ng_backendconfig_map_.at(backend_name); -} - -vector BackendManager::GetBackendAdditionalAttributes( - const string& backend_name) { - return BackendManager::GetBackendConfig(backend_name) - ->GetAdditionalAttributes(); -} - +// Split unordered_map BackendManager::GetBackendAttributeValues( const string& backend_config) { unordered_map backend_parameters; - string backend_name = backend_config.substr(0, backend_config.find(':')); - NGRAPH_VLOG(3) << "Got Backend Name " << backend_name; + int delimiter_index = backend_config.find(':'); + if (delimiter_index < 0) { + // ":" not found + backend_parameters["ngraph_backend"] = backend_config; + backend_parameters["ngraph_device_id"] = ""; + } else { + backend_parameters["ngraph_backend"] = + backend_config.substr(0, delimiter_index); + backend_parameters["ngraph_device_id"] = + backend_config.substr(delimiter_index + 1); + } + + NGRAPH_VLOG(3) << "Got Backend Name " << backend_parameters["ngraph_backend"]; + NGRAPH_VLOG(3) << "Got Device Id " << backend_parameters["ngraph_device_id"]; - return BackendManager::GetBackendConfig(backend_name)->Split(backend_config); + return backend_parameters; } -string BackendManager::GetBackendCreationString( - const string& backend_name, - const unordered_map& additional_attribute_map) { - return BackendManager::GetBackendConfig(backend_name) - ->Join(additional_attribute_map); +// Join +string BackendManager::GetBackendCreationString(const string& backend_name, + const string& device_id) { + if (device_id != "") { + return backend_name + ":" + device_id; + } else { + return backend_name; + } } } // namespace ngraph_bridge diff --git a/ngraph_bridge/ngraph_backend_manager.h b/ngraph_bridge/ngraph_backend_manager.h index 5c227b9bf..a0b1141da 100644 --- a/ngraph_bridge/ngraph_backend_manager.h +++ b/ngraph_bridge/ngraph_backend_manager.h @@ -31,7 +31,6 @@ #include "ngraph/runtime/backend_manager.hpp" #include "logging/ngraph_log.h" -#include "ngraph_bridge/ngraph_backend_config.h" using namespace std; namespace ng = ngraph; @@ -116,15 +115,10 @@ class BackendManager { GetBackendAttributeValues( // SplitBackendConfig const string& backend_config); - // Given a backend name and list of attributes + // Given a backend name and device id // joins them into a string to create ngraph backend - // For e.g. - // 1. GetBackendCreationString("GPU", {"_ngraph_device_config", "2"}) - // returns "GPU:2" - // throws an error if the required attributes are not present in the map - static string GetBackendCreationString( - const string& backend_name, - const unordered_map& additional_attribute_map); + static string GetBackendCreationString(const string& backend_name, + const string& device_id); ~BackendManager(); @@ -136,17 +130,8 @@ class BackendManager { static map ng_backend_map_; static mutex ng_backend_map_mutex_; - // map of cached backend config objects - static unordered_map> - ng_backendconfig_map_; - static mutex ng_backendconfig_map_mutex_; - // Map of backends and their reference counts static std::map ref_count_each_backend_; - - // utility functions - static std::unique_ptr& GetBackendConfig( - const string& backend_name); }; } // namespace ngraph_bridge diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 6421b7d95..735625299 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -20,6 +20,7 @@ #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/attr_value.pb.h" #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/framework/node_def_util.h" #include "tensorflow/core/framework/op.h" @@ -159,25 +160,31 @@ class NGraphEncapsulateOp : public OpKernel { // Set the backend type for the op std::string backend_name; OP_REQUIRES_OK(ctx, ctx->GetAttr("ngraph_backend", &backend_name)); + std::string device_id; + OP_REQUIRES_OK(ctx, ctx->GetAttr("ngraph_device_id", &device_id)); // Get the optional attributes - std::vector additional_attributes = - BackendManager::GetBackendAdditionalAttributes(backend_name); std::unordered_map additional_attribute_map; - for (size_t i = 0; i < additional_attributes.size(); i++) { - std::string val; - // Append _ngraph_ to the additional attributes since they - // are added as optional attributes with a `ngraph` prefix - // to the encapsulate node - std::string attr = "_ngraph_" + additional_attributes[i]; - // If an attribute does not exist, TF will return a non-ok status - OP_REQUIRES_OK(ctx, ctx->GetAttr(attr, &val)); - additional_attribute_map.insert({additional_attributes[i], val}); + auto node_def = ctx->def(); + auto additional_attributes = node_def.attr(); + for (auto itx : additional_attributes) { + // Find the optional attributes to be sent to the backend. + // The optional attributes have '_ngraph_' appended to the start + // so we need to get rid of that and only send the remaining string + // since the backend will only look for that. + // '_ngraph_' is only appended for the bridge. + // For e.g. _ngraph_ice_cores --> ice_cores + if (itx.first.find("_ngraph_") != std::string::npos) { + NGRAPH_VLOG(4) << "Attribute: " << itx.first.substr(strlen("_ngraph_")) + << " Value: " << itx.second.s(); + additional_attribute_map.insert( + {itx.first.substr(strlen("_ngraph_")), itx.second.s()}); + } } - // Concatenate the backend_name:backend_config + // Concatenate the backend_name:device_id try { - m_op_backend_name = BackendManager::GetBackendCreationString( - backend_name, additional_attribute_map); + m_op_backend_name = + BackendManager::GetBackendCreationString(backend_name, device_id); } catch (const std::exception& exp) { Status status = errors::Internal( "Caught exception while creating backend string ", exp.what(), "\n"); diff --git a/ngraph_bridge/ops/ngraph_ops.cc b/ngraph_bridge/ops/ngraph_ops.cc index f7372a319..ff91415b4 100644 --- a/ngraph_bridge/ops/ngraph_ops.cc +++ b/ngraph_bridge/ops/ngraph_ops.cc @@ -29,6 +29,7 @@ REGISTER_OP("NGraphEncapsulate") .Attr("ngraph_cluster: int") .Attr("ngraph_graph_id: int") .Attr("ngraph_backend: string") + .Attr("ngraph_device_id: string") .SetIsStateful() .Doc("nGraph Encapsulation Op. For use by the nGraph JIT only."); diff --git a/python/ngraph_bridge/__init__.in.py b/python/ngraph_bridge/__init__.in.py index 307e94671..405bf9606 100644 --- a/python/ngraph_bridge/__init__.in.py +++ b/python/ngraph_bridge/__init__.in.py @@ -199,17 +199,17 @@ def cxx11_abi_flag(): def is_grappler_enabled(): return ngraph_bridge_lib.ngraph_tf_is_grappler_enabled() -def update_config(config): +def update_config(config, backend_name = "CPU", device_id = ""): #updating session config if grappler is enabled if(ngraph_bridge_lib.ngraph_tf_is_grappler_enabled()): - rewrite_options = rewriter_config_pb2.RewriterConfig( - meta_optimizer_iterations=rewriter_config_pb2.RewriterConfig.ONE, - min_graph_nodes=-1, - custom_optimizers=[ - rewriter_config_pb2.RewriterConfig.CustomGraphOptimizer( - name="ngraph-optimizer") - ]) - config.MergeFrom(tf.ConfigProto(graph_options=tf.GraphOptions(rewrite_options=rewrite_options))) + rewriter_options = rewriter_config_pb2.RewriterConfig() + rewriter_options.meta_optimizer_iterations=(rewriter_config_pb2.RewriterConfig.ONE) + rewriter_options.min_graph_nodes=-1 + ngraph_optimizer = rewriter_options.custom_optimizers.add() + ngraph_optimizer.name = "ngraph-optimizer" + ngraph_optimizer.parameter_map["ngraph_backend"].s = backend_name.encode() + ngraph_optimizer.parameter_map["device_id"].s = device_id.encode() + config.MergeFrom(tf.ConfigProto(graph_options=tf.GraphOptions(rewrite_options=rewriter_options))) # For reference, if we want to provide configuration support(backend parameters) # in a python script using the ngraph-optimizer # rewriter_options = rewriter_config_pb2.RewriterConfig() @@ -217,8 +217,8 @@ def update_config(config): # rewriter_options.min_graph_nodes=-1 # ngraph_optimizer = rewriter_options.custom_optimizers.add() # ngraph_optimizer.name = "ngraph-optimizer" - # ngraph_optimizer.parameter_map["ngraph_backend"].s = b'NNPI' - # ngraph_optimizer.parameter_map["device_id"].s = b'1' + # ngraph_optimizer.parameter_map["ngraph_backend"].s = backend_name.encode() + # ngraph_optimizer.parameter_map["device_id"].s = device_id.encode() # ngraph_optimizer.parameter_map["max_batch_size"].s = b'64' # ngraph_optimizer.parameter_map["ice_cores"].s = b'12' # config.MergeFrom(tf.ConfigProto(graph_options=tf.GraphOptions(rewrite_options=rewriter_options))) diff --git a/test/ci/buildkite/test_runner.py b/test/ci/buildkite/test_runner.py index d4276c5de..d0612e392 100755 --- a/test/ci/buildkite/test_runner.py +++ b/test/ci/buildkite/test_runner.py @@ -86,6 +86,7 @@ def main(): raise Exception("Need to specify --artifacts_dir") # Set the backend if specified + # NOTE: This way of backend setting will not work with grappler if (arguments.backend): os.environ['NGRAPH_TF_BACKEND'] = arguments.backend diff --git a/test/graph_rewrites/backend_manager_test.cc b/test/graph_rewrites/backend_manager_test.cc index b59df6de7..52d5a6d02 100644 --- a/test/graph_rewrites/backend_manager_test.cc +++ b/test/graph_rewrites/backend_manager_test.cc @@ -194,21 +194,6 @@ TEST(BackendManager, BackendClustering) { ASSERT_NE(A_cluster, B_cluster); } -// Test GetBackendAdditionalAttributes API -TEST(BackendManager, GetBackendAdditionalAttributes) { - vector default_backend_optional_attrs = {"device_config"}; - vector nnpi_backend_optional_attrs = {"device_id", "ice_cores", - "max_batch_size"}; - - auto cpu_options = BackendManager::GetBackendAdditionalAttributes("CPU"); - auto nnpi_options = BackendManager::GetBackendAdditionalAttributes("NNPI"); - auto gpu_options = BackendManager::GetBackendAdditionalAttributes("GPU"); - - ASSERT_EQ(cpu_options, default_backend_optional_attrs); - ASSERT_EQ(nnpi_options, nnpi_backend_optional_attrs); - ASSERT_EQ(gpu_options, default_backend_optional_attrs); -} - // Test GetBackendAttributeValues API TEST(BackendManager, GetBackendAttributeValues) { auto cpu_options = BackendManager::GetBackendAttributeValues("CPU"); @@ -218,67 +203,42 @@ TEST(BackendManager, GetBackendAttributeValues) { BackendManager::GetBackendAttributeValues("PLAIDML:device:567:892_34"); ASSERT_NE(cpu_options.find("ngraph_backend"), cpu_options.end()); - ASSERT_NE(cpu_options.find("_ngraph_device_config"), cpu_options.end()); + ASSERT_NE(cpu_options.find("ngraph_device_id"), cpu_options.end()); ASSERT_EQ(cpu_options["ngraph_backend"], "CPU"); - ASSERT_EQ(cpu_options["_ngraph_device_config"], ""); + ASSERT_EQ(cpu_options["ngraph_device_id"], ""); ASSERT_NE(nnpi_options.find("ngraph_backend"), nnpi_options.end()); - ASSERT_NE(nnpi_options.find("_ngraph_device_config"), nnpi_options.end()); + ASSERT_NE(nnpi_options.find("ngraph_device_id"), nnpi_options.end()); ASSERT_EQ(nnpi_options["ngraph_backend"], "NNPI"); - ASSERT_EQ(nnpi_options["_ngraph_device_config"], "3,5,6"); + ASSERT_EQ(nnpi_options["ngraph_device_id"], "3,5,6"); ASSERT_NE(gpu_options.find("ngraph_backend"), gpu_options.end()); - ASSERT_NE(gpu_options.find("_ngraph_device_config"), gpu_options.end()); + ASSERT_NE(gpu_options.find("ngraph_device_id"), gpu_options.end()); ASSERT_EQ(gpu_options["ngraph_backend"], "GPU"); - ASSERT_EQ(gpu_options["_ngraph_device_config"], "5"); + ASSERT_EQ(gpu_options["ngraph_device_id"], "5"); ASSERT_NE(plaidml_options.find("ngraph_backend"), plaidml_options.end()); - ASSERT_NE(plaidml_options.find("_ngraph_device_config"), - plaidml_options.end()); + ASSERT_NE(plaidml_options.find("ngraph_device_id"), plaidml_options.end()); ASSERT_EQ(plaidml_options["ngraph_backend"], "PLAIDML"); - ASSERT_EQ(plaidml_options["_ngraph_device_config"], "device:567:892_34"); + ASSERT_EQ(plaidml_options["ngraph_device_id"], "device:567:892_34"); } // Test GetBackendCreationString API TEST(BackendManager, GetBackendCreationString) { - unordered_map cpu_map = {{"device_config", ""}}; - unordered_map nnpi_map = {{"device_id", "5"}}; - unordered_map gpu_map = {{"device_config", "678"}}; + string cpu_device_id = ""; + string nnpi_device_id = "5"; + string gpu_device_id = "678"; - auto cpu_backend = BackendManager::GetBackendCreationString("CPU", cpu_map); + auto cpu_backend = + BackendManager::GetBackendCreationString("CPU", cpu_device_id); auto nnpi_backend = - BackendManager::GetBackendCreationString("NNPI", nnpi_map); - auto gpu_backend = BackendManager::GetBackendCreationString("GPU", gpu_map); + BackendManager::GetBackendCreationString("NNPI", nnpi_device_id); + auto gpu_backend = + BackendManager::GetBackendCreationString("GPU", gpu_device_id); ASSERT_EQ(cpu_backend, "CPU"); ASSERT_EQ(nnpi_backend, "NNPI:5"); ASSERT_EQ(gpu_backend, "GPU:678"); - - // throw errors - unordered_map test_empty_map = {}; - // "device_config" is not valid for NNPI - unordered_map test_missing_config_nnpi = { - {"device_config", "345"}}; - // "device_id" is not valid for default configs - unordered_map test_missing_config_default = { - {"device_id", "45"}}; - - ASSERT_THROW(BackendManager::GetBackendCreationString("CPU", test_empty_map), - std::out_of_range); - ASSERT_THROW(BackendManager::GetBackendCreationString("NNPI", test_empty_map), - std::out_of_range); - ASSERT_THROW(BackendManager::GetBackendCreationString("GPU", test_empty_map), - std::out_of_range); - - ASSERT_THROW(BackendManager::GetBackendCreationString( - "CPU", test_missing_config_default), - std::out_of_range); - ASSERT_THROW(BackendManager::GetBackendCreationString( - "NNPI", test_missing_config_nnpi), - std::out_of_range); - ASSERT_THROW(BackendManager::GetBackendCreationString( - "GPU", test_missing_config_default), - std::out_of_range); } } // namespace testing diff --git a/test/graph_rewrites/config_for_grappler_test.cc b/test/graph_rewrites/config_for_grappler_test.cc index ea180444a..4207b7b22 100644 --- a/test/graph_rewrites/config_for_grappler_test.cc +++ b/test/graph_rewrites/config_for_grappler_test.cc @@ -26,14 +26,12 @@ #include "tensorflow/core/protobuf/config.pb.h" #include "tensorflow/core/public/session.h" +#include "logging/tf_graph_writer.h" #include "ngraph_bridge/ngraph_assign_clusters.h" -#include "ngraph_bridge/ngraph_backend_config.h" #include "ngraph_bridge/ngraph_backend_manager.h" #include "ngraph_bridge/ngraph_mark_for_clustering.h" #include "test/test_utilities.h" -#include "logging/tf_graph_writer.h" - using namespace std; namespace ng = ngraph; @@ -44,6 +42,7 @@ namespace ngraph_bridge { namespace testing { #define ASSERT_OK(x) ASSERT_EQ((x), ::tensorflow::Status::OK()); +#define ASSERT_NOT_OK(x) ASSERT_NE((x), ::tensorflow::Status::OK()); // This test can only be run when nGraph-bridge is built with grappler // When running with other modes, grappler's ngraph-optimizer is not @@ -73,8 +72,8 @@ TEST(GrapplerConfig, RConfig1) { ConfigProto config_proto; auto backend_name = AttrValue(); backend_name.set_s("CPU"); - auto device_config = AttrValue(); - device_config.set_s("1"); + auto device_id = AttrValue(); + device_id.set_s("1"); auto& rewriter_config = *config_proto.mutable_graph_options()->mutable_rewrite_options(); rewriter_config.add_optimizers("ngraph-optimizer"); @@ -83,7 +82,7 @@ TEST(GrapplerConfig, RConfig1) { auto* custom_config = rewriter_config.add_custom_optimizers(); custom_config->set_name("ngraph-optimizer"); (*custom_config->mutable_parameter_map())["ngraph_backend"] = backend_name; - (*custom_config->mutable_parameter_map())["device_config"] = device_config; + (*custom_config->mutable_parameter_map())["device_id"] = device_id; // Run grappler tensorflow::grappler::MetaOptimizer optimizer(nullptr, config_proto); @@ -107,18 +106,18 @@ TEST(GrapplerConfig, RConfig1) { ng_encap = node; } ASSERT_NE(ng_encap, nullptr); - string ng_backend, ng_device_config; + string ng_backend, ng_device_id; ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_backend", &ng_backend)); - ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "_ngraph_device_config", - &ng_device_config)); + ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_device_id", &ng_device_id)); ASSERT_EQ(ng_backend, "CPU"); - ASSERT_EQ(ng_device_config, "1"); + ASSERT_EQ(ng_device_id, "1"); } // Though Backend is set via BackendManager -// The backend set via RewriterConfig takes precedence +// The backend set via RewriterConfig takes affect +// since that is the only way of setting backend with grappler TEST(GrapplerConfig, RConfig2) { // Create Graph Scope root = Scope::NewRootScope(); @@ -137,7 +136,8 @@ TEST(GrapplerConfig, RConfig2) { } // set backend - // Though we set the backend, the rewriter-config takes precedence + // Though we set the backend, the rewriter-config takes affect + // since that is the only way of setting backend with grappler ASSERT_OK(BackendManager::SetBackendName("INTERPRETER")); // Create GraphDef and Grappler @@ -146,8 +146,8 @@ TEST(GrapplerConfig, RConfig2) { ConfigProto config_proto; auto backend_name = AttrValue(); backend_name.set_s("CPU"); - auto device_config = AttrValue(); - device_config.set_s("1"); + auto device_id = AttrValue(); + device_id.set_s("1"); auto& rewriter_config = *config_proto.mutable_graph_options()->mutable_rewrite_options(); rewriter_config.add_optimizers("ngraph-optimizer"); @@ -156,7 +156,7 @@ TEST(GrapplerConfig, RConfig2) { auto* custom_config = rewriter_config.add_custom_optimizers(); custom_config->set_name("ngraph-optimizer"); (*custom_config->mutable_parameter_map())["ngraph_backend"] = backend_name; - (*custom_config->mutable_parameter_map())["device_config"] = device_config; + (*custom_config->mutable_parameter_map())["device_id"] = device_id; // Run grappler tensorflow::grappler::MetaOptimizer optimizer(nullptr, config_proto); @@ -180,21 +180,21 @@ TEST(GrapplerConfig, RConfig2) { ng_encap = node; } ASSERT_NE(ng_encap, nullptr); - string ng_backend, ng_device_config; + string ng_backend, ng_device_id; ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_backend", &ng_backend)); - ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "_ngraph_device_config", - &ng_device_config)); + ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_device_id", &ng_device_id)); ASSERT_EQ(ng_backend, "CPU"); - ASSERT_EQ(ng_device_config, "1"); + ASSERT_EQ(ng_device_id, "1"); // Clean up ASSERT_OK(BackendManager::SetBackendName("CPU")); } // Though Backend is set via NGRAPH_TF_BACKEND -// The backend set via RewriterConfig takes precedence +// The backend set via RewriterConfig takes affect +// since that is the only way of setting backend with grappler TEST(GrapplerConfig, RConfig3) { // If NGRAPH_TF_BACKEND is set, unset it const unordered_map& env_map = StoreEnv(); @@ -227,7 +227,7 @@ TEST(GrapplerConfig, RConfig3) { ASSERT_EQ("NOP", check_backend); // Though we set the backend and NGRAPH_TF_BACKEND - // the rewriter-config takes precedence + // the rewriter-config takes affect // Create GraphDef and Grappler grappler::GrapplerItem item; @@ -235,8 +235,8 @@ TEST(GrapplerConfig, RConfig3) { ConfigProto config_proto; auto backend_name = AttrValue(); backend_name.set_s("CPU"); - auto device_config = AttrValue(); - device_config.set_s("1"); + auto device_id = AttrValue(); + device_id.set_s("1"); auto& rewriter_config = *config_proto.mutable_graph_options()->mutable_rewrite_options(); rewriter_config.add_optimizers("ngraph-optimizer"); @@ -245,7 +245,7 @@ TEST(GrapplerConfig, RConfig3) { auto* custom_config = rewriter_config.add_custom_optimizers(); custom_config->set_name("ngraph-optimizer"); (*custom_config->mutable_parameter_map())["ngraph_backend"] = backend_name; - (*custom_config->mutable_parameter_map())["device_config"] = device_config; + (*custom_config->mutable_parameter_map())["device_id"] = device_id; // Run grappler tensorflow::grappler::MetaOptimizer optimizer(nullptr, config_proto); @@ -269,14 +269,13 @@ TEST(GrapplerConfig, RConfig3) { ng_encap = node; } ASSERT_NE(ng_encap, nullptr); - string ng_backend, ng_device_config; + string ng_backend, ng_device_id; ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_backend", &ng_backend)); - ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "_ngraph_device_config", - &ng_device_config)); + ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_device_id", &ng_device_id)); ASSERT_EQ(ng_backend, "CPU"); - ASSERT_EQ(ng_device_config, "1"); + ASSERT_EQ(ng_device_id, "1"); // Clean up ASSERT_OK(BackendManager::SetBackendName("CPU")); @@ -307,8 +306,10 @@ TEST(GrapplerConfig, RConfig4) { ConfigProto config_proto; auto backend_name = AttrValue(); backend_name.set_s("INTERPRETER"); + auto device_id = AttrValue(); + device_id.set_s("5"); auto test_echo = AttrValue(); - test_echo.set_s("5"); + test_echo.set_s("hi"); auto& rewriter_config = *config_proto.mutable_graph_options()->mutable_rewrite_options(); rewriter_config.add_optimizers("ngraph-optimizer"); @@ -317,6 +318,7 @@ TEST(GrapplerConfig, RConfig4) { auto* custom_config = rewriter_config.add_custom_optimizers(); custom_config->set_name("ngraph-optimizer"); (*custom_config->mutable_parameter_map())["ngraph_backend"] = backend_name; + (*custom_config->mutable_parameter_map())["device_id"] = device_id; (*custom_config->mutable_parameter_map())["test_echo"] = test_echo; // Run grappler @@ -340,13 +342,58 @@ TEST(GrapplerConfig, RConfig4) { ng_encap = node; } ASSERT_NE(ng_encap, nullptr); - string ng_backend, ng_test_echo; + string ng_backend, ng_test_echo, ng_device_id; ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_backend", &ng_backend)); ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "_ngraph_test_echo", &ng_test_echo)); + ASSERT_OK(GetNodeAttr(ng_encap->attrs(), "ngraph_device_id", &ng_device_id)); ASSERT_EQ(ng_backend, "INTERPRETER"); - ASSERT_EQ(ng_test_echo, "5"); + ASSERT_EQ(ng_test_echo, "hi"); + ASSERT_EQ(ng_device_id, "5"); +} + +// Test the failure case where the compulsory attribute device_id +// is not provided using the rewriter config +TEST(GrapplerConfig, RConfig5) { + // Create Graph + Scope root = Scope::NewRootScope(); + auto A = ops::Const(root.WithOpName("A"), {3.f, 2.f}); + auto B = ops::Const(root.WithOpName("B"), {3.f, 2.f}); + auto Add = ops::Add(root.WithOpName("Add"), A, B); + auto C = ops::Const(root.WithOpName("C"), {3.f, 2.f}); + auto Mul = ops::Mul(root.WithOpName("Mul"), Add, C); + + Graph graph(OpRegistry::Global()); + TF_CHECK_OK(root.ToGraph(&graph)); + + // set device specification + for (auto node : graph.op_nodes()) { + node->set_requested_device("CPU"); + } + + // Create GraphDef and Grappler + grappler::GrapplerItem item; + graph.ToGraphDef(&item.graph); + ConfigProto config_proto; + auto backend_name = AttrValue(); + backend_name.set_s("CPU"); + auto device_id = AttrValue(); + device_id.set_s("5"); + auto& rewriter_config = + *config_proto.mutable_graph_options()->mutable_rewrite_options(); + rewriter_config.add_optimizers("ngraph-optimizer"); + rewriter_config.set_min_graph_nodes(-1); + rewriter_config.set_meta_optimizer_iterations(RewriterConfig::ONE); + auto* custom_config = rewriter_config.add_custom_optimizers(); + custom_config->set_name("ngraph-optimizer"); + (*custom_config->mutable_parameter_map())["ngraph_backend"] = backend_name; + + // Run grappler + tensorflow::grappler::MetaOptimizer optimizer(nullptr, config_proto); + GraphDef output; + + ASSERT_NOT_OK(optimizer.Optimize(nullptr, item, &output)); } } // namespace testing diff --git a/test/graph_rewrites/encapsulate_clusters_test.cc b/test/graph_rewrites/encapsulate_clusters_test.cc index 8d7c24257..e94914fad 100644 --- a/test/graph_rewrites/encapsulate_clusters_test.cc +++ b/test/graph_rewrites/encapsulate_clusters_test.cc @@ -80,7 +80,9 @@ TEST(EncapsulateClusters, PopulateLibrary) { g.AddEdge(node3, Graph::kControlSlot, sink, Graph::kControlSlot); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&g, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&g, 0, fdeflib_new, config_map)); int num_encapsulates = 0; int num_tf_nodes = 0; diff --git a/test/graph_rewrites/enter_in_catalog_test.cc b/test/graph_rewrites/enter_in_catalog_test.cc index 13dd0bfdc..c31872e5d 100644 --- a/test/graph_rewrites/enter_in_catalog_test.cc +++ b/test/graph_rewrites/enter_in_catalog_test.cc @@ -76,7 +76,9 @@ TEST(CatalogTest, SmallGraph1) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); ASSERT_OK(EnterInCatalog(&graph, 0)); bool remove = false; @@ -118,7 +120,9 @@ TEST(CatalogTest, SmallGraph2) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); ASSERT_OK(EnterInCatalog(&graph, 0)); bool remove = false; @@ -187,7 +191,9 @@ TEST(CatalogTest, SmallGraph3) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); ASSERT_OK(EnterInCatalog(&graph, 0)); // check if the _ngraph_remove attribute is added/not-added as expected @@ -251,7 +257,9 @@ TEST(CatalogTest, SmallGraph4) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); ASSERT_OK(EnterInCatalog(&graph, 0)); string key; diff --git a/test/graph_rewrites/remove_ngraphassigns.cc b/test/graph_rewrites/remove_ngraphassigns.cc index 72fc0d815..b620caef6 100644 --- a/test/graph_rewrites/remove_ngraphassigns.cc +++ b/test/graph_rewrites/remove_ngraphassigns.cc @@ -70,7 +70,9 @@ TEST(RemoveNGraphAssigns, Graph1) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); // Get all the nodes in map [utility] map node_map; @@ -126,7 +128,9 @@ TEST(RemoveNGraphAssigns, Graph2) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); // clean up config::ngraph_set_disabled_ops(""); @@ -217,7 +221,9 @@ TEST(RemoveNGraphAssigns, Graph3) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); // Get all the nodes in map [utility] map node_map; @@ -314,7 +320,9 @@ TEST(RemoveNGraphAssigns, Graph4) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); // clean up config::ngraph_set_disabled_ops(""); @@ -410,7 +418,9 @@ TEST(RemoveNGraphAssigns, Graph5) { ASSERT_OK(MarkForClustering(&graph, skip_these_nodes, "CPU")); ASSERT_OK(AssignClusters(&graph)); FunctionDefLibrary* fdeflib_new = new FunctionDefLibrary(); - ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, {})); + std::unordered_map config_map; + config_map["ngraph_device_id"] = ""; + ASSERT_OK(EncapsulateClusters(&graph, 0, fdeflib_new, config_map)); // Get all the nodes in map [utility] map node_map; diff --git a/test/grappler/benchmark_cnn.patch b/test/grappler/benchmark_cnn.patch index 39f4911dd..ebe2d42cd 100644 --- a/test/grappler/benchmark_cnn.patch +++ b/test/grappler/benchmark_cnn.patch @@ -1,15 +1,17 @@ diff --git a/scripts/tf_cnn_benchmarks/benchmark_cnn.py b/scripts/tf_cnn_benchmarks/benchmark_cnn.py -index d3b81d5..fd7aad1 100644 +index d3b81d5..f3620da 100644 --- a/scripts/tf_cnn_benchmarks/benchmark_cnn.py +++ b/scripts/tf_cnn_benchmarks/benchmark_cnn.py -@@ -667,6 +667,10 @@ def create_config_proto(params): +@@ -667,9 +667,9 @@ def create_config_proto(params): config.gpu_options.visible_device_list = str(hvd.local_rank()) if params.variable_update == 'collective_all_reduce': config.gpu_options.experimental.num_dev_to_dev_copy_streams = 2 -+ rewrite_options = rewriter_config_pb2.RewriterConfig( -+ meta_optimizer_iterations=rewriter_config_pb2.RewriterConfig.ONE, -+ custom_optimizers=[rewriter_config_pb2.RewriterConfig.CustomGraphOptimizer(name="ngraph-optimizer")]) -+ config.graph_options.rewrite_options.MergeFrom(rewrite_options) - - return config +- +- return config +- ++ import ngraph_bridge ++ config_new = ngraph_bridge.update_config(config) ++ return config_new + def get_mode_from_params(params): + """Returns the mode in which this script is running. diff --git a/test/python/flib_graph_1.pbtxt b/test/python/flib_graph_1.pbtxt index 95efd5437..5662e47e2 100644 --- a/test/python/flib_graph_1.pbtxt +++ b/test/python/flib_graph_1.pbtxt @@ -103,7 +103,7 @@ node { } } attr { - key: "_ngraph_device_config" + key: "ngraph_device_id" value { s: "" } diff --git a/test/python/flib_graph_2.pbtxt b/test/python/flib_graph_2.pbtxt index 02ae0792c..8cc4f40fa 100644 --- a/test/python/flib_graph_2.pbtxt +++ b/test/python/flib_graph_2.pbtxt @@ -175,7 +175,7 @@ node { } } attr { - key: "_ngraph_device_config" + key: "ngraph_device_id" value { s: "" } diff --git a/test/python/tensorflow/tf_unittest_ngraph_with_grappler.patch b/test/python/tensorflow/tf_unittest_ngraph_with_grappler.patch index 5825bc2fb..fee35e927 100644 --- a/test/python/tensorflow/tf_unittest_ngraph_with_grappler.patch +++ b/test/python/tensorflow/tf_unittest_ngraph_with_grappler.patch @@ -1,23 +1,15 @@ diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py -index af1687c8ef..56bc84f87e 100644 +index 544190e23d..19e621478e 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py -@@ -1385,6 +1385,7 @@ class TensorFlowTestCase(googletest.TestCase): - self._threads = [] - self._tempdir = None - self._cached_session = None -+ import ngraph_bridge - - def setUp(self): - self._ClearCachedSession() -@@ -2449,6 +2450,10 @@ class TensorFlowTestCase(googletest.TestCase): +@@ -2737,7 +2737,9 @@ class TensorFlowTestCase(googletest.TestCase): rewriter_config_pb2.RewriterConfig.OFF) config.graph_options.rewrite_options.pin_to_host_optimization = ( rewriter_config_pb2.RewriterConfig.OFF) -+ rewrite_options = rewriter_config_pb2.RewriterConfig( -+ meta_optimizer_iterations=rewriter_config_pb2.RewriterConfig.ONE, -+ custom_optimizers=[rewriter_config_pb2.RewriterConfig.CustomGraphOptimizer(name="ngraph-optimizer")]) -+ config.graph_options.rewrite_options.MergeFrom(rewrite_options) - return config +- return config ++ import ngraph_bridge ++ config_new = ngraph_bridge.update_config(config) ++ return config_new return ErrorLoggingSession(graph=graph, config=prepare_config(config)) + diff --git a/test/python/tensorflow/tf_unittest_runner.py b/test/python/tensorflow/tf_unittest_runner.py index 86b221d13..b4988758e 100644 --- a/test/python/tensorflow/tf_unittest_runner.py +++ b/test/python/tensorflow/tf_unittest_runner.py @@ -43,7 +43,7 @@ def main(): required.add_argument( '--tensorflow_path', help= - "Specify the path to Tensorflow source code. Eg:/localdisk/skantama/tf-ngraph/tensorflow \n", + "Specify the path to Tensorflow source code. Eg:ngraph-bridge/build_cmake/tensorflow \n", required=True) optional.add_argument( '--list_tests', diff --git a/test/python/test_updateconfig.py b/test/python/test_updateconfig.py new file mode 100644 index 000000000..bf1a6b3f9 --- /dev/null +++ b/test/python/test_updateconfig.py @@ -0,0 +1,48 @@ +# ============================================================================== +# 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 update_config api test + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import os + +import tensorflow as tf +from tensorflow.core.protobuf import rewriter_config_pb2 + +from common import NgraphTest +import ngraph_bridge + + +class TestUpdateConfig(NgraphTest): + + @pytest.mark.skipif( + not ngraph_bridge.is_grappler_enabled(), reason='Only for Grappler') + def test_update_config(self): + config = tf.ConfigProto() + config.allow_soft_placement = True + config_new = ngraph_bridge.update_config(config) + rewriter_options = config_new.graph_options.rewrite_options + ngraph_optimizer_name = rewriter_options.custom_optimizers[0].name + assert ngraph_optimizer_name == 'ngraph-optimizer' + ngraph_optimizer = rewriter_options.custom_optimizers[0] + ngraph_optimizer.parameter_map["max_batch_size"].s = b'64' + ngraph_optimizer.parameter_map["ice_cores"].s = b'12' + assert config_new.__str__( + ) == 'allow_soft_placement: true\ngraph_options {\n rewrite_options {\n meta_optimizer_iterations: ONE\n min_graph_nodes: -1\n custom_optimizers {\n name: "ngraph-optimizer"\n parameter_map {\n key: "device_id"\n value {\n s: ""\n }\n }\n parameter_map {\n key: "ice_cores"\n value {\n s: "12"\n }\n }\n parameter_map {\n key: "max_batch_size"\n value {\n s: "64"\n }\n }\n parameter_map {\n key: "ngraph_backend"\n value {\n s: "CPU"\n }\n }\n }\n }\n}\n' diff --git a/tools/test_utils.py b/tools/test_utils.py index 220d01242..c8d4eacc4 100755 --- a/tools/test_utils.py +++ b/tools/test_utils.py @@ -294,6 +294,7 @@ def run_resnet50(build_dir): junit_script = os.path.abspath('%s/test/ci/junit-wrap.sh' % root_pwd) # Check to see if we need to patch the repo for Grappler + # benchmark_cnn.patch will only work for the CPU backend patch_file = os.path.abspath( os.path.join(ngraph_tf_src_dir, "test/grappler/benchmark_cnn.patch")) import ngraph_bridge @@ -359,6 +360,7 @@ def run_resnet50_from_artifacts(ngraph_tf_src_dir, artifact_dir, batch_size, call(['git', 'checkout', '4c7b09ad87bbfc4b1f89650bcee40b3fc5e7dfed']) # Check to see if we need to patch the repo for Grappler + # benchmark_cnn.patch will only work for the CPU backend patch_file = os.path.abspath( os.path.join(ngraph_tf_src_dir, "test/grappler/benchmark_cnn.patch")) import ngraph_bridge @@ -446,6 +448,7 @@ def run_resnet50_forward_pass(build_dir): junit_script = os.path.abspath('%s/test/ci/junit-wrap.sh' % root_pwd) # Check to see if we need to patch the repo for Grappler + # benchmark_cnn.patch will only work for the CPU backend patch_file = os.path.abspath( os.path.join(ngraph_tf_src_dir, "test/grappler/benchmark_cnn.patch")) import ngraph_bridge @@ -494,6 +497,7 @@ def run_resnet50_forward_pass_from_artifacts(ngraph_tf_src_dir, artifact_dir, call(['git', 'checkout', '4c7b09ad87bbfc4b1f89650bcee40b3fc5e7dfed']) # Check to see if we need to patch the repo for Grappler + # benchmark_cnn.patch will only work for the CPU backend patch_file = os.path.abspath( os.path.join(ngraph_tf_src_dir, "test/grappler/benchmark_cnn.patch")) import ngraph_bridge From 65348d7e9511d0ce9e8f45ab283284aeb89b0b81 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 25 Jul 2019 15:05:47 -0700 Subject: [PATCH 19/31] sarkars/destructor order (#146) Free all executables before calling ReleaseBackend --- ngraph_bridge/ngraph_encapsulate_op.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 01ae17be5..86d751283 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -245,6 +245,10 @@ class NGraphEncapsulateOp : public OpKernel { } #endif + m_ng_exec_input_cache_map.clear(); + m_ng_exec_output_cache_map.clear(); + m_ng_exec_map.clear(); + m_ng_function_map.clear(); // Release the backend NGRAPH_VLOG(2) << "~NGraphEncapsulateOp():: ReleaseBackend"; From 652cca88f6c038d475f6bfcdd8dd8740e3b09089 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 25 Jul 2019 17:50:30 -0700 Subject: [PATCH 20/31] Update bridge version number --- README.md | 2 +- ngraph_bridge/version.cc | 4 ++-- python/setup.in.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 17fc111dd..a5e63932a 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Once TensorFlow's dependencies are installed, clone the `ngraph-bridge` repo: git clone https://github.com/tensorflow/ngraph-bridge.git cd ngraph-bridge - git checkout v0.16.0-rc3 + git checkout v0.17.0-rc0 Run the following Python script to build TensorFlow, nGraph, and the bridge. Use Python 3.5: diff --git a/ngraph_bridge/version.cc b/ngraph_bridge/version.cc index 98c6cd082..b13792694 100644 --- a/ngraph_bridge/version.cc +++ b/ngraph_bridge/version.cc @@ -24,7 +24,7 @@ // nGraph-TensorFlow bridge uses semantic versioning: see http://semver.org/ #define NG_TF_MAJOR_VERSION 0 -#define NG_TF_MINOR_VERSION 16 +#define NG_TF_MINOR_VERSION 17 #define NG_TF_PATCH_VERSION 0 // The version suffix is used for pre-release version numbers @@ -32,7 +32,7 @@ // candidate such as v0.7.0-rc0 // The code in master will always have the last released version number // with a suffix of '-master' -#define NG_TF_VERSION_SUFFIX "-rc3" +#define NG_TF_VERSION_SUFFIX "-rc0" #define VERSION_STR_HELPER(x) #x #define VERSION_STR(x) VERSION_STR_HELPER(x) diff --git a/python/setup.in.py b/python/setup.in.py index 686e9630f..da344926e 100644 --- a/python/setup.in.py +++ b/python/setup.in.py @@ -59,7 +59,7 @@ def get_tag(self): setup( name='ngraph_tensorflow_bridge', - version='0.16.0rc3', + version='0.17.0rc0', description='Intel nGraph compiler and runtime for TensorFlow', long_description=long_description, long_description_content_type="text/markdown", From a10636b46a57b8b2ba7c6231e07948f6aacde71f Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 25 Jul 2019 19:01:28 -0700 Subject: [PATCH 21/31] sarkars/Possible fix for backend settings (#159) _ngraph_backend attribute added to TF nodes will now be backend:device_id instead of just backend. --- ngraph_bridge/grappler/ngraph_optimizer.cc | 17 ++++++++++------- ngraph_bridge/grappler/ngraph_optimizer.h | 1 + ngraph_bridge/ngraph_builder.cc | 11 ++++++++--- ngraph_bridge/ngraph_encapsulate_clusters.cc | 19 +++++++++++-------- ngraph_bridge/ngraph_mark_for_clustering.cc | 12 +++++++++--- ngraph_bridge/ngraph_rewrite_pass.cc | 14 +++++++------- 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/ngraph_bridge/grappler/ngraph_optimizer.cc b/ngraph_bridge/grappler/ngraph_optimizer.cc index 1ed6f6033..502d66bd6 100644 --- a/ngraph_bridge/grappler/ngraph_optimizer.cc +++ b/ngraph_bridge/grappler/ngraph_optimizer.cc @@ -51,6 +51,7 @@ Status NgraphOptimizer::Init( } } config_backend_name = params.at("ngraph_backend").s(); + config_device_id = params.at("device_id").s(); NGRAPH_VLOG(3) << "Backend name from config: " << config_backend_name; for (auto i : params) { if (i.first != "ngraph_backend") { @@ -195,19 +196,21 @@ Status NgraphOptimizer::Optimize(tensorflow::grappler::Cluster* cluster, // Get backend + its configurations, to be attached to the nodes // using RewriteConfig - string backend_name; + string backend_creation_string = BackendManager::GetBackendCreationString( + config_backend_name, config_device_id); if (!config_backend_name.empty()) { - if (!BackendManager::IsSupportedBackend(config_backend_name)) { - return errors::Internal("NGRAPH_TF_BACKEND: ", config_backend_name, + if (!BackendManager::IsSupportedBackend(backend_creation_string)) { + return errors::Internal("NGRAPH_TF_BACKEND: ", backend_creation_string, " is not supported"); } - backend_name = config_backend_name; - NGRAPH_VLOG(1) << "Setting backend from the RewriteConfig " << backend_name; + NGRAPH_VLOG(1) << "Setting backend from the RewriteConfig " + << backend_creation_string; } - NGRAPH_VLOG(0) << "NGraph using backend: " << backend_name; + NGRAPH_VLOG(0) << "NGraph using backend: " << backend_creation_string; // 1. Mark for clustering then, if requested, dump the graphs. - TF_RETURN_IF_ERROR(MarkForClustering(&graph, skip_these_nodes, backend_name)); + TF_RETURN_IF_ERROR( + MarkForClustering(&graph, skip_these_nodes, backend_creation_string)); if (DumpMarkedGraphs()) { DumpGraphs(graph, idx, "marked", "Graph Marked for Clustering"); } diff --git a/ngraph_bridge/grappler/ngraph_optimizer.h b/ngraph_bridge/grappler/ngraph_optimizer.h index 7495c4e99..fd9caaff5 100644 --- a/ngraph_bridge/grappler/ngraph_optimizer.h +++ b/ngraph_bridge/grappler/ngraph_optimizer.h @@ -73,6 +73,7 @@ class NgraphOptimizer : public tensorflow::grappler::CustomGraphOptimizer { private: std::string config_backend_name; + std::string config_device_id; std::unordered_map config_map; std::vector compulsory_attrs = {"ngraph_backend", "device_id"}; diff --git a/ngraph_bridge/ngraph_builder.cc b/ngraph_bridge/ngraph_builder.cc index 51fa6f181..b41a4de3c 100644 --- a/ngraph_bridge/ngraph_builder.cc +++ b/ngraph_bridge/ngraph_builder.cc @@ -1090,7 +1090,8 @@ static Status TranslateCombinedNonMaxSuppressionOp( std::string backend_name; TF_RETURN_IF_ERROR(ngraph_bridge::GetNodeBackend(op, &backend_name)); - if (backend_name != "NNPI") { + auto config_map = BackendManager::GetBackendAttributeValues(backend_name); + if (config_map.at("ngraph_backend") != "NNPI") { return errors::Internal("In translating CombinedNonMaxSuppression op ", op->name(), " found requested backend ", backend_name, " which is unsupported"); @@ -2230,7 +2231,10 @@ static Status TranslateGatherV2Op( std::string backend_name; TF_RETURN_IF_ERROR(ngraph_bridge::GetNodeBackend(op, &backend_name)); - if (backend_name != "NNPI") { + // split and check the first part only, since the node attribute contains + // the full backend creation string + auto config_map = BackendManager::GetBackendAttributeValues(backend_name); + if (config_map.at("ngraph_backend") != "NNPI") { return errors::Internal("In translating GatherV2 op ", op->name(), " found requested backend ", backend_name, " which is unsupported"); @@ -2763,7 +2767,8 @@ static Status TranslateNonMaxSuppressionV4Op( std::string backend_name; TF_RETURN_IF_ERROR(ngraph_bridge::GetNodeBackend(op, &backend_name)); - if (backend_name != "NNPI") { + auto config_map = BackendManager::GetBackendAttributeValues(backend_name); + if (config_map.at("ngraph_backend") != "NNPI") { return errors::Internal("In translating NonMaxSuppressionV4 op ", op->name(), " found requested backend ", backend_name, " which is unsupported"); diff --git a/ngraph_bridge/ngraph_encapsulate_clusters.cc b/ngraph_bridge/ngraph_encapsulate_clusters.cc index b2c68d9b4..514edeafb 100644 --- a/ngraph_bridge/ngraph_encapsulate_clusters.cc +++ b/ngraph_bridge/ngraph_encapsulate_clusters.cc @@ -329,14 +329,17 @@ Status EncapsulateClusters( } Node* n; - NodeBuilder nb = NodeBuilder(ss.str(), "NGraphEncapsulate") - .Attr("ngraph_cluster", cluster_idx) - .Attr("ngraph_backend", cluster_backend) - .Attr("Targuments", input_types) - .Attr("Tresults", cluster_output_dt_map[cluster_idx]) - .Attr("ngraph_graph_id", graph_id) - .Device(device_name_map[cluster_idx]) - .Input(inputs); + NodeBuilder nb = + NodeBuilder(ss.str(), "NGraphEncapsulate") + .Attr("ngraph_cluster", cluster_idx) + .Attr("ngraph_backend", + BackendManager::GetBackendAttributeValues(cluster_backend) + .at("ngraph_backend")) + .Attr("Targuments", input_types) + .Attr("Tresults", cluster_output_dt_map[cluster_idx]) + .Attr("ngraph_graph_id", graph_id) + .Device(device_name_map[cluster_idx]) + .Input(inputs); if (!device_config.empty()) { NGRAPH_VLOG(3) << "Device config is not empty"; for (auto const& i : device_config) { diff --git a/ngraph_bridge/ngraph_mark_for_clustering.cc b/ngraph_bridge/ngraph_mark_for_clustering.cc index 54fb3c069..6aa4fea2f 100644 --- a/ngraph_bridge/ngraph_mark_for_clustering.cc +++ b/ngraph_bridge/ngraph_mark_for_clustering.cc @@ -657,19 +657,25 @@ Status MarkForClustering(Graph* graph, const std::set skip_these_nodes, bool* result) { // TODO: replace current_backend -> // BackendManager::GetCurrentlySetBackendName() - *result = (current_backend == "NNPI"); + auto config_map = + BackendManager::GetBackendAttributeValues(current_backend); + *result = (config_map.at("ngraph_backend") == "NNPI"); return Status::OK(); }; confirmation_function_map["NonMaxSuppressionV4"] = [¤t_backend]( Node* n, bool* result) { - *result = (current_backend == "NNPI"); + auto config_map = + BackendManager::GetBackendAttributeValues(current_backend); + *result = (config_map.at("ngraph_backend") == "NNPI"); return Status::OK(); }; confirmation_function_map["CombinedNonMaxSuppression"] = [¤t_backend]( Node* n, bool* result) { - *result = (current_backend == "NNPI"); + auto config_map = + BackendManager::GetBackendAttributeValues(current_backend); + *result = (config_map.at("ngraph_backend") == "NNPI"); return Status::OK(); }; diff --git a/ngraph_bridge/ngraph_rewrite_pass.cc b/ngraph_bridge/ngraph_rewrite_pass.cc index 14a87b2d8..2a0f7b683 100644 --- a/ngraph_bridge/ngraph_rewrite_pass.cc +++ b/ngraph_bridge/ngraph_rewrite_pass.cc @@ -221,18 +221,18 @@ class NGraphEncapsulationPass : public NGraphRewritePass { // to be attached to the nodes // Precedence Order: Env Variable > BackendManager std::unordered_map config_map; - string backend_name; + string backend_creation_string; + // GetCurrentlySetBackendName could return GPU:0 (not just GPU) TF_RETURN_IF_ERROR( - BackendManager::GetCurrentlySetBackendName(&backend_name)); + BackendManager::GetCurrentlySetBackendName(&backend_creation_string)); - // splits into {"ngraph_backend", "_ngraph_device_config"} + // splits into {"ngraph_backend", "ngraph_device_id"} config_map = BackendManager::GetBackendAttributeValues( - backend_name); // SplitBackendConfig - backend_name = config_map.at("ngraph_backend"); + backend_creation_string); // SplitBackendConfig config_map.erase("ngraph_backend"); if ((std::getenv("NGRAPH_TF_LOG_0_DISABLED") == nullptr)) { - NGRAPH_VLOG(0) << "NGraph using backend: " << backend_name; + NGRAPH_VLOG(0) << "NGraph using backend: " << backend_creation_string; } // Now Process the Graph @@ -240,7 +240,7 @@ class NGraphEncapsulationPass : public NGraphRewritePass { // 1. Mark for clustering then, if requested, dump the graphs. std::set skip_these_nodes = {}; TF_RETURN_IF_ERROR(MarkForClustering(options.graph->get(), skip_these_nodes, - backend_name)); + backend_creation_string)); if (DumpMarkedGraphs()) { DumpGraphs(options, idx, "marked", "Graph Marked for Clustering"); } From 2454cc55181047c7cfead7e31060a148b7a0a351 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 25 Jul 2019 19:52:43 -0700 Subject: [PATCH 22/31] Sarkars/update tf2ngraph to use rewriterconfig (#149) --- test/python/test_rewriter_config_setting.py | 87 ++++++++++++++++++ test/python/test_tf2ngraph_functions.py | 92 +++++++++++++++++++ ...ert_script.py => test_tf2ngraph_script.py} | 23 +++-- tools/tf2ngraph.py | 83 ++++++++++++++--- 4 files changed, 263 insertions(+), 22 deletions(-) create mode 100644 test/python/test_rewriter_config_setting.py create mode 100644 test/python/test_tf2ngraph_functions.py rename test/python/{test_convert_script.py => test_tf2ngraph_script.py} (83%) diff --git a/test/python/test_rewriter_config_setting.py b/test/python/test_rewriter_config_setting.py new file mode 100644 index 000000000..f48792641 --- /dev/null +++ b/test/python/test_rewriter_config_setting.py @@ -0,0 +1,87 @@ +# ============================================================================== +# 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 test for checking backend setting using rewriter config for grappler + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import os +import numpy as np +import shutil +import tensorflow as tf +from tensorflow.core.protobuf import rewriter_config_pb2 +import ngraph_bridge + +from common import NgraphTest + + +class TestRewriterConfigBackendSetting(NgraphTest): + + @pytest.mark.skipif( + not ngraph_bridge.is_grappler_enabled(), + reason='Rewriter config only works for grappler path') + @pytest.mark.parametrize(("backend",), ( + ('CPU',), + ('INTERPRETER',), + )) + def test_config_updater_api(self, backend): + dim1 = 3 + dim2 = 4 + a = tf.placeholder(tf.float32, shape=(dim1, dim2), name='a') + x = tf.placeholder(tf.float32, shape=(dim1, dim2), name='x') + b = tf.placeholder(tf.float32, shape=(dim1, dim2), name='y') + axpy = (a * x) + b + + config = tf.ConfigProto() + rewriter_options = rewriter_config_pb2.RewriterConfig() + rewriter_options.meta_optimizer_iterations = ( + rewriter_config_pb2.RewriterConfig.ONE) + rewriter_options.min_graph_nodes = -1 + ngraph_optimizer = rewriter_options.custom_optimizers.add() + ngraph_optimizer.name = "ngraph-optimizer" + ngraph_optimizer.parameter_map["ngraph_backend"].s = backend.encode() + ngraph_optimizer.parameter_map["device_id"].s = b'0' + # TODO: This test will pass if grappler fails silently. + # Need to do something about that + backend_extra_params_map = { + 'CPU': { + 'device_config': '' + }, + 'INTERPRETER': { + 'test_echo': '42', + 'hello': '3' + } + } + extra_params = backend_extra_params_map[backend] + for k in extra_params: + ngraph_optimizer.parameter_map[k].s = extra_params[k].encode() + config.MergeFrom( + tf.ConfigProto( + graph_options=tf.GraphOptions( + rewrite_options=rewriter_options))) + + with tf.Session(config=config) as sess: + outval = sess.run( + axpy, + feed_dict={ + a: 1.5 * np.ones((dim1, dim2)), + b: np.ones((dim1, dim2)), + x: np.ones((dim1, dim2)) + }) + assert (outval == 2.5 * (np.ones((dim1, dim2)))).all() diff --git a/test/python/test_tf2ngraph_functions.py b/test/python/test_tf2ngraph_functions.py new file mode 100644 index 000000000..102cb98aa --- /dev/null +++ b/test/python/test_tf2ngraph_functions.py @@ -0,0 +1,92 @@ +# ============================================================================== +# 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 test for helper functions of tf2ngraph tool + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import os +import numpy as np +import shutil +import tensorflow as tf +import ngraph_bridge + +from tools.build_utils import command_executor +from tools.tf2ngraph import parse_extra_params_string, update_config_to_include_custom_config + +from common import NgraphTest + + +class Testtf2ngraphHelperFunctions(NgraphTest): + + def test_config_updater_api(self): + config = update_config_to_include_custom_config(tf.ConfigProto(), 'CPU', + '0', { + 'abc': '1', + 'def': '2' + }) + assert config.HasField('graph_options') + assert config.graph_options.HasField('rewrite_options') + custom_opts = config.graph_options.rewrite_options.custom_optimizers + assert len(custom_opts) == 1 + assert custom_opts[0].name == 'ngraph-optimizer' + assert set(custom_opts[0].parameter_map.keys()) == { + 'abc', 'ngraph_backend', 'def', 'device_id' + } + retrieved_dict = {} + for key, val in custom_opts[0].parameter_map.items(): + retrieved_dict[key] = val.ListFields()[0][1].decode() + assert retrieved_dict == { + 'abc': '1', + 'def': '2', + 'ngraph_backend': 'CPU', + 'device_id': '0' + } + + # In this test we test that the spaces are handled correctly + @pytest.mark.parametrize(('ng_device',), + (('{abc:1,def:2}',), ('{abc:1, def:2}',), + ('{abc :1,def: 2}',), ('{abc:1,def: 2} ',))) + def parse_extra_params_string(self, raw_string): + assert (parse_extra_params_string(raw_string) == { + 'abc': '1', + 'def': '2' + }) + + # This test checks the parsing of the empty dictionary {} + def parse_extra_params_empty(self): + assert (parse_extra_params_string('{}') == {}) + + # In this test we pass badly formatted strings, + # and expect parse_extra_params_string to fail + @pytest.mark.parametrize(('ng_device',), ( + ('abc:1,def:2}',), + ('{abc:1, def:2',), + ('{abc :1:2 ,def: 2}',), + )) + def parse_extra_params_string(self, raw_string): + function_failed = False + try: + parse_extra_params_string(raw_string) + except: + function_failed = True + assert function_failed + + # TODO: write a test for parse_extra_params_string for incorrect parsings + # where parse_extra_params_string is expected to fail diff --git a/test/python/test_convert_script.py b/test/python/test_tf2ngraph_script.py similarity index 83% rename from test/python/test_convert_script.py rename to test/python/test_tf2ngraph_script.py index 39173fffb..f87d89fbc 100644 --- a/test/python/test_convert_script.py +++ b/test/python/test_tf2ngraph_script.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== +"""nGraph TensorFlow bridge test for tf2ngraph script for precompilation + +""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -30,7 +33,7 @@ from common import NgraphTest -class TestConversionScript(NgraphTest): +class Testtf2ngraph(NgraphTest): # utility function to make sure input format and location match @staticmethod @@ -61,7 +64,7 @@ def test_command_line_api(self, inp_format, inp_loc, out_format, # Only run this test when grappler is enabled if not ngraph_bridge.is_grappler_enabled(): return - assert TestConversionScript.format_and_loc_match(inp_format, inp_loc) + assert Testtf2ngraph.format_and_loc_match(inp_format, inp_loc) out_loc = inp_loc.split('.')[0] + '_modified' + ( '' if out_format == 'savedmodel' else ('.' + out_format)) try: @@ -70,15 +73,20 @@ def test_command_line_api(self, inp_format, inp_loc, out_format, pass conversion_successful = False try: + extra_params = { + 'CPU': '{device_config:0}', + 'INTERPRETER': '{test_echo:1}' + }[ng_device] if commandline: # In CI this test is expected to be run out of artifacts/test/python - command_executor( - 'python ../../tools/tf2ngraph.py --input_' + inp_format + - ' ' + inp_loc + ' --output_nodes out_node --output_' + - out_format + ' ' + out_loc + ' --ngbackend ' + ng_device) + command_executor('python ../../tools/tf2ngraph.py --input_' + + inp_format + ' ' + inp_loc + + ' --output_nodes out_node --output_' + + out_format + ' ' + out_loc + ' --ng_backend ' + + ng_device + ' --extra_params ' + extra_params) else: convert(inp_format, inp_loc, out_format, out_loc, ['out_node'], - ng_device) + ng_device, extra_params) conversion_successful = True finally: if not conversion_successful: @@ -97,6 +105,7 @@ def test_command_line_api(self, inp_format, inp_loc, out_format, assert len([ 0 for i in g.get_operations() if i.type == 'NGraphEncapsulate' ]) == 1 + # TODO: check that the encapsulate op has correct backend and extra params attached to it x = self.get_tensor(g, "x:0", False) y = self.get_tensor(g, "y:0", False) out = self.get_tensor(g, "out_node:0", False) diff --git a/tools/tf2ngraph.py b/tools/tf2ngraph.py index a8e2f4bab..c475d15ac 100644 --- a/tools/tf2ngraph.py +++ b/tools/tf2ngraph.py @@ -18,6 +18,7 @@ import tensorflow as tf from google.protobuf import text_format from tensorflow.core.protobuf import meta_graph_pb2 +from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.grappler import tf_optimizer import ngraph_bridge import os @@ -25,7 +26,50 @@ from functools import partial -def run_ngraph_grappler_optimizer(input_gdef, output_nodes): +def parse_extra_params_string(raw_extra_params): + raw_extra_params = raw_extra_params.strip(' ') + assert raw_extra_params[0] == '{' and raw_extra_params[ + -1] == '}', "Expected extra_params string to be a dictionary beginning with { and ending with }" + raw_extra_params_contents = raw_extra_params[1:-1].strip(' ') + extra_params_dict = {} + if len(raw_extra_params_contents) == 0: + return extra_params_dict + # could have used eval(extra_params_string), but then the string would have to be the cumbersome {\"abc\":1} + # and not {"abc":1} or {abc:1}. Hence explicity parsing the string without using eval + for key_val in raw_extra_params_contents.split(','): + key_val = key_val.strip(' ') + try: + key, val = key_val.split(':') + extra_params_dict[key.strip(' ')] = val.strip(' ') + except Exception as e: + raise type( + e + )(e.message + + 'Got an entry in extra_params, that is an invalid entry for a python dictionary: ' + + key_val) + return extra_params_dict + + +def update_config_to_include_custom_config(config, backend, device_id, + extra_params): + rewriter_options = rewriter_config_pb2.RewriterConfig() + rewriter_options.meta_optimizer_iterations = ( + rewriter_config_pb2.RewriterConfig.ONE) + rewriter_options.min_graph_nodes = -1 + ngraph_optimizer = rewriter_options.custom_optimizers.add() + ngraph_optimizer.name = "ngraph-optimizer" + ngraph_optimizer.parameter_map["ngraph_backend"].s = backend.encode() + ngraph_optimizer.parameter_map["device_id"].s = device_id.encode() + for k in extra_params: + ngraph_optimizer.parameter_map[k].s = extra_params[k].encode() + config.MergeFrom( + tf.ConfigProto( + graph_options=tf.GraphOptions(rewrite_options=rewriter_options))) + return config + + +def run_ngraph_grappler_optimizer(input_gdef, output_nodes, ng_backend, + device_id, extra_params): graph = tf.Graph() with graph.as_default(): tf.import_graph_def(input_gdef, name="") @@ -45,7 +89,10 @@ def run_ngraph_grappler_optimizer(input_gdef, output_nodes): output_collection) session_config = tf.ConfigProto() - session_config = ngraph_bridge.update_config(session_config) + # Pass backend and extra backend params to grappler through rewriter config by updating the config + # TODO: move update_config_to_include_custom_config to ngraph_bridge + session_config = update_config_to_include_custom_config( + session_config, ng_backend, device_id, extra_params) output_gdef = tf_optimizer.OptimizeGraph( session_config, grappler_meta_graph_def, graph_id=b"tf_graph") return output_gdef @@ -99,7 +146,7 @@ def prepare_argparser(formats): python tf2ngraph.py --input_savedmodel resnet_model_location --output_nodes out_node --output_pbtxt resnet_ngraph.pbtxt python tf2ngraph.py --input_pbtxt mobilenet.pbtxt --output_nodes out_node --output_pbtxt mobilenet_ngraph.pbtxt python tf2ngraph.py --input_pb inception_v3_2016_08_28_frozen.pb --output_nodes InceptionV3/Predictions/Reshape_1 --output_pb inception_v3_2016_08_28_frozen_ngraph.pb - python tf2ngraph.py --input_pbtxt ../test/test_axpy.pbtxt --output_nodes add --output_pbtxt axpy_ngraph.pbtxt + python tf2ngraph.py --input_pbtxt ../test/test_axpy.pbtxt --output_nodes add --output_pbtxt axpy_ngraph.pbtxt --ng_backend CPU ''') in_out_groups = [ parser.add_argument_group(i, j) for i, j in zip( @@ -120,9 +167,14 @@ def prepare_argparser(formats): "summarize_graph tool provided by Tensorflow", required=True) parser.add_argument( - "--ngbackend", - default='CPU', - help="Ngraph backend (with cardinality). Eg, NNPI:0") + "--ng_backend", default='CPU', help="Ngraph backend. Eg, NNPI") + parser.add_argument("--device_id", default='', help="Device id. Eg, 0") + parser.add_argument( + "--extra_params", + default='{}', + help= + "Other params that the backend needs in the form of a dictionary. Eg, {max_cores: 4}." + ) if len(sys.argv) == 1: parser.print_help(sys.stderr) sys.exit(1) @@ -173,9 +225,7 @@ def save_model(gdef, format, location): }[format](gdef, location) -def attach_device_and_ng_backend(gdef, ng_backend): - ngraph_bridge.set_backend(ng_backend) - # Assumes that the whole graph runs on a single ng_backend +def attach_device(gdef): for n in gdef.node: n.device = "/device:CPU:0" @@ -186,7 +236,8 @@ def attach_device_and_ng_backend(gdef, ng_backend): } -def convert(inp_format, inp_loc, out_format, out_loc, output_nodes, ng_backend): +def convert(inp_format, inp_loc, out_format, out_loc, output_nodes, ng_backend, + device_id, extra_params): """Functional api for converting TF models by inserting ngraph nodes. Sample usage: from tf2ngraph import convert @@ -206,23 +257,25 @@ def convert(inp_format, inp_loc, out_format, out_loc, output_nodes, ng_backend): assert out_format in allowed_formats['output'] assert ngraph_bridge.is_grappler_enabled() input_gdef = get_gdef(inp_format, inp_loc) - attach_device_and_ng_backend(input_gdef, ng_backend) - output_gdef = run_ngraph_grappler_optimizer(input_gdef, output_nodes) + attach_device(input_gdef) + output_gdef = run_ngraph_grappler_optimizer( + input_gdef, output_nodes, ng_backend, device_id, extra_params) save_model(output_gdef, out_format, out_loc) def main(): """ Entry point of command line api for converting TF models by inserting ngraph nodes. Sample usage: - python tf2ngraph.py --inputsavedmodel test_graph --output_nodes out_node --outputpbtxt test_graph_ngraph.pbtxt --ngbackend NNPI:0 - python tf2ngraph.py --inputpbtxt test_graph.pbtxt --output_nodes out_node --outputpbtxt test_graph_ngraph.pbtxt --ngbackend NNPI:0 + python tf2ngraph.py --inputsavedmodel test_graph --output_nodes out_node --outputpbtxt test_graph_ngraph.pbtxt --ng_backend NNPI:0 + python tf2ngraph.py --inputpbtxt test_graph.pbtxt --output_nodes out_node --outputpbtxt test_graph_ngraph.pbtxt --ng_backend NNPI:0 """ args = prepare_argparser(allowed_formats) inp_format, inp_loc = filter_dict("input", args.__dict__) out_format, out_loc = filter_dict("output", args.__dict__) output_nodes = args.output_nodes.split(',') + extra_params = parse_extra_params_string(args.extra_params) convert(inp_format, inp_loc, out_format, out_loc, output_nodes, - args.ngbackend) + args.ng_backend, args.device_id, extra_params) print('Converted the model. Exiting now') From 20a6394acc78d11e42050fe180efd51efdbe47fd Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 25 Jul 2019 20:35:57 -0700 Subject: [PATCH 23/31] Upgrade to 0.17.0rc1 (#163) --- README.md | 2 +- ngraph_bridge/version.cc | 2 +- python/setup.in.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5e63932a..dbbcee7f1 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Once TensorFlow's dependencies are installed, clone the `ngraph-bridge` repo: git clone https://github.com/tensorflow/ngraph-bridge.git cd ngraph-bridge - git checkout v0.17.0-rc0 + git checkout v0.17.0-rc1 Run the following Python script to build TensorFlow, nGraph, and the bridge. Use Python 3.5: diff --git a/ngraph_bridge/version.cc b/ngraph_bridge/version.cc index b13792694..ff98837cb 100644 --- a/ngraph_bridge/version.cc +++ b/ngraph_bridge/version.cc @@ -32,7 +32,7 @@ // candidate such as v0.7.0-rc0 // The code in master will always have the last released version number // with a suffix of '-master' -#define NG_TF_VERSION_SUFFIX "-rc0" +#define NG_TF_VERSION_SUFFIX "-rc1" #define VERSION_STR_HELPER(x) #x #define VERSION_STR(x) VERSION_STR_HELPER(x) diff --git a/python/setup.in.py b/python/setup.in.py index da344926e..b720aa0b6 100644 --- a/python/setup.in.py +++ b/python/setup.in.py @@ -59,7 +59,7 @@ def get_tag(self): setup( name='ngraph_tensorflow_bridge', - version='0.17.0rc0', + version='0.17.0rc1', description='Intel nGraph compiler and runtime for TensorFlow', long_description=long_description, long_description_content_type="text/markdown", From 5a040c763fccb528edfbb69b4f598cbb8ba90eb5 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Fri, 26 Jul 2019 14:51:59 -0700 Subject: [PATCH 24/31] Upgrade nGraph Core to 0.24.0-rc.2 (#166) --- CMakeLists.txt | 2 +- README.md | 2 +- bazel/WORKSPACE | 8 ++++---- build_ngtf.py | 2 +- ngraph_bridge/version.cc | 2 +- python/setup.in.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31c7e8818..f3b00b0d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ if (NOT USE_PRE_BUILT_NGRAPH) ExternalProject_Add( ext_ngraph GIT_REPOSITORY https://github.com/NervanaSystems/ngraph - GIT_TAG v0.24.0-rc.0 + GIT_TAG v0.24.0-rc.2 CMAKE_ARGS -DNGRAPH_DISTRIBUTED_ENABLE=${NGRAPH_DISTRIBUTED_ENABLE} -DNGRAPH_INSTALL_PREFIX=${NGRAPH_ARTIFACTS_DIR} diff --git a/README.md b/README.md index dbbcee7f1..217787693 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Once TensorFlow's dependencies are installed, clone the `ngraph-bridge` repo: git clone https://github.com/tensorflow/ngraph-bridge.git cd ngraph-bridge - git checkout v0.17.0-rc1 + git checkout v0.17.0-rc2 Run the following Python script to build TensorFlow, nGraph, and the bridge. Use Python 3.5: diff --git a/bazel/WORKSPACE b/bazel/WORKSPACE index f9372a98a..20600872d 100644 --- a/bazel/WORKSPACE +++ b/bazel/WORKSPACE @@ -25,11 +25,11 @@ tf_configure( http_archive( name = "ngraph", build_file = "//:bazel/ngraph.BUILD", - sha256 = "9f396b6ec5286eeb15eac8c2547b5d60dc07cf8dcc9feb969d5ef352ac38edb1", - strip_prefix = "ngraph-0.24.0-rc.0", + sha256 = "fba0fb45225c6eb068cfea16decdcef6d0e1552ab2d5f90f4940fa1059e60481", + strip_prefix = "ngraph-0.24.0-rc.2", urls = [ - "https://mirror.bazel.build/github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.0.tar.gz", - "https://github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.0.tar.gz" + "https://mirror.bazel.build/github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.2.tar.gz", + "https://github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.2.tar.gz" ], ) diff --git a/build_ngtf.py b/build_ngtf.py index 74b61c506..d06f65417 100755 --- a/build_ngtf.py +++ b/build_ngtf.py @@ -53,7 +53,7 @@ def main(): ''' # Component versions - ngraph_version = "v0.24.0-rc.0" + ngraph_version = "v0.24.0-rc.2" tf_version = "v1.14.0" # Command line parser options diff --git a/ngraph_bridge/version.cc b/ngraph_bridge/version.cc index ff98837cb..c16ea6e4f 100644 --- a/ngraph_bridge/version.cc +++ b/ngraph_bridge/version.cc @@ -32,7 +32,7 @@ // candidate such as v0.7.0-rc0 // The code in master will always have the last released version number // with a suffix of '-master' -#define NG_TF_VERSION_SUFFIX "-rc1" +#define NG_TF_VERSION_SUFFIX "-rc2" #define VERSION_STR_HELPER(x) #x #define VERSION_STR(x) VERSION_STR_HELPER(x) diff --git a/python/setup.in.py b/python/setup.in.py index b720aa0b6..296775f5a 100644 --- a/python/setup.in.py +++ b/python/setup.in.py @@ -59,7 +59,7 @@ def get_tag(self): setup( name='ngraph_tensorflow_bridge', - version='0.17.0rc1', + version='0.17.0rc2', description='Intel nGraph compiler and runtime for TensorFlow', long_description=long_description, long_description_content_type="text/markdown", From 0b6482369b23cd1e313a2564a170853f514dcf59 Mon Sep 17 00:00:00 2001 From: Avijit Date: Mon, 29 Jul 2019 23:54:00 +0530 Subject: [PATCH 25/31] Avijit/bazel cleanup (#140) --- test/ci/buildkite/ngtf-cpu_centos-grappler.yaml | 1 + test/ci/buildkite/ngtf-cpu_centos.yaml | 1 + test/ci/buildkite/ngtf-cpu_tf_bin.yaml | 3 ++- test/ci/buildkite/ngtf-cpu_ubuntu-bin-build.yaml | 1 + test/ci/buildkite/ngtf-cpu_ubuntu.yaml | 1 + test/ci/buildkite/ngtf-cpu_ubuntu_18_04.yaml | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/ci/buildkite/ngtf-cpu_centos-grappler.yaml b/test/ci/buildkite/ngtf-cpu_centos-grappler.yaml index 713d14415..6f177b335 100644 --- a/test/ci/buildkite/ngtf-cpu_centos-grappler.yaml +++ b/test/ci/buildkite/ngtf-cpu_centos-grappler.yaml @@ -32,6 +32,7 @@ /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/tensorflow/tensorflow-1.14.0-cp36-cp36m-linux_x86_64.whl PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel + bazel clean --expunge label: ":bazel: Bazel Build" timeout_in_minutes: 30 diff --git a/test/ci/buildkite/ngtf-cpu_centos.yaml b/test/ci/buildkite/ngtf-cpu_centos.yaml index 16de50f1a..70e761aee 100644 --- a/test/ci/buildkite/ngtf-cpu_centos.yaml +++ b/test/ci/buildkite/ngtf-cpu_centos.yaml @@ -44,6 +44,7 @@ /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/tensorflow/tensorflow-1.14.0-cp36-cp36m-linux_x86_64.whl PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel + bazel clean --expunge label: ":bazel: Bazel Build" timeout_in_minutes: 30 diff --git a/test/ci/buildkite/ngtf-cpu_tf_bin.yaml b/test/ci/buildkite/ngtf-cpu_tf_bin.yaml index aa484ea6d..efc224a82 100644 --- a/test/ci/buildkite/ngtf-cpu_tf_bin.yaml +++ b/test/ci/buildkite/ngtf-cpu_tf_bin.yaml @@ -40,7 +40,8 @@ source /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/venv/bin/activate PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel - + bazel clean --expunge + label: ":bazel: Bazel Build" timeout_in_minutes: 30 agents: diff --git a/test/ci/buildkite/ngtf-cpu_ubuntu-bin-build.yaml b/test/ci/buildkite/ngtf-cpu_ubuntu-bin-build.yaml index 3fb9ef919..98975646a 100644 --- a/test/ci/buildkite/ngtf-cpu_ubuntu-bin-build.yaml +++ b/test/ci/buildkite/ngtf-cpu_ubuntu-bin-build.yaml @@ -26,6 +26,7 @@ source /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/venv/bin/activate PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel + bazel clean --expunge label: ":bazel: Bazel Build" timeout_in_minutes: 30 diff --git a/test/ci/buildkite/ngtf-cpu_ubuntu.yaml b/test/ci/buildkite/ngtf-cpu_ubuntu.yaml index 0dd8813f5..776410b6a 100644 --- a/test/ci/buildkite/ngtf-cpu_ubuntu.yaml +++ b/test/ci/buildkite/ngtf-cpu_ubuntu.yaml @@ -44,6 +44,7 @@ /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/tensorflow/tensorflow-1.14.0-cp36-cp36m-linux_x86_64.whl PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel + bazel clean --expunge label: ":bazel: Bazel Build" timeout_in_minutes: 30 diff --git a/test/ci/buildkite/ngtf-cpu_ubuntu_18_04.yaml b/test/ci/buildkite/ngtf-cpu_ubuntu_18_04.yaml index 98a6ead11..4e5844365 100644 --- a/test/ci/buildkite/ngtf-cpu_ubuntu_18_04.yaml +++ b/test/ci/buildkite/ngtf-cpu_ubuntu_18_04.yaml @@ -41,6 +41,7 @@ /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID/tensorflow/tensorflow-1.14.0-cp36-cp36m-linux_x86_64.whl PYTHONPATH=`pwd` python3 test/ci/buildkite/test_runner.py \ --artifacts /localdisk/buildkite/artifacts/$BUILDKITE_BUILD_ID --test_bazel + bazel clean --expunge label: ":bazel: Bazel Build" timeout_in_minutes: 30 From 951ca465be49bc271ae3b6e130d6d88a0324809f Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Thu, 1 Aug 2019 11:00:12 -0700 Subject: [PATCH 26/31] Shrestha/Fix --num_inter_threads (#175) * Added Control Edge between input_0 and input_1 of NGAssign --- .../enable_variable_ops/ngraph_assign_op.cc | 8 ++++--- .../ngraph_enter_in_catalog.cc | 1 + .../ngraph_remove_ngraphassigns.cc | 5 +++++ .../ngraph_rewrite_pass.cc | 8 +++---- .../ngraph_tracked_variable.cc | 9 ++++---- ngraph_bridge/ngraph_encapsulate_op.cc | 2 +- test/graph_rewrites/remove_ngraphassigns.cc | 22 +++++++++++++++++++ 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/ngraph_bridge/enable_variable_ops/ngraph_assign_op.cc b/ngraph_bridge/enable_variable_ops/ngraph_assign_op.cc index bcba19cce..ddb14d820 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_assign_op.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_assign_op.cc @@ -101,7 +101,7 @@ class NGraphAssignOp : public OpKernel { IsNgraphTFLogTensorCopiesEnabled(ng_graph_id_, log_copies)); std::stringstream copy_log_str; copy_log_str << "KERNEL[" << type_string() << "]: " << name() - << " ,Copy_TF " << PrintBool(copy_to_tf_) + << " ,copy-to-tf " << PrintBool(copy_to_tf_) << ", is_tf_just_looking " << PrintBool(is_tf_just_looking_) << ", just_looking " << PrintBool(just_looking_) << "\n"; int number_of_copies = 0; @@ -131,7 +131,9 @@ class NGraphAssignOp : public OpKernel { // Get input[1] - // input[1] cannot be from NGraphEncap Op + // The NGraphAssign Ops with input[1] from NGraphEncap Op are removed + // in the RemoveNGraphAssigns phase in rewrite pass + // Assert input[1] is not from NGraphEncap Op // No way to get input node and check its type string input_1_name = def().input(1); OP_REQUIRES( @@ -151,7 +153,7 @@ class NGraphAssignOp : public OpKernel { if (copy_to_tf_) { if (var->copy_ng_to_tf()) { number_of_copies++; - copy_log_str << " COPY_TF "; + copy_log_str << " COPY_TO_TF "; } if (!is_tf_just_looking_) { diff --git a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc index 1145f4cac..31ecf1c88 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_enter_in_catalog.cc @@ -91,6 +91,7 @@ Status EnterInCatalog(Graph* graph, int graph_id) { NGRAPH_VLOG(4) << "output_index " << output_index; string key = NGraphCatalog::CreateNodeKey(graph_id, input_1->name(), output_index); + tuple value = make_tuple(shared_name, copy_to_tf, is_tf_just_looking); NGRAPH_VLOG(4) << "Adding to EncapOutputInfoMap "; diff --git a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc index f18804978..5261b7690 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_remove_ngraphassigns.cc @@ -45,6 +45,11 @@ Status RemoveNGraphAssigns(Graph* graph) { input_1->type_string()); } + // Add control edge between the Op providing the variable and the Op + // updating it + graph->AddEdge(input_0, Graph::kControlSlot, input_1, + Graph::kControlSlot); + // Handle input edges NGRAPH_VLOG(3) << "Handling input edges "; vector remove_edges; diff --git a/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc b/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc index 603dbc50f..11609e3b9 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_rewrite_pass.cc @@ -316,24 +316,24 @@ class NGraphEncapsulationPass : public NGraphRewritePass { "Graph with Clusters Encapsulated"); } - // Rewrite for tracking then, if requested, dump the graphs. + // 5. Rewrite for tracking then, if requested, dump the graphs. TF_RETURN_IF_ERROR(RewriteForTracking(options.graph->get(), idx)); if (DumpTrackedGraphs()) { DumpGraphs(options, idx, "tracked", "Graph with Variables Rewritten for Tracking"); } - // Enter in catalog then. + // 6. Enter in catalog then. TF_RETURN_IF_ERROR(EnterInCatalog(options.graph->get(), idx)); if (DumpCatalogedGraphs()) { DumpGraphs(options, idx, "cataloged", "Graph with Variables Inputs Entered in Catalog"); } - // Remove Certain NGraphAssigns then. + // 7. Remove Certain NGraphAssigns then. TF_RETURN_IF_ERROR(RemoveNGraphAssigns(options.graph->get())); if (DumpRemoveNGraphAssignsGraphs()) { - DumpGraphs(options, idx, "ngraphssigns_optimized", + DumpGraphs(options, idx, "ngraphassigns_optimized", "Graph with NGraphAssigns Optimized/Removed"); } diff --git a/ngraph_bridge/enable_variable_ops/ngraph_tracked_variable.cc b/ngraph_bridge/enable_variable_ops/ngraph_tracked_variable.cc index 77a8e3f95..f91bd278d 100644 --- a/ngraph_bridge/enable_variable_ops/ngraph_tracked_variable.cc +++ b/ngraph_bridge/enable_variable_ops/ngraph_tracked_variable.cc @@ -134,9 +134,10 @@ void NGraphVariableOp::Compute(OpKernelContext* ctx) { OP_REQUIRES_OK(ctx, IsNgraphTFLogTensorCopiesEnabled(ng_graph_id_, log_copies)); std::stringstream copy_log_str; - copy_log_str << "KERNEL[" << type_string() << "]: " << name() << " ,Copy_TF " - << PrintBool(copy_to_tf_) << " ,is_tf_just_looking " - << PrintBool(is_tf_just_looking_) << "\n"; + copy_log_str << "KERNEL[" << type_string() << "]: " << name() + << " ,copy-to-tf " << PrintBool(copy_to_tf_) + << " ,is_tf_just_looking " << PrintBool(is_tf_just_looking_) + << "\n"; int number_of_copies = 0; mutex_lock l(init_mu_); @@ -202,7 +203,7 @@ void NGraphVariableOp::Compute(OpKernelContext* ctx) { if (!just_synced) { if (var->copy_ng_to_tf()) { number_of_copies++; - copy_log_str << " COPY_TF "; + copy_log_str << " COPY_TO_TF "; } NGRAPH_VLOG(4) << "Copying to TF Tensor"; } diff --git a/ngraph_bridge/ngraph_encapsulate_op.cc b/ngraph_bridge/ngraph_encapsulate_op.cc index 86d751283..f984752d8 100644 --- a/ngraph_bridge/ngraph_encapsulate_op.cc +++ b/ngraph_bridge/ngraph_encapsulate_op.cc @@ -867,7 +867,7 @@ class NGraphEncapsulateOp : public OpKernel { if (NGraphCatalog::GetCopyToTFFromEncapOutputInfoMap(output_key)) { if (var->copy_ng_to_tf()) { number_of_copies++; - copy_log_str << " COPY_TF "; + copy_log_str << " COPY_TO_TF "; } if (!NGraphCatalog::GetIsTFJustLookingFromEncapOutputInfoMap( output_key)) { diff --git a/test/graph_rewrites/remove_ngraphassigns.cc b/test/graph_rewrites/remove_ngraphassigns.cc index b620caef6..3d501080a 100644 --- a/test/graph_rewrites/remove_ngraphassigns.cc +++ b/test/graph_rewrites/remove_ngraphassigns.cc @@ -184,10 +184,18 @@ TEST(RemoveNGraphAssigns, Graph2) { edge_count++; } + // Assert on edges connected to add ASSERT_EQ(edge_count, 3); ASSERT_EQ(add_in_0, node_map.at("Var")); ASSERT_EQ(add_in_1, node_map.at(encap_op_name)); ASSERT_EQ(add_in_ctrl, node_map.at(encap_op_name)); + + // Assert on control edge between Var and Encap + for (auto edge : add_in_0->out_edges()) { + if ((edge != nullptr) && (edge->IsControlEdge())) { + ASSERT_EQ(add_in_1, edge->dst()); + } + } } // Var Const @@ -280,6 +288,13 @@ TEST(RemoveNGraphAssigns, Graph3) { ASSERT_EQ(assign_in_0, node_map.at("Var")); ASSERT_EQ(assign_in_1, node_map.at(encap_op_name)); ASSERT_EQ(assign_in_ctrl, node_map.at(encap_op_name)); + + // Assert on control edge between Var and Encap + for (auto edge : assign_in_0->out_edges()) { + if ((edge != nullptr) && (edge->IsControlEdge())) { + ASSERT_EQ(assign_in_1, edge->dst()); + } + } } // Var Const @@ -385,6 +400,13 @@ TEST(RemoveNGraphAssigns, Graph4) { ASSERT_EQ(add_in_0, node_map.at("Var")); ASSERT_EQ(add_in_1, node_map.at(encap_op_name)); ASSERT_EQ(add_in_ctrl, node_map.at(encap_op_name)); + + // Assert on control edge between Var and Encap + for (auto edge : add_in_0->out_edges()) { + if ((edge != nullptr) && (edge->IsControlEdge())) { + ASSERT_EQ(add_in_1, edge->dst()); + } + } } // Var Const From f0e85ae9f9c546cc91be82de39ccf4ce6c7376c9 Mon Sep 17 00:00:00 2001 From: Sayantan Sarkar Date: Thu, 1 Aug 2019 12:15:34 -0700 Subject: [PATCH 27/31] sarkars/Upgrade to ngcore24 (#180) --- CMakeLists.txt | 2 +- README.md | 8 ++++---- bazel/WORKSPACE | 8 ++++---- build_ngtf.py | 2 +- ngraph_bridge/version.cc | 2 +- python/setup.in.py | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3b00b0d8..91bd72ab2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ if (NOT USE_PRE_BUILT_NGRAPH) ExternalProject_Add( ext_ngraph GIT_REPOSITORY https://github.com/NervanaSystems/ngraph - GIT_TAG v0.24.0-rc.2 + GIT_TAG v0.24.0 CMAKE_ARGS -DNGRAPH_DISTRIBUTED_ENABLE=${NGRAPH_DISTRIBUTED_ENABLE} -DNGRAPH_INSTALL_PREFIX=${NGRAPH_ARTIFACTS_DIR} diff --git a/README.md b/README.md index 217787693..e10fd0512 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ environment. The requirements for building nGraph bridge are identical to the requirements for building TensorFlow from source. For more information, review the [TensorFlow configuration] details. -##### Prepare you build environment +##### Prepare your build environment Install the following requirements before building `nGraph-bridge`. @@ -88,7 +88,7 @@ Once TensorFlow's dependencies are installed, clone the `ngraph-bridge` repo: git clone https://github.com/tensorflow/ngraph-bridge.git cd ngraph-bridge - git checkout v0.17.0-rc2 + git checkout v0.17.0-rc3 Run the following Python script to build TensorFlow, nGraph, and the bridge. Use Python 3.5: @@ -115,7 +115,7 @@ To use the `ngraph-tensorflow-bridge`, activate the following `virtualenv` to st source build_cmake/venv-tf-py3/bin/activate -Alternatively, you can also install the TensorFlow and nGraph bridge outside of a `virtualenv`. The Python `whl` files are located in the `build_cmake/artifacts/` and `build_cmake/artifats/tensorflow` directories, respectively. +Alternatively, you can also install the TensorFlow and nGraph bridge outside of a `virtualenv`. The Python `whl` files are located in the `build_cmake/artifacts/` and `build_cmake/artifacts/tensorflow` directories, respectively. Select the help option of `build_ngtf.py` script to learn more about various build options and how to build other backends. @@ -219,7 +219,7 @@ results = sess.run(output_operation.outputs[0], { elapsed = time.time() - start print('Time elapsed: %f seconds' % elapsed) ``` -Observe that the ouput time runs faster than TensorFlow native (i.e., without nGraph). +Observe that the output time runs faster than TensorFlow native (i.e., without nGraph). #### Add additional backends diff --git a/bazel/WORKSPACE b/bazel/WORKSPACE index 20600872d..617a3ec78 100644 --- a/bazel/WORKSPACE +++ b/bazel/WORKSPACE @@ -25,11 +25,11 @@ tf_configure( http_archive( name = "ngraph", build_file = "//:bazel/ngraph.BUILD", - sha256 = "fba0fb45225c6eb068cfea16decdcef6d0e1552ab2d5f90f4940fa1059e60481", - strip_prefix = "ngraph-0.24.0-rc.2", + sha256 = "19788f421416a74659d7b38ef9d777baf4d935881b11cb1598629bc0ea16d99b", + strip_prefix = "ngraph-0.24.0", urls = [ - "https://mirror.bazel.build/github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.2.tar.gz", - "https://github.com/NervanaSystems/ngraph/archive/v0.24.0-rc.2.tar.gz" + "https://mirror.bazel.build/github.com/NervanaSystems/ngraph/archive/v0.24.0.tar.gz", + "https://github.com/NervanaSystems/ngraph/archive/v0.24.0.tar.gz" ], ) diff --git a/build_ngtf.py b/build_ngtf.py index d06f65417..5f86a20f9 100755 --- a/build_ngtf.py +++ b/build_ngtf.py @@ -53,7 +53,7 @@ def main(): ''' # Component versions - ngraph_version = "v0.24.0-rc.2" + ngraph_version = "v0.24.0" tf_version = "v1.14.0" # Command line parser options diff --git a/ngraph_bridge/version.cc b/ngraph_bridge/version.cc index c16ea6e4f..f90bb18ea 100644 --- a/ngraph_bridge/version.cc +++ b/ngraph_bridge/version.cc @@ -32,7 +32,7 @@ // candidate such as v0.7.0-rc0 // The code in master will always have the last released version number // with a suffix of '-master' -#define NG_TF_VERSION_SUFFIX "-rc2" +#define NG_TF_VERSION_SUFFIX "-rc3" #define VERSION_STR_HELPER(x) #x #define VERSION_STR(x) VERSION_STR_HELPER(x) diff --git a/python/setup.in.py b/python/setup.in.py index 296775f5a..b40555c68 100644 --- a/python/setup.in.py +++ b/python/setup.in.py @@ -59,7 +59,7 @@ def get_tag(self): setup( name='ngraph_tensorflow_bridge', - version='0.17.0rc2', + version='0.17.0rc3', description='Intel nGraph compiler and runtime for TensorFlow', long_description=long_description, long_description_content_type="text/markdown", From fd1d7132bcee6b0fe8db85b93b4abac84d8e8de9 Mon Sep 17 00:00:00 2001 From: Sindhura Kantamani Date: Wed, 7 Aug 2019 14:20:19 -0700 Subject: [PATCH 28/31] Sindhu/pad op python test (#187) * Implement python test for Pad Op --- test/python/test_pad.py | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 test/python/test_pad.py diff --git a/test/python/test_pad.py b/test/python/test_pad.py new file mode 100644 index 000000000..98c3eb09f --- /dev/null +++ b/test/python/test_pad.py @@ -0,0 +1,48 @@ +# ============================================================================== +# Copyright 2018-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 pad operation test + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import numpy as np + +import tensorflow as tf + +from common import NgraphTest + +np.random.seed(5) + + +class TestCastOperations(NgraphTest): + + def test_pad(self): + input_data = tf.placeholder(tf.int32, shape=(2, 3)) + paddings = tf.placeholder(tf.int32, shape=(2, 2)) + + out = tf.pad(input_data, paddings) + + inp = ((4, 2, 4), (4, 4, 1)) + pad = ((5, 3), (5, 5)) + + def run_test(sess): + return sess.run(out, feed_dict={input_data: inp, paddings: pad}) + + assert ( + self.with_ngraph(run_test) == self.without_ngraph(run_test)).all() From 12aa7e9c791188b9b0773e1cdae1c4ad60baa6ba Mon Sep 17 00:00:00 2001 From: Sindhura Kantamani Date: Wed, 7 Aug 2019 18:42:49 -0700 Subject: [PATCH 29/31] Sindhu/bfloat16 op tests (#183) This PR implements new tests listed below to test bfloat16 conversion test_conv2d.py test_conv2dbackpropfilter_nchw.py test_conv2dbackpropfilter_nhwc.py test_conv2dbackpropinput_nchw.py test_conv2dbackpropinput_nhwc.py --- test/python/bfloat16/test_conv2d.py | 107 ++++++++++++++++ .../test_conv2dbackpropfilter_nchw.py | 116 ++++++++++++++++++ .../test_conv2dbackpropfilter_nhwc.py | 107 ++++++++++++++++ .../bfloat16/test_conv2dbackpropinput_nchw.py | 115 +++++++++++++++++ .../bfloat16/test_conv2dbackpropinput_nhwc.py | 107 ++++++++++++++++ tools/test_utils.py | 3 +- 6 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 test/python/bfloat16/test_conv2d.py create mode 100644 test/python/bfloat16/test_conv2dbackpropfilter_nchw.py create mode 100644 test/python/bfloat16/test_conv2dbackpropfilter_nhwc.py create mode 100644 test/python/bfloat16/test_conv2dbackpropinput_nchw.py create mode 100644 test/python/bfloat16/test_conv2dbackpropinput_nhwc.py diff --git a/test/python/bfloat16/test_conv2d.py b/test/python/bfloat16/test_conv2d.py new file mode 100644 index 000000000..062538ab7 --- /dev/null +++ b/test/python/bfloat16/test_conv2d.py @@ -0,0 +1,107 @@ +# ============================================================================== +# 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 Conv2d operation test + +""" +import pytest + +import tensorflow as tf +import numpy as np +import os + +import ngraph_bridge + +#Test Ngraph Op Convolution, TF Op:conv2d +# Implemented based on NNP's unit test TEST(test_assign_layout, convolution_special_case) + +np.random.seed(5) + +# Colvolution Op is placed on NNP and conerted to +# bfloat16 only for the special case below, otherwise it falls +# back to CPU for compute +# Check to assure: +# The input rank is 4-D +# The stride is less than the filter size +# The Window and Data dilation is {1,1} +# Filter shape is allowed +# If any fail, then we should place Op on CPU for compute + +#Inputs +N = 1 +C = 1 +H = 3 +W = 5 + +filter_size = np.random.rand(1, 1, 1, 2) +input_size_nhwc = [N, H, W, C] +input_size_nchw = [N, C, H, W] +input_nhwc = tf.placeholder(tf.float32, shape=input_size_nhwc, name='x') +input_nchw = tf.placeholder(tf.float32, shape=input_size_nchw, name='x') + +n_np = np.random.rand(*input_size_nchw).astype('f') +#Tensorflow supports only NHWC, change input shapes from NCHW to NHWC +t_np = np.transpose(n_np, (0, 2, 3, 1)) + + +#TF graph +def tf_model(): + stride_nhwc = [1, 2, 2, 1] + x = tf.cast(input_nhwc, dtype=tf.bfloat16) + filter_cast = tf.cast(filter_size, dtype=tf.bfloat16) + m = tf.nn.conv2d( + x, filter_cast, stride_nhwc, "SAME", data_format="NHWC", name="m") + m = tf.cast(m, dtype=tf.float32) + return m, input_nhwc + + +#Ngraph graph +def ng_model(): + stride_nchw = [1, 1, 2, 2] + m = tf.nn.conv2d( + input_nchw, + filter_size, + stride_nchw, + "SAME", + data_format="NCHW", + name="m") + return m, input_nchw + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + + +def test_conv2d(): + #Test 1: tf_model TF-native + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, input_data = tf_model() + feed_dict = {input_data: t_np} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, input_data = ng_model() + feed_dict = {input_data: n_np} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert np.allclose( + np.transpose(tf_outval, (0, 3, 1, 2)), ng_outval, rtol=0, atol=1e-02) diff --git a/test/python/bfloat16/test_conv2dbackpropfilter_nchw.py b/test/python/bfloat16/test_conv2dbackpropfilter_nchw.py new file mode 100644 index 000000000..e1283695f --- /dev/null +++ b/test/python/bfloat16/test_conv2dbackpropfilter_nchw.py @@ -0,0 +1,116 @@ +# ============================================================================== +# 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 Conv2d operation test + +""" +import pytest + +import tensorflow as tf +import numpy as np +import os +from tensorflow.python.ops import nn_ops +import ngraph_bridge + +#Tests Ngraph Op: ConvolutionBackpropFilters with data format NCHW +#TF Op: conv2d_backprop_filter + +np.random.seed(5) +#Inputs +N = 1 +H = 7 +W = 6 +C = 2 + +I = C +O = 2 +filt_width = 3 +filt_height = 3 + +input_sizes_nchw = [N, C, H, W] +input_sizes_nhwc = [N, H, W, C] +filter_size_hwio = [filt_height, filt_width, I, O] +out_backprop_valid = [1, 2, 3, 2] +out_backprop_same = [1, 2, 4, 3] +out_backprop_in_sizes = {"VALID": out_backprop_valid, "SAME": out_backprop_same} +stride_nhwc = [1, 2, 2, 1] +stride_nchw = [1, 1, 2, 2] + + +#TF graph +def tf_model(padding): + t1 = tf.placeholder(dtype=tf.float32, shape=input_sizes_nhwc, name='t1') + t2 = tf.constant(filter_size_hwio, dtype=tf.int32, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + #reshaping the out_backprop to NHWC since TF does not support NCHW + t3 = tf.transpose(t3, [0, 2, 3, 1]) + + #Cast dtype to bfloat16 for TF because NNP casts ng_model inputs + t1 = tf.cast(t1, dtype=tf.bfloat16) + t3 = tf.cast(t3, dtype=tf.bfloat16) + + filt = nn_ops.conv2d_backprop_filter( + t1, t2, t3, stride_nhwc, padding=padding, data_format='NHWC') + + #Cast dtype back to float32 similar to NNP + filt = tf.cast(filt, dtype=tf.float32) + return filt, t1, t3 + + +#Ngraph Graph +def ng_model(padding): + t1 = tf.placeholder(dtype=tf.float32, shape=input_sizes_nchw, name='t1') + t2 = tf.constant(filter_size_hwio, dtype=tf.int32, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + filt = nn_ops.conv2d_backprop_filter( + t1, t2, t3, stride_nchw, padding=padding, data_format='NCHW') + return filt, t1, t3 + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_conv2dbackpropfilter_nchw(padding): + n_np_inp = np.random.rand(*input_sizes_nchw).astype('f') + n_np_out = np.random.rand(*out_backprop_in_sizes[padding]).astype('f') + + #Reshape to NHWC for TF + t_np_inp = np.transpose(n_np_inp, (0, 2, 3, 1)) + t_np_out = np.transpose(n_np_out, (0, 2, 3, 1)) + + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, input_data, out_backprop = tf_model(padding) + feed_dict = {input_data: t_np_inp, out_backprop: t_np_out} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, input_data, out_backprop = ng_model(padding) + feed_dict = {input_data: n_np_inp, out_backprop: n_np_out} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02) diff --git a/test/python/bfloat16/test_conv2dbackpropfilter_nhwc.py b/test/python/bfloat16/test_conv2dbackpropfilter_nhwc.py new file mode 100644 index 000000000..34f639621 --- /dev/null +++ b/test/python/bfloat16/test_conv2dbackpropfilter_nhwc.py @@ -0,0 +1,107 @@ +# ============================================================================== +# 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 Conv2d operation test + +""" +import pytest + +import tensorflow as tf +import numpy as np +import os +from tensorflow.python.ops import nn_ops +import ngraph_bridge + +#Tests Ngraph Op: ConvolutionBackpropFilters with data format NHWC +#TF Op: conv2d_backprop_filter + +np.random.seed(5) +#Inputs +N = 1 +H = 7 +W = 6 +C = 2 + +I = C +O = 2 +filt_width = 3 +filt_height = 3 + +input_sizes_nhwc = [N, H, W, C] +filter_size_hwio = [filt_height, filt_width, I, O] +out_backprop_valid = [1, 3, 2, 2] +out_backprop_same = [1, 4, 3, 2] +out_backprop_in_sizes = {"VALID": out_backprop_valid, "SAME": out_backprop_same} +stride = [1, 2, 2, 1] + + +#TF graph +def tf_model(padding): + t1 = tf.placeholder(dtype=tf.float32, shape=input_sizes_nhwc, name='t1') + t2 = tf.constant(filter_size_hwio, dtype=tf.int32, name='t1') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + #Cast dtype to bfloat16 for TF because NNP casts ng_model inputs + t1 = tf.cast(t1, dtype=tf.bfloat16) + t3 = tf.cast(t3, dtype=tf.bfloat16) + + filt = nn_ops.conv2d_backprop_filter( + t1, t2, t3, stride, padding=padding, data_format='NHWC') + + #Cast dtype back to float32 similar to NNP + filt = tf.cast(filt, dtype=tf.float32) + return filt, t1, t3 + + +#Ngraph Graph +def ng_model(padding): + t1 = tf.placeholder(dtype=tf.float32, shape=input_sizes_nhwc, name='t1') + t2 = tf.constant(filter_size_hwio, dtype=tf.int32, name='t1') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + filt = nn_ops.conv2d_backprop_filter( + t1, t2, t3, stride, padding=padding, data_format='NHWC') + return filt, t1, t3 + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_conv2dbackpropfilter_nhwc(padding): + np_inp = np.random.rand(*input_sizes_nhwc).astype('f') + np_out = np.random.rand(*out_backprop_in_sizes[padding]).astype('f') + + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, input_data, out_backprop = tf_model(padding) + feed_dict = {input_data: np_inp, out_backprop: np_out} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, input_data, out_backprop = ng_model(padding) + feed_dict = {input_data: np_inp, out_backprop: np_out} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02) diff --git a/test/python/bfloat16/test_conv2dbackpropinput_nchw.py b/test/python/bfloat16/test_conv2dbackpropinput_nchw.py new file mode 100644 index 000000000..1fc73dbfa --- /dev/null +++ b/test/python/bfloat16/test_conv2dbackpropinput_nchw.py @@ -0,0 +1,115 @@ +# ============================================================================== +# 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 Conv2d operation test + +""" +import pytest + +import tensorflow as tf +import numpy as np +import os +from tensorflow.python.ops import nn_ops +import ngraph_bridge + +# Tests Ngraph Op: ConvolutionBackpropData with data format NCHW +#TF Op: conv2d_backprop_input + +np.random.seed(5) +#Inputs +N = 1 +C = 2 +H = 7 +W = 6 + +I = C +O = 2 +filt_width = 3 +filt_height = 3 + +input_sizes_nchw = [N, C, H, W] +input_sizes_nhwc = [N, H, W, C] +filter_size_hwio = [filt_height, filt_width, I, O] +out_backprop_valid = [1, 2, 3, 2] +out_backprop_same = [1, 2, 4, 3] +out_backprop_in_sizes = {"VALID": out_backprop_valid, "SAME": out_backprop_same} +stride_nhwc = [1, 2, 2, 1] +stride_nchw = [1, 1, 2, 2] + + +#TF graph +def tf_model(padding): + t1 = tf.constant(input_sizes_nhwc, dtype=tf.int32, name='t1') + t2 = tf.placeholder(dtype=tf.float32, shape=filter_size_hwio, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + #reshaping the out_backprop to NHWC since TF does not support NCHW + t3 = tf.transpose(t3, [0, 2, 3, 1]) + + #Cast dtype to bfloat16 for TF because NNP casts ng_model inputs + t2 = tf.cast(t2, dtype=tf.bfloat16) + t3 = tf.cast(t3, dtype=tf.bfloat16) + + inp = nn_ops.conv2d_backprop_input( + t1, t2, t3, stride_nhwc, padding=padding, data_format='NHWC') + + #Reshaping back to NCHW to compare outputs + inp = tf.transpose(inp, [0, 3, 1, 2]) + #Cast dtype back to float32 similar to NNP + inp = tf.cast(inp, dtype=tf.float32) + return inp, t2, t3 + + +#Ngraph Graph +def ng_model(padding): + t1 = tf.constant(input_sizes_nchw, dtype=tf.int32, name='t1') + t2 = tf.placeholder(dtype=tf.float32, shape=filter_size_hwio, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + inp = nn_ops.conv2d_backprop_input( + t1, t2, t3, stride_nchw, padding=padding, data_format='NCHW') + return inp, t2, t3 + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_conv2dbackpropinput_nchw(padding): + np_filter = np.random.rand(*filter_size_hwio).astype('f') + n_np_out = np.random.rand(*out_backprop_in_sizes[padding]).astype('f') + #Reshape to NHWC for TF + t_np_out = np.transpose(n_np_out, (0, 2, 3, 1)) + + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, filter_size, out_backprop = tf_model(padding) + feed_dict = {filter_size: np_filter, out_backprop: t_np_out} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, filter_size, out_backprop = ng_model(padding) + feed_dict = {filter_size: np_filter, out_backprop: n_np_out} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02) diff --git a/test/python/bfloat16/test_conv2dbackpropinput_nhwc.py b/test/python/bfloat16/test_conv2dbackpropinput_nhwc.py new file mode 100644 index 000000000..a427fc895 --- /dev/null +++ b/test/python/bfloat16/test_conv2dbackpropinput_nhwc.py @@ -0,0 +1,107 @@ +# ============================================================================== +# 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 Conv2d operation test + +""" +import pytest + +import tensorflow as tf +import numpy as np +import os +from tensorflow.python.ops import nn_ops +import ngraph_bridge + +#Tests Ngraph Op: ConvolutionBackpropData with data format NHWC +#TF Op: conv2d_backprop_input + +np.random.seed(5) +#Inputs +N = 1 +H = 7 +W = 6 +C = 2 + +I = C +O = 2 +filt_width = 3 +filt_height = 3 + +input_sizes_nhwc = [N, H, W, C] +filter_size_hwio = [filt_height, filt_width, I, O] +out_backprop_valid = [1, 3, 2, 2] +out_backprop_same = [1, 4, 3, 2] +out_backprop_in_sizes = {"VALID": out_backprop_valid, "SAME": out_backprop_same} +stride = [1, 2, 2, 1] + + +#TF graph +def tf_model(padding): + t1 = tf.constant(input_sizes_nhwc, dtype=tf.int32, name='t1') + t2 = tf.placeholder(dtype=tf.float32, shape=filter_size_hwio, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + #Cast dtype to bfloat16 for TF because NNP casts ng_model inputs + t2 = tf.cast(t2, dtype=tf.bfloat16) + t3 = tf.cast(t3, dtype=tf.bfloat16) + + inp = nn_ops.conv2d_backprop_input( + t1, t2, t3, stride, padding=padding, data_format='NHWC') + + #Cast dtype back to float32 similar to NNP + inp = tf.cast(inp, dtype=tf.float32) + return inp, t2, t3 + + +#Ngraph Graph +def ng_model(padding): + t1 = tf.constant(input_sizes_nhwc, dtype=tf.int32, name='t1') + t2 = tf.placeholder(dtype=tf.float32, shape=filter_size_hwio, name='t2') + t3 = tf.placeholder( + dtype=tf.float32, shape=out_backprop_in_sizes[padding], name='t3') + + inp = nn_ops.conv2d_backprop_input( + t1, t2, t3, stride, padding=padding, data_format='NHWC') + return inp, t2, t3 + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_conv2dbackpropinput_nhwc(padding): + np_filter = np.random.rand(*filter_size_hwio).astype('f') + n_np_out = np.random.rand(*out_backprop_in_sizes[padding]).astype('f') + + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, filter_size, out_backprop = tf_model(padding) + feed_dict = {filter_size: np_filter, out_backprop: n_np_out} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, filter_size, out_backprop = ng_model(padding) + feed_dict = {filter_size: np_filter, out_backprop: n_np_out} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02) diff --git a/tools/test_utils.py b/tools/test_utils.py index c8d4eacc4..b9d750ce9 100755 --- a/tools/test_utils.py +++ b/tools/test_utils.py @@ -159,7 +159,8 @@ def run_ngtf_pytests_from_artifacts(artifacts_dir): command_executor(["pip", "install", "-U", "psutil"]) command_executor([ "python", "-m", "pytest", - ('--junitxml=%s/xunit_pytest.xml' % artifacts_dir) + ('--junitxml=%s/xunit_pytest.xml' % artifacts_dir), + "--ignore=" + artifacts_dir + "/test/python/bfloat16" ]) os.chdir(root_pwd) From a68e5b41f3e4d688d5c76440947140f3a0f22c30 Mon Sep 17 00:00:00 2001 From: Shrestha Malik Date: Wed, 7 Aug 2019 19:17:15 -0700 Subject: [PATCH 30/31] Fixed version issue --- ngraph_bridge/version.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngraph_bridge/version.cc b/ngraph_bridge/version.cc index c16ea6e4f..f90bb18ea 100644 --- a/ngraph_bridge/version.cc +++ b/ngraph_bridge/version.cc @@ -32,7 +32,7 @@ // candidate such as v0.7.0-rc0 // The code in master will always have the last released version number // with a suffix of '-master' -#define NG_TF_VERSION_SUFFIX "-rc2" +#define NG_TF_VERSION_SUFFIX "-rc3" #define VERSION_STR_HELPER(x) #x #define VERSION_STR(x) VERSION_STR_HELPER(x) From 478c89e561b3a4e61713566afc7f4e06880dfb00 Mon Sep 17 00:00:00 2001 From: kanvi-nervana Date: Wed, 7 Aug 2019 19:34:54 -0700 Subject: [PATCH 31/31] Kanvi/bfloat16 tests (#185) This PR implements the following new tests to test the bfloat16 conversions test_fusedbatchnorm_training_nhwc.py test_fusedbatchnorm_training_nchw.py test_maxpoolbackprop_nhwc.py test_maxpoolbackprop_nhwc.py The following existing tests are also fixed as part of this PR test_fusedbatchnorm.py test_l2loss.py test_maxpoolbackprop.py test_relugrad.py test_sparse_softmax_cross_entropy_with_logits.py Also, made changes to the cmake so the new folder is included. --- test/CMakeLists.txt | 1 + test/python/bfloat16/CMakeLists.txt | 23 +++ .../test_fusedbatchnorm_training_nchw.py | 90 +++++++++++ .../test_fusedbatchnorm_training_nhwc.py | 81 ++++++++++ .../bfloat16/test_maxpoolbackprop_nchw.py | 151 ++++++++++++++++++ .../bfloat16/test_maxpoolbackprop_nhwc.py | 139 ++++++++++++++++ test/python/test_fusedbatchnorm.py | 80 +++++----- test/python/test_l2loss.py | 2 + test/python/test_maxpoolbackprop.py | 98 ++++++------ test/python/test_relugrad.py | 64 ++++---- ...parse_softmax_cross_entropy_with_logits.py | 21 +-- 11 files changed, 608 insertions(+), 142 deletions(-) create mode 100644 test/python/bfloat16/CMakeLists.txt create mode 100644 test/python/bfloat16/test_fusedbatchnorm_training_nchw.py create mode 100644 test/python/bfloat16/test_fusedbatchnorm_training_nhwc.py create mode 100644 test/python/bfloat16/test_maxpoolbackprop_nchw.py create mode 100644 test/python/bfloat16/test_maxpoolbackprop_nhwc.py diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1b4076df5..3d8522cfa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -109,6 +109,7 @@ if (NGRAPH_PLAIDML_ENABLE) endif() add_subdirectory(python) +add_subdirectory(python/bfloat16) add_subdirectory(model_level_tests) if (DEFINED NGRAPH_TF_INSTALL_PREFIX) diff --git a/test/python/bfloat16/CMakeLists.txt b/test/python/bfloat16/CMakeLists.txt new file mode 100644 index 000000000..519c682e7 --- /dev/null +++ b/test/python/bfloat16/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2019 Nervana Systems Inc. +# 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. + +cmake_minimum_required(VERSION 3.4) + +file(GLOB files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.py") +foreach(file ${files}) + execute_process( + COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/${file} + ${CMAKE_CURRENT_BINARY_DIR}/${file} +) +endforeach() \ No newline at end of file diff --git a/test/python/bfloat16/test_fusedbatchnorm_training_nchw.py b/test/python/bfloat16/test_fusedbatchnorm_training_nchw.py new file mode 100644 index 000000000..aee482364 --- /dev/null +++ b/test/python/bfloat16/test_fusedbatchnorm_training_nchw.py @@ -0,0 +1,90 @@ +# ============================================================================== +# 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 FusedBatchNorm test + +""" +import numpy as np +import tensorflow as tf +import os +import ngraph_bridge +import pytest + +np.random.seed(5) + +# Inputs +scale = [1.0, 0.9, 1.1] +offset = [0.1, 0.2, -.3] +input_shape_nchw = [4, 3, 1, 2] + + +def tf_model(): + x = tf.placeholder(tf.float32, shape=input_shape_nchw) + + # cast the input dtype to bfloat16 + x_c = tf.cast(x, dtype=tf.bfloat16) + + # reshape the inputs to NHWC since TF does not support NCHW + x_t = tf.transpose(x_c, (0, 2, 3, 1)) # shape=[4, 1, 2, 3] + + out_list = tf.nn.fused_batch_norm(x_t, scale, offset, data_format='NHWC') + + # cast the output back to float32 + norm = [tf.cast(i, dtype=tf.float32) for i in out_list] + return norm, x + + +def ng_model(): + x = tf.placeholder(tf.float32, shape=input_shape_nchw) + norm = tf.nn.fused_batch_norm(x, scale, offset, data_format='NCHW') + return norm, x + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + +k_np = np.random.rand(4, 3, 1, 2).astype('f') # NCHW + + +def test_fusedbatchnorm_nchw(): + #Test 1: tf_model TF-native + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, in_0 = tf_model() + feed_dict = {in_0: k_np} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, in_0 = ng_model() + feed_dict = {in_0: k_np} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + # transpose TF output from NHWC to NCHW for comparison with ngraph output + result1_bool = np.allclose( + np.transpose(tf_outval[0], (0, 3, 1, 2)), + ng_outval[0], + rtol=0, + atol=1e-02) + # these TF outputs do not need to be transposed since they have only 1 dimension + result2_bool = np.allclose(tf_outval[1], ng_outval[1], rtol=0, atol=1e-02) + result3_bool = np.allclose(tf_outval[2], ng_outval[2], rtol=0, atol=1e-02) + + assert (result1_bool and result2_bool and result3_bool) diff --git a/test/python/bfloat16/test_fusedbatchnorm_training_nhwc.py b/test/python/bfloat16/test_fusedbatchnorm_training_nhwc.py new file mode 100644 index 000000000..8227896a4 --- /dev/null +++ b/test/python/bfloat16/test_fusedbatchnorm_training_nhwc.py @@ -0,0 +1,81 @@ +# ============================================================================== +# 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 FusedBatchNorm test + +""" +import numpy as np +import tensorflow as tf +import os +import ngraph_bridge +import pytest + +np.random.seed(5) + +# Inputs +scale = [1.0, 0.9, 1.1] +offset = [0.1, 0.2, -.3] +input_shape_nhwc = [4, 1, 2, 3] + + +def tf_model(): + x = tf.placeholder(tf.float32, shape=input_shape_nhwc) + + # cast the input dtype to bfloat16 for TF + x_c = tf.cast(x, dtype=tf.bfloat16) + + out_list = tf.nn.fused_batch_norm(x, scale, offset, data_format='NHWC') + + # cast the output dtype back to float32 + norm = [tf.cast(i, dtype=tf.float32) for i in out_list] + return norm, x + + +def ng_model(): + x = tf.placeholder(tf.float32, shape=input_shape_nhwc) + norm = tf.nn.fused_batch_norm(x, scale, offset, data_format='NHWC') + return norm, x + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + +k_np = np.random.rand(4, 1, 2, 3).astype('f') # NHWC + + +def test_fusedbatchnorm_nhwc(): + #Test 1: tf_model TF-native + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, in_0 = tf_model() + feed_dict = {in_0: k_np} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, in_0 = ng_model() + feed_dict = {in_0: k_np} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + result1_bool = np.allclose(tf_outval[0], ng_outval[0], rtol=0, atol=1e-02) + result2_bool = np.allclose(tf_outval[1], ng_outval[1], rtol=0, atol=1e-02) + result3_bool = np.allclose(tf_outval[2], ng_outval[2], rtol=0, atol=1e-02) + + assert (result1_bool and result2_bool and result3_bool) diff --git a/test/python/bfloat16/test_maxpoolbackprop_nchw.py b/test/python/bfloat16/test_maxpoolbackprop_nchw.py new file mode 100644 index 000000000..d62b51f35 --- /dev/null +++ b/test/python/bfloat16/test_maxpoolbackprop_nchw.py @@ -0,0 +1,151 @@ +# ============================================================================== +# 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 MaxPoolBackprop operation test + +""" + +# Currently, this test fails with a segmentation fault +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import numpy as np +import os + +import tensorflow as tf +from tensorflow.python.ops.gen_nn_ops import max_pool_grad + +import ngraph_bridge + +# Test Ngraph Op MaxPoolBackprop with data format NCHW +# TF Op:MaxPoolGrad + +np.random.seed(5) + +#Inputs +N = 4 +C = 3 +H = 8 +W = 8 + +valid_shape = [4, 3, 3, 3] +same_shape = [4, 3, 4, 4] + +output_nchw = { + "VALID": np.random.rand(*valid_shape).astype('f'), + "SAME": np.random.rand(*same_shape).astype('f') +} +grad_nchw = { + "VALID": np.random.rand(*valid_shape).astype('f'), + "SAME": np.random.rand(*same_shape).astype('f') +} + +stride_nhwc = [1, 2, 2, 1] +ksize_nhwc = [1, 3, 3, 1] + +stride_nchw = [1, 1, 2, 2] +ksize_nchw = [1, 1, 3, 3] + + +# TF graph +def tf_model(padding): + orig_in = tf.placeholder(tf.float32, shape=[N, C, H, W]) + if padding == "VALID": + grad = tf.placeholder(tf.float32, shape=valid_shape) + orig_out = tf.placeholder(tf.float32, shape=valid_shape) + elif padding == "SAME": + grad = tf.placeholder(tf.float32, shape=same_shape) + orig_out = tf.placeholder(tf.float32, shape=same_shape) + + # cast the input dtype to bfloat16 for TF + orig_in_c = tf.cast(orig_in, tf.bfloat16) + orig_out_c = tf.cast(orig_out, tf.bfloat16) + grad_c = tf.cast(grad, tf.bfloat16) + + # transpose to NHWC + orig_in_t = tf.transpose(orig_in_c, (0, 2, 3, 1)) + orig_out_t = tf.transpose(orig_out_c, (0, 2, 3, 1)) + grad_t = tf.transpose(grad_c, (0, 2, 3, 1)) + + out = max_pool_grad( + orig_in_t, + orig_out_t, + grad_t, + ksize_nhwc, + stride_nhwc, + padding=padding, + data_format="NHWC") + + # cast the output dtype back to float32 + output = tf.cast(out, tf.float32) + + # transpose to NCHW + output_nchw = tf.transpose(output, (0, 3, 1, 2)) + return output_nchw, orig_in, orig_out, grad + + +# Ngraph graph +def ng_model(padding): + orig_in = tf.placeholder(tf.float32, shape=[N, C, H, W]) + if padding == "VALID": + grad = tf.placeholder(tf.float32, shape=valid_shape) + orig_out = tf.placeholder(tf.float32, shape=valid_shape) + elif padding == "SAME": + grad = tf.placeholder(tf.float32, shape=same_shape) + orig_out = tf.placeholder(tf.float32, shape=same_shape) + + out = max_pool_grad( + orig_in, + orig_out, + grad, + ksize_nchw, + stride_nchw, + padding=padding, + data_format="NCHW") + return out, orig_in, orig_out, grad + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + +i_np = np.random.rand(N, C, H, W).astype('f') # NHWC + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_maxpoolbackprop_nchw(padding): + g_np = grad_nchw[padding] + o_np = output_nchw[padding] + + #Test 1: tf_model TF-native + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, orig_in, orig_out, grad = tf_model(padding) + feed_dict = {orig_in: i_np, orig_out: o_np, grad: g_np} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, orig_in, orig_out, grad = ng_model(padding) + feed_dict = {orig_in: i_np, orig_out: o_np, grad: g_np} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert (np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02)) diff --git a/test/python/bfloat16/test_maxpoolbackprop_nhwc.py b/test/python/bfloat16/test_maxpoolbackprop_nhwc.py new file mode 100644 index 000000000..857ae6e06 --- /dev/null +++ b/test/python/bfloat16/test_maxpoolbackprop_nhwc.py @@ -0,0 +1,139 @@ +# ============================================================================== +# 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 MaxPoolBackprop operation test + +""" + +# Currently, this test fails with a segmentation fault +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import pytest +import numpy as np +import os + +import tensorflow as tf +from tensorflow.python.ops.gen_nn_ops import max_pool_grad + +import ngraph_bridge + +# Test Ngraph Op MaxPoolBackprop with data format NHWC +# TF Op:MaxPoolGrad + +np.random.seed(5) + +#Inputs +N = 4 +H = 8 +W = 8 +C = 3 + +valid_shape = [4, 3, 3, 3] +same_shape = [4, 4, 4, 3] + +output_nhwc = { + "VALID": np.random.rand(*valid_shape).astype('f'), + "SAME": np.random.rand(*same_shape).astype('f') +} +grad_nhwc = { + "VALID": np.random.rand(*valid_shape).astype('f'), + "SAME": np.random.rand(*same_shape).astype('f') +} +stride_nhwc = [1, 2, 2, 1] +ksize_nhwc = [1, 3, 3, 1] + + +# TF graph +def tf_model(padding): + orig_in = tf.placeholder(tf.float32, shape=[N, H, W, C]) + if padding == "VALID": + grad = tf.placeholder(tf.float32, shape=valid_shape) + orig_out = tf.placeholder(tf.float32, shape=valid_shape) + elif padding == "SAME": + grad = tf.placeholder(tf.float32, shape=same_shape) + orig_out = tf.placeholder(tf.float32, shape=same_shape) + + # cast the input dtype to bfloat16 for TF + orig_in_c = tf.cast(orig_in, tf.bfloat16) + orig_out_c = tf.cast(orig_out, tf.bfloat16) + grad_c = tf.cast(grad, tf.bfloat16) + + out = max_pool_grad( + orig_in_c, + orig_out_c, + grad_c, + ksize_nhwc, + stride_nhwc, + padding=padding, + data_format="NHWC") + + # cast the output dtype back to float32 + output = tf.cast(out, tf.float32) + return output, orig_in, orig_out, grad + + +# Ngraph graph +def ng_model(padding): + orig_in = tf.placeholder(tf.float32, shape=[N, H, W, C]) + if padding == "VALID": + grad = tf.placeholder(tf.float32, shape=valid_shape) + orig_out = tf.placeholder(tf.float32, shape=valid_shape) + elif padding == "SAME": + grad = tf.placeholder(tf.float32, shape=same_shape) + orig_out = tf.placeholder(tf.float32, shape=same_shape) + + out = max_pool_grad( + orig_in, + orig_out, + grad, + ksize_nhwc, + stride_nhwc, + padding=padding, + data_format="NHWC") + return out, orig_in, orig_out, grad + + +config = tf.ConfigProto( + allow_soft_placement=True, + log_device_placement=False, + inter_op_parallelism_threads=1) + +i_np = np.random.rand(N, H, W, C).astype('f') # NHWC + + +@pytest.mark.parametrize("padding", ("VALID", "SAME")) +def test_maxpoolbackprop_nhwc(padding): + g_np = grad_nhwc[padding] + o_np = output_nhwc[padding] + + #Test 1: tf_model TF-native + with tf.Session(config=config) as sess_tf: + ngraph_bridge.disable() + tf_out, orig_in, orig_out, grad = tf_model(padding) + feed_dict = {orig_in: i_np, orig_out: o_np, grad: g_np} + tf_outval = sess_tf.run(tf_out, feed_dict=feed_dict) + + #Test 2: model2 with ngraph, NNP backend + with tf.Session(config=config) as sess_ng: + ngraph_bridge.enable() + ngraph_bridge.update_config(config) + os.environ['NGRAPH_TF_DISABLE_DEASSIGN_CLUSTERS'] = '1' + ng_out, orig_in, orig_out, grad = ng_model(padding) + feed_dict = {orig_in: i_np, orig_out: o_np, grad: g_np} + ng_outval = sess_ng.run(ng_out, feed_dict=feed_dict) + + assert (np.allclose(tf_outval, ng_outval, rtol=0, atol=1e-02)) diff --git a/test/python/test_fusedbatchnorm.py b/test/python/test_fusedbatchnorm.py index b00cbb9a6..df1fbf534 100644 --- a/test/python/test_fusedbatchnorm.py +++ b/test/python/test_fusedbatchnorm.py @@ -29,63 +29,63 @@ # yes, it works without (tested over 1000 runs) but there's always a chance np.random.seed(5) +NHWC_TO_NCHW = (0, 3, 1, 2) +NCHW_TO_NHWC = (0, 2, 3, 1) + -@pytest.mark.skip(reason="new deviceless mode WIP") class TestFusedBatchNorm(NgraphTest): - x = np.random.rand(64, 3, 10, 8).astype('f') + x = np.random.rand(64, 3, 10, 8).astype('f') #NCHW scale = [1.0, 0.9, 1.1] offset = [0.1, 0.2, -.3] mean = [0.4, 0.5, 0.6] variance = [0.1, 0.2, 0.3] def test_fusedbatchnorm_nchw(self): - with self.device: + + def test_on_ng(sess): norm = tf.nn.fused_batch_norm( self.x, self.scale, self.offset, data_format='NCHW') + return (sess.run(norm)) - with self.session as sess: - result = sess.run(norm) - - with tf.device('/cpu:0'): - x_t = tf.transpose(self.x, (0, 2, 3, 1)) + def test_on_tf(sess): # tensorflow CPU doesn't support NCHW + x_t = tf.transpose(self.x, NCHW_TO_NHWC) # NHWC norm = tf.nn.fused_batch_norm( x_t, self.scale, self.offset, data_format='NHWC') + return (sess.run(norm)) - with self.session as sess: - expected = sess.run(norm) - + expected = self.without_ngraph(test_on_tf) + result = self.with_ngraph(test_on_ng) np.testing.assert_allclose( result[0], - np.transpose(expected[0], (0, 3, 1, 2)), + np.transpose(expected[0], NHWC_TO_NCHW), rtol=0, atol=5e-5) np.testing.assert_allclose(result[1], expected[1], rtol=0, atol=5e-5) np.testing.assert_allclose(result[2], expected[2], rtol=0, atol=5e-5) def test_fusedbatchnorm_nhwc(self): - x_t = tf.transpose(self.x, (0, 2, 3, 1)) + x_t = tf.transpose(self.x, NCHW_TO_NHWC) - with self.device: + def test_on_ng(sess): norm = tf.nn.fused_batch_norm( x_t, self.scale, self.offset, data_format='NHWC') + return (sess.run(norm)) - with self.session as sess: - result = sess.run(norm) - - with tf.device('/cpu:0'): + def test_on_tf(sess): norm = tf.nn.fused_batch_norm( x_t, self.scale, self.offset, data_format='NHWC') + return (sess.run(norm)) - with self.session as sess: - expected = sess.run(norm) - + expected = self.without_ngraph(test_on_tf) + result = self.with_ngraph(test_on_ng) np.testing.assert_allclose(result[0], expected[0], rtol=0, atol=5e-5) np.testing.assert_allclose(result[1], expected[1], rtol=0, atol=5e-5) np.testing.assert_allclose(result[2], expected[2], rtol=0, atol=5e-5) def test_fusedbatchnorm_inference_nchw(self): - with self.device: + + def test_on_ng(sess): norm = tf.nn.fused_batch_norm( self.x, self.scale, @@ -94,12 +94,10 @@ def test_fusedbatchnorm_inference_nchw(self): self.variance, data_format='NCHW', is_training=False) + return (sess.run(norm[0])) - with self.session as sess: - result = sess.run(norm[0]) - - with tf.device('/cpu:0'): - x_t = tf.transpose(self.x, (0, 2, 3, 1)) + def test_on_tf(sess): + x_t = tf.transpose(self.x, NCHW_TO_NHWC) norm = tf.nn.fused_batch_norm( x_t, self.scale, @@ -108,17 +106,17 @@ def test_fusedbatchnorm_inference_nchw(self): self.variance, data_format='NHWC', is_training=False) + return (sess.run(norm[0])) - with self.session as sess: - expected = sess.run(norm[0]) - + expected = self.without_ngraph(test_on_tf) + result = self.with_ngraph(test_on_ng) np.testing.assert_allclose( - result, np.transpose(expected, (0, 3, 1, 2)), rtol=0, atol=5e-5) + result, np.transpose(expected, NHWC_TO_NCHW), rtol=0, atol=5e-5) def test_fusedbatchnorm_inference_nhwc(self): - x_t = tf.transpose(self.x, (0, 2, 3, 1)) + x_t = tf.transpose(self.x, NCHW_TO_NHWC) - with self.device: + def test_on_ng(sess): norm = tf.nn.fused_batch_norm( x_t, self.scale, @@ -127,11 +125,9 @@ def test_fusedbatchnorm_inference_nhwc(self): self.variance, data_format='NHWC', is_training=False) + return (sess.run(norm[0])) - with self.session as sess: - result = sess.run(norm[0]) - - with tf.device('/cpu:0'): + def test_on_tf(sess): norm = tf.nn.fused_batch_norm( x_t, self.scale, @@ -140,8 +136,10 @@ def test_fusedbatchnorm_inference_nhwc(self): self.variance, data_format='NHWC', is_training=False) + return (sess.run(norm[0])) - with self.session as sess: - expected = sess.run(norm[0]) - - np.testing.assert_allclose(result, expected, rtol=0, atol=5e-5) + np.testing.assert_allclose( + self.with_ngraph(test_on_ng), + self.without_ngraph(test_on_tf), + rtol=0, + atol=5e-5) diff --git a/test/python/test_l2loss.py b/test/python/test_l2loss.py index 7b1a41d86..c03a138e4 100644 --- a/test/python/test_l2loss.py +++ b/test/python/test_l2loss.py @@ -26,6 +26,8 @@ from common import NgraphTest +np.random.seed(5) + class TestL2Loss(NgraphTest): diff --git a/test/python/test_maxpoolbackprop.py b/test/python/test_maxpoolbackprop.py index 243224677..5f2ffe535 100644 --- a/test/python/test_maxpoolbackprop.py +++ b/test/python/test_maxpoolbackprop.py @@ -31,73 +31,69 @@ NHWC_TO_NCHW = (0, 3, 1, 2) NCHW_TO_NHWC = (0, 2, 3, 1) +np.random.seed(5) + -@pytest.mark.skip(reason="new deviceless mode WIP") class TestMaxPoolBackpropInput(NgraphTest): + + # NHWC input_nhwc = np.random.rand(128, 224, 224, 3) - input_nchw = np.transpose(input_nhwc, NHWC_TO_NCHW) - output_nhwc = np.random.rand(128, 224, 224, 3) - output_nchw = np.transpose(output_nhwc, NHWC_TO_NCHW) strides_nhwc = ksize_nhwc = [1, 2, 3, 1] - strides_nchw = ksize_nchw = [1, 1, 2, 3] + output_nhwc = { + "VALID": np.random.rand(128, 112, 74, 3), + "SAME": np.random.rand(128, 112, 75, 3) + } grad_nhwc = { "VALID": np.random.rand(128, 112, 74, 3), "SAME": np.random.rand(128, 112, 75, 3) } + + # NCHW + input_nchw = np.transpose(input_nhwc, NHWC_TO_NCHW) + strides_nchw = ksize_nchw = [1, 1, 2, 3] + output_nchw = { + "VALID": np.random.rand(128, 3, 112, 74), + "SAME": np.random.rand(128, 3, 112, 75) + } grad_nchw = { - "VALID": np.transpose(grad_nhwc["VALID"], NHWC_TO_NCHW), - "SAME": np.transpose(grad_nhwc["SAME"], NHWC_TO_NCHW) + "VALID": np.random.rand(128, 3, 112, 74), + "SAME": np.random.rand(128, 3, 112, 75) } @pytest.mark.parametrize("padding", ("VALID", "SAME")) def test_nhwc(self, padding): strides = self.strides_nhwc ksize = self.ksize_nhwc - output = self.output_nhwc - np_nhwc = self.grad_nhwc[padding] + output = self.output_nhwc[padding] + g_nhwc = self.grad_nhwc[padding] if padding == "VALID": grad = tf.placeholder(tf.float32, shape=(128, 112, 74, 3)) elif padding == "SAME": grad = tf.placeholder(tf.float32, shape=(128, 112, 75, 3)) - - with self.device: - a = max_pool_grad( - self.input_nhwc, - output, - grad, - ksize, - strides, - padding=padding, - data_format="NHWC") - with self.session as sess: - result = sess.run(a, feed_dict={grad: np_nhwc}) - - with tf.device('/cpu:0'): - b = max_pool_grad( - self.input_nhwc, - output, - grad, - ksize, - strides, - padding=padding, - data_format="NHWC") - with self.session as sess: - expected = sess.run(b, feed_dict={grad: np_nhwc}) - - np.testing.assert_allclose(result, expected, rtol=5e-7) + out = max_pool_grad( + self.input_nhwc, + output, + grad, + ksize, + strides, + padding=padding, + data_format="NHWC") + sess_fn = lambda sess: sess.run(out, feed_dict={grad: g_nhwc}) + assert (np.allclose( + self.with_ngraph(sess_fn), self.without_ngraph(sess_fn), rtol=5e-7)) @pytest.mark.parametrize("padding", ("VALID", "SAME")) def test_nchw(self, padding): strides = self.strides_nchw ksize = self.ksize_nchw - output = self.output_nchw - np_nchw = self.grad_nchw[padding] + output = self.output_nchw[padding] + g_nchw = self.grad_nchw[padding] if padding == "VALID": grad = tf.placeholder(tf.float32, shape=(128, 3, 112, 74)) elif padding == "SAME": grad = tf.placeholder(tf.float32, shape=(128, 3, 112, 75)) - with self.device: + def test_on_ng(sess): a = max_pool_grad( self.input_nchw, output, @@ -106,27 +102,27 @@ def test_nchw(self, padding): strides, padding=padding, data_format="NCHW") - with self.session as sess: - result = sess.run(a, feed_dict={grad: np_nchw}) + return sess.run(a, feed_dict={grad: g_nchw}) + # To validate on the CPU side we will need to run in NHWC, because the CPU - # implementation of avgpool backprop does not support NCHW. We will + # implementation of maxpool backprop does not support NCHW. We will # transpose on the way in and on the way out - with tf.device('/cpu:0'): - grad = tf.transpose(grad, NCHW_TO_NHWC) - np_nhwc = self.grad_nhwc[padding] - output = self.output_nhwc + def test_on_tf(sess): + grad_t = tf.transpose(grad, NCHW_TO_NHWC) ksize = self.ksize_nhwc strides = self.strides_nhwc + input_t = np.transpose(self.input_nchw, NCHW_TO_NHWC) + output_t = np.transpose(output, NCHW_TO_NHWC) b = max_pool_grad( - self.input_nhwc, - output, - grad, + input_t, + output_t, + grad_t, ksize, strides, padding=padding, data_format="NHWC") b = tf.transpose(b, NHWC_TO_NCHW) - with self.session as sess: - expected = sess.run(b, feed_dict={grad: np_nhwc}) + return sess.run(b, feed_dict={grad: g_nchw}) - np.testing.assert_allclose(result, expected, rtol=5e-7) + assert np.allclose( + self.with_ngraph(test_on_ng), self.without_ngraph(test_on_tf)) diff --git a/test/python/test_relugrad.py b/test/python/test_relugrad.py index 989887f42..9ed7208fd 100644 --- a/test/python/test_relugrad.py +++ b/test/python/test_relugrad.py @@ -21,6 +21,7 @@ from __future__ import print_function import pytest +import numpy as np import tensorflow as tf from tensorflow.python.framework import constant_op @@ -28,46 +29,35 @@ from common import NgraphTest +np.random.seed(5) + -@pytest.mark.skip(reason="new deviceless mode WIP") class TestReluGradOperations(NgraphTest): def test_relugrad_2d(self): - gradients = constant_op.constant( - self.generate_random_numbers(6, 1.0, 10.0), shape=[2, 3]) - features = constant_op.constant( - self.generate_random_numbers(6, 0.0, 100.0), shape=[2, 3]) - - # Run on nGraph - with self.device: - out = relu_grad(gradients, features) - with self.session as sess: - result = sess.run(out) - - # Run on CPU - with self.cpu_device: - out = relu_grad(gradients, features) - with self.session as sess: - expected = sess.run(out) - - assert (result == expected).all() + gradients = tf.placeholder(tf.float32, [2, 3]) + features = tf.placeholder(tf.float32, [2, 3]) + out = relu_grad(gradients, features) + g = np.random.rand(2, 3) + f = np.random.rand(2, 3) + sess_fn = lambda sess: sess.run( + out, feed_dict={ + gradients: g, + features: f + }) + assert (np.allclose( + self.with_ngraph(sess_fn), self.without_ngraph(sess_fn))) def test_relugrad_1d(self): - gradients = constant_op.constant( - self.generate_random_numbers(100, 123.0, 345.0), shape=[100]) - features = constant_op.constant( - self.generate_random_numbers(100, 567.0, 789.0), shape=[100]) - - # Run on nGraph - with self.device: - out = relu_grad(gradients, features) - with self.session as sess: - result = sess.run(out) - - # Run on CPU - with self.cpu_device: - out = relu_grad(gradients, features) - with self.session as sess: - expected = sess.run(out) - - assert (result == expected).all() + gradients = tf.placeholder(tf.float32, [100]) + features = tf.placeholder(tf.float32, [100]) + out = relu_grad(gradients, features) + g = np.random.rand(100) + f = np.random.rand(100) + sess_fn = lambda sess: sess.run( + out, feed_dict={ + gradients: g, + features: f + }) + assert (np.allclose( + self.with_ngraph(sess_fn), self.without_ngraph(sess_fn))) diff --git a/test/python/test_sparse_softmax_cross_entropy_with_logits.py b/test/python/test_sparse_softmax_cross_entropy_with_logits.py index 3097e41ac..9ad5a9a6f 100644 --- a/test/python/test_sparse_softmax_cross_entropy_with_logits.py +++ b/test/python/test_sparse_softmax_cross_entropy_with_logits.py @@ -28,8 +28,9 @@ import numpy as np from common import NgraphTest +np.random.seed(5) + -@pytest.mark.skip(reason="new deviceless mode WIP") class TestSparseSoftmaxCrossEntropyWithLogitsOperations(NgraphTest): def test_sparse_softmax_cross_entropy_with_logits_2d(self): @@ -44,17 +45,11 @@ def test_sparse_softmax_cross_entropy_with_logits_2d(self): self.generate_random_numbers(total_size, 0.0, 1.0), shape=[batch_size, num_classes]) - # Run on CPU - with self.cpu_device: - out_cpu = sparse_softmax_cross_entropy_with_logits(features, labels) - with self.session as sess: - expected = sess.run(out_cpu) + out = sparse_softmax_cross_entropy_with_logits(features, labels) + sess_fn = lambda sess: sess.run(out) - # Run on nGraph - with self.device: - out = sparse_softmax_cross_entropy_with_logits(features, labels) - with self.session as sess: - result = sess.run(out) + expected = self.without_ngraph(sess_fn) + result = self.with_ngraph(sess_fn) - assert np.allclose(result[0], expected[0]) - assert np.allclose(result[1], expected[1]) + assert np.allclose(result[0], expected[0], rtol=0, atol=1e-02) + assert np.allclose(result[1], expected[1], rtol=0, atol=1e-02)